19课:单片机定时器、中断试验

19课:单片机定时器|♂〓♂※、中断试验

  网络消费维权成本居高不下  上述报告从2016年11月至12月抽样选取的360手机卫士用户主动标记骚扰电话标记量来看※,广东(16.9%)〓※※※|、北京(8.0%)♂|、河南(6.0%)※※、山东(5.9%)和江苏(5.7%)这5个省级行政区的用户标记量最多※〓。

19课:单片机定时器♂|卍、中断试验

我们在学单片机时我们第一个例程就是灯的闪烁〓卍||,那是用延时程序做的卍|,现在回想起来〓|,这样做不很恰当|〓※,为什么呢※〓?我们的主程序做了灯的闪烁卍♂卍|,就不能再干其它的事了〓卍,难道单片机只能这样工作吗〓♂?当然不是♂♂卍卍,我们能用定时器来实现灯的闪烁的功能♂※〓※♂。

例1:查询方式ORG0000HAJMPSTARTORG30HSTART:MOVP1,#0FFH;关所灯MOVTMOD,#00000001B;定时/计数器0工作于方式1MOVTH0,#15HMOVTL0,#0A0H;即数5536SETBTR0;定时/计数器0开始运行LOOP:JBCTF0,NEXT;如果TF0等于1卍※♂|,则清TF0并转NEXT处AJMPLOOP;不然跳转到LOOP处运行NEXT:,#15HMOVTL0,#9FH;重置定时/计数器的初值AJMPLOOPENDAJMPLOOPEND键入程序卍|,看到了什么〓※?灯在闪烁了♂,这可是用定时器做的♂卍,不再是主程序的循环了卍。简单地分析一下程序卍|,为什么用JBC呢|卍|♂〓?TF0是定时/计数器0的溢出标记位〓卍※,当定时器产生溢出后〓卍♂♂※,该位由0变1〓卍卍♂〓,所以查询该位就可知宇时时间是否已到※卍♂|。该位为1后※〓|,要用软件将标记位清0卍卍,以便下一次定时是间到时该位由0变1※♂,所以用了JBC指令♂♂|,该指位在判1转移的同时|※卍♂♂,还将该位清0〓♂※♂|。以上程序是能实现灯的闪烁了〓♂※〓,可是主程序除了让灯闪烁外♂※卍|,还是不能做其他的事啊♂|!不卍♂♂,不对||※,我们能在LOOP:……和AJMPLOOP指令之间插入一些指令来做其他的事情|,只要保证执行这些指令的时间少于定时时间就行了卍〓卍。那我们在用软件延时程序的时候不是也能用一些指令来替代DJNZ吗※〓※※卍?是的|♂,但是那就要求你精确计算所用指令的时间卍卍,然后再减去对应的DJNZ循环次数卍,很不方便〓※〓卍〓,而现在只要求所用指令的时间少于定时时间就行♂〓♂||,显然要求低了※|卍卍卍。当然|〓,这样的办法还是不好卍卍,所以我们常用以下的办法来实现|♂|〓|。

程序2:用中断实现ORG0000H,http://;定时器0的中断向量地址AJMPTIME0;跳转到真正的定时器程序处ORG30HSTART:MOVP1,#0FFH;关所灯MOVTMOD,#00000001B;定时/计数器0工作于方式1MOVTH0,#15HMOVTL0,#0A0H;即数5536SETBEA;开总中断允许SETBET0;开定时/计数器0允许SETBTR0;定时/计数器0开始运行LOOP:AJMPLOOP;真正工作时,这里可写任意程序TIME0:;定时器0的中断处理程序PUSHACCPUSHPSW;将PSW和ACC推入堆栈保护,#15HMOVTL0,#0A0H;重置定时常数POPPSWPOPACCRETIEND上面的例程中卍卍♂♂〓,定时时间一到|卍||♂,TF0由0变1|※,就会引发中断|※〓||,CPU将自动转至000B处寻找程序并执行||♂卍,由于留给定时器中断的空间只有8个字节※〓〓卍,显然不足以写下所有有中断处理程序♂|※※,所以在000B处安排一条跳转指令卍,转到实际处理中断的程序处♂※卍卍|,这样♂〓|,中断程序能写在任意地方※〓卍♂♂,也能写任意长度了※卍|。进入定时中断后〓卍,首先要保存当前的一些状态|♂,程序中只演示了保存存ACC和PSW〓,实际工作中应该根据需要将可能会改变的单元的值都推入堆栈进行保护(本程序中实际不需保存护任何值♂|♂,这里只作个演示)※※卍♂。上面的两个单片机程序运行后♂※〓卍〓,我们发现灯的闪烁非常快|〓,根本分辨不出来|,只是视觉上感到灯有些晃动而已〓|卍♂〓,为什么呢〓♂♂?我们能计算一下♂||,定时器中预置的数是5536卍♂♂※♂,所以每计60000个脉冲就是定时时间到※♂,这60000个脉冲的时间是多少呢|〓♂卍?我们的晶体震荡器是12M||♂,所以就是60000微秒||,即60毫秒※※〓〓,因此速度是非常快的♂。如果我想实现一个1S的定时♂|,该怎么办呢卍|?在该晶体震荡器濒率下※♂,最长的定时也就是65♂|♂|※。536个毫秒啊♂※卍〓!上面给出一个例程|〓♂|♂。ORG0000HAJMPSTARTORG000BH;定时器0的中断向量地址AJMPTIME0;跳转到真正的定时器程序处ORG30HSTART:MOVP1,#0FFH;关所灯MOV30H,#00H;软件计数器预清0MOVTMOD,#00000001B;定时/计数器0工作于方式1MOVTH0,#3CHMOVTL0,#0B0H;即数15536SETBEA;开总中断允许SETBET0;开定时/计数器0允许SETBTR0;定时/计数器0开始运行LOOP:AJMPLOOP;真正工作时,这里可写任意程序TIME0:;定时器0的中断处理程序PUSHACCPUSHPSW;将PSW和ACC推入堆栈保护INC30HMOVA,30HCJNEA,#20,T_RET;30H单元中的值到了20了吗T_L1:;到了,取反P10MOV30H,#0;清软件计数器T_RET:MOVTH0,#15HMOVTL0,#9FH;重置定时常数POPPSWPOPACCRETIEND先自己分析一下♂〓|,看看是怎么实现的※〓♂♂※?这里采用了软件计数器的概念※卍※※♂,思路是这样的卍※〓,先用定时/计数器0做一个50毫秒的定时器♂|〓卍,定时是间到了以后并不是立即取反P10♂,而是将软件计数器中的值加1〓,如果软件计数器计到了20♂|卍♂,就取反P10♂|,并清掉软件计数器中的值|,不然直接返回|〓〓卍〓,这样〓卍|※,就变成了20次定时中断才取反一次P10♂|♂※卍,因此定时时间就延长了成了20*50即1000毫秒了※卍※♂。这个思路在工程中是非常有用的※〓♂※,有的时候我们需要若干个定时器♂〓,可51中总共才有2个|,怎么办呢〓卍※〓?其实※♂※♂,只要这几个定时的时间有一定的公约数|※,我们就能用软件定时器加以实现〓※卍卍,如我要实现P10口所接灯按1S每次♂,而P11口所接灯按2S每次闪烁〓〓卍|※,怎么实现呢|〓卍♂|?对了我们用两个计数器卍,一个在它计到20时※〓〓|※,取反P10|〓||,并清零♂♂,就如上面所示♂|※,另一个计到40取反P11|,然后清0※|♂♂♂,不就行了吗〓|?这部份的程序如下ORG0000HAJMPSTARTORG000BH;定时器0的中断向量地址AJMPTIME0;跳转到真正的定时器程序处ORG30HSTART:MOVP1,#0FFH;关所灯MOV30H,#00H;软件计数器预清0MOVTMOD,#00000001B;定时/计数器0工作于方式1MOVTH0,#3CHMOVTL0,#0B0H;即数15536SETBEA;开总中断允许SETBET0;开定时/计数器0允许SETBTR0;定时/计数器0开始运行LOOP:AJMPLOOP;真正工作时,这里可写任意程序TIME0:;定时器0的中断处理程序PUSHACCPUSHPSW;将PSW和ACC推入堆栈保护INC30HINC31H;两个计数器都加1MOVA,30HCJNEA,#20,T_NEXT;30H单元中的值到了20了吗T_L1:;到了,取反P10MOV30H,#0;清软件计数器T_NEXT:MOVA,31HCJNEA,#40,T_RET;31h单元中的值到40了吗T_L2:,#0;到了,取反P11,清计数器,返回T_RET:MOVTH0,#15HMOVTL0,#9FH;重置定时常数POPPSWPOPACCRETIEND您能用定时器的办法实现前面讲的流水灯吗|※※♂?试试看卍卍。