历史上的今天
今天是:2025年02月06日(星期四)
2020年02月06日 | PIC单片机中断程序的设计技巧总结
2020-02-06 来源:eefocus
所有的中档系列PIC单片机,PORTB端口最高的4个引脚(RB7~RB4)在设为输入模式时,当输入电平由高到低或由低到高发生变化时,可以让单片机产生中断。这就是通常所说的引脚状态变化中断。
在设计引脚中断程序时,有三个需要特别注意的地方。一是,在清除P0RTB中断标志位RBIF之前,必须安排一条必不可少的,以PORTB端口数据寄存器PORTB为源寄存器的读操作指令。放置这一指令的目的有时并不只是为了读取有用的数据,而是为了取消状态变化的硬件信号,以便顺利清除RBIF标志位,为下一次中断做好准备。二是,由于端口PORTB是引脚电子变化中断,即无论引脚出现上升沿还是下降沿都会产生中断请求,所以必须处理好不需要的虚假中断。三是,一般都利用PIC单片机的引脚功能来检测按键,所以必须处理好按键消抖的问題。
在主程序里先设置有关的寄存器。
◇设置TRISB寄存器,使RB7~RB4相关的引脚处于输入状态;
◇如果需要弱上拉,通过OPTION_REG的第7位设置;
◇RBIF=O;
◇RBIE=1;
◇GIF=1。
响应状态变化后的中断服务程序。
◇检查RBIF是否为l,为l则是引脚变化引起的中断;
◇调用延时程序,延时20~30 ms,目的是为了按键去抖;
◇判断是引脚出现上升沿还是下降沿引起的中断;
◇调用按键处理程序;
◇读PORTB口的值,取消状态变化的硬件信号;
◇清除RBIF标志。
笔者认为上面程序设计最大的问题是在中断程序里调用延时程序。大家知道,中档PIC单片机只有8层深度的硬件堆栈,在中断里调用于程序出现极易堆栈溢出的情况。另外,PIC单片机中断程序人口只有一个,在响应中断的请求时,PIC单片机就会自动把全局中断的使能位(INTCON的第7位GIF)清除,这样其他中断就暂时不能被响应(此时,如果别的中断发出的中断请求,标志位将一直保留着),直到这个中断程序退出后才会得到响应。这就要求我们设计中断程序的时候必须尽量短,避免调用子程序,更不要在中断里进行复杂的运算。
下面给出笔者设计程序时的思路。
当引脚状态变化引起中断时,在中断子程序里首先判断引起中断的原因是不是我们需要的变化引起的中断。如果是,不要在这里延时,而是设置一个标志位,接着清除中断标志,退出中断。中断程序如下:
else if((RBIE&RBlF)==1){ //如果引脚变化引起中断
if(RB4==0){ //RB4上的按钮接地
key=1; //按键标志位置位
}
RBIF=0; //清除引脚中断标志位
}
其中,if(RB4==0)语句相当于读取了PORTB端口数据寄存器,取消了状态变化的硬件信号。
下面详细介绍怎么样进行按键去抖。
首先,在定时器中断里设置一个lms的时间基准标志位“SYSlms”,每到lms,“SYSlms”便置位。程序如下:
unsigned char count;
if((ToIE&TOIF)==1){ //定时器中断
TMRO+=0x09; //每250μs中断一次
if(count==4){
count=0;
SYSlms=l; //系统时间标志
couot++;
}
T0IF=0; //清除时钟中断标志位
}
有了这个时间基准,便可以在主程序里进行按键去抖处理了。为了更好地利用这个时间基准,定义一个消息标志SYSTime,笔者把它称作时间消息。为了让这个消息有自我发布和自我消失的功能.定义了如下一个宏:
bit SYSTime;
#defincTimeEnahle()SYSTime=0,if(SYSlms){SYSTime=l;SYSlms=0;)
可以把TimeEnable()放到主程序死循环的任何地方,每当程序执行这个宏,SYSTime就会清零,这就是标志位的自我消失.如果在定时器时间基准标志位SYSlms已经置位的话,SYSTime就会置1,这样别的程序就可以利用这个时间消息了,这就是消息的自我发布。下面就是利用这个时间消息来进行按键延时去抖的,首先看一下按键扫描子程序;
void seaakey(){
unsigned char KeyTime,KeyTask;//定义任务时间参数、
//任务参数
switch(KeyTask){
case0:if(key){
KeyTime=30; //准备延时30 ms
KeyTask++; //准备好下一个任务
kcy=0;
}
break;
case I:KeyTime--; //延时30 ms
if(KeyTime==0)Key+ask++;
break;
case2;if(RB4==o){
//调按键处理程序
KeyTask=0;
}
else KeyTask=0;//退出任务
break;
}
}
在主程序的死循环中这样用:
while(1){
TimeEnable();
If(SYSTime==1){scankey();)
//在此可以添加其他程序
只有有时问消息的时候才执行按键扫描程序。可以看到,进入扫描程序执行第一次的时候,程序首先判断按键标志位有没有置位,置位的话(也就是有按键按下的话),任务时间参数(KeyTime)赋值为30,这是延时30ms,去抖,当然你也可以设置为其他的时间值;同时任务参数 (KeyTask)加1。1ms后,再进入扫描程序,这个时候扫描程序执行casel的语句,这样30次后(延时了30ms),任务参数(KeyTask)加1,值为2。lms后,再进入扫描程序,将执行case 2的语句,首先在这里再次判断是不是按键还在按下,如果是就调按键的处理程序,如果不是。就退出按键扫描程序。在这里,还可以加入按键是否抬起的判断程序。
这样设计的引脚变化程序,CPU开销小,效率高,不会出现堆浅溢出的问题,提高了系统的实时性。
上一篇:PIC单片机双机异步通信程序详解
下一篇:PIC单片机的内部A/D转换
史海拾趣
|
整理了一天,打印时记得用双面A4,因为是按照双面排版的! 下载了记得顶一下,本人刚注册的号,积分不多,帮忙挣点积分了好下载资料,在此谢过了!!… 查看全部问答> |
|
本帖最后由 jameswangsynnex 于 2015-3-3 19:57 编辑 对于有钱有势的谷歌和微软来说,今年的6月过得不大舒坦。 6月底,谷歌和微软不约而同地宣布不再推出新的自有品牌手机。其实,谷歌试水手机市场只有5个多月,而微软则只有两个多月。这对已经习 ...… 查看全部问答> |
|
请教各位大虾: 在WinCE6.0 的用户态驱动中如何映射物理地址? 对于下面的这样一段代码, 如果这个驱动是被运行在用户态, 输出的vpReg为0. 哪位知道该如何映射物理地址, 请不吝赐教. DWORD HDR_Init(LPCTSTR pContext, LPCVOID lpvBus ...… 查看全部问答> |
|
求助!!!CC2430芯片烧不进程序,请问电路设计哪出了问题!!! 向CC2430芯片烧程序的时候,程序烧不进去,经测试发现CC2430烧程序的数据线(DD引脚,46脚)为3.3V高电平,CC2430的电源3.3V。而正常情况下这个引脚的电压应该几乎等于0V,为低电平。烧写器没有问题,接线没有错。 现在已经确定是CC2430芯片和周围 ...… 查看全部问答> |
|
S3C2410/2440如何接市面上买来的液晶屏?我研究了好多天,还是一头雾水,请高手帮帮我 现在市面上买来的液晶屏一般有以下信号 HSYNC //2410有相应引脚 VSYNC //2410有相应引脚 DOTCLK //2410有相应引脚 DEN //2410有相应引脚 AVDD //模 ...… 查看全部问答> |
|
买了一个掌上电脑HP iPAQ 212,他的cpu类型是Marvell PXA310,请问这是个啥cpu,基于什么架构平台的,原来ARM的程序不用改动可以移植到这上面吗?x86下的程序呢… 查看全部问答> |
|
pxa270wince下大页面nandflash驱动的问题? 我最近在做pxa270wince下大页面nandflash的驱动,更改了read,write函数后,在控制面板里可以看到这个设备,容量显示也是正确的,可是一格式化,就在FMD_SetBlockStatus中把每一个block立刻mark成bad,不知道该如何解决,有做过这个的大大给我讲一下 ...… 查看全部问答> |
|
USART的配置如下USART_InitStructure.USART_BaudRate = 4800; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1;& ...… 查看全部问答> |




