历史上的今天
今天是:2025年05月18日(星期日)
2020年05月18日 | 关于51单片机学习中计数器/定时器中断的理解
2020-05-18 来源:eefocus
对于单片机初学者来说,为了达到延时控制时间等目的,常常让单片机计算for循环函数,随着学习的深入,不可避免的,我们开始逐渐接触到了定时器/计数器中断来控制时间,这里针对定时器/计数器中断,专门作出如下讨论:
定时器/计数器是什么?
众所周知,一块单片机的基本由 中央处理器CPU、随机存储器RAM、只读存储器ROM、多种I/O口和中 断系统、定时器/计数器 构成,
定时器/计数器在单片机中的脚管位置,如图

我们可以看到,在P3系列的脚管中,P3.4,P3.5脚管上标注着T0,T1;它们分别代表着单片机内部的定时/计数器0,1,也就是英文 Timer 0,Timer 1,从图上看,一块80C51单片机上有着两个Timer,Timer既有计时的功能,又有计数的功能,通过设置与他们相关的特殊功能寄存器可以选择启用定时功能或者记数功能,关于功能的实现将在第三点讲,现在我们主要研究 Timer是什么 。
下面是Timer的结构框图:

我们可以看到,Timer是一个十六位的加一计数器,TCON(Timer control)指的是Timer的控制寄存器,TMOD(Timer Mode)则是timer的工作方式寄存器;
为什么要去实现Timer的中断
原因很简单,1.提高代码的工作效率,由于Timer是单片机中的一个独立的单元,不会去占用CPU的运行速 度,单独运行,自然提高效率
2.精确的控制时间,下面就以keil4中的for循环的delay( )函数和中断函数做对比,来控制蜂鸣器每500ms响一次,通过debug中的运行时间计算,来看看中断时如何精确的控制时间的;
for的代码
#include #define uint unsigned int #define uchar unsigned char sbit beep=P2^3; void delay(uint); int main(void) { while(1)' { beep=1; delay(500); beep=0; delay(500); } return 0; } void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } 从图中看,delay(500)函数执行用了485ms 再看Timer中断,还是调试蜂鸣器 代码如下: #define uint unsigned int #define uchar unsigned char #include sbit beep=P2^3; uchar num; int main(void) { TMOD=0x01; TH0=(65535-45872)/256; TL0=(65535-45872)%256; EA=1; ET0=1; TR0=1; while(1); return 0; } void T0_time()interrupt 1 { TH0=(65536-45872)/256; TL0=(65535-45872)%256; num++; if(num==20) { num =0; beep=~beep; } } 什么?关于它的运行时间是多少? …… 我也不会用keil4来做,本人小菜鸡哈,求教大神帮忙试一下。没关系我会算: 机器周期=12*时钟周期(我的晶振的频率是11.0592MHZ),我们想让计数器记的数N=t/机器周期, t是自己设定的,比如我们需要设定的是50ms,那么N=50 000/1.09 =45872,OK,误差在微秒级上,你说哪个精确? 怎么实现Timer中断? 我们还是要从头说起,第一点,要说一下51单片机的中断级别,废话不说,直接上图 这张图直接以由高到低的顺序解释了52单片机的中断级别(52与51类似,除了没有T2)C语言用的序号是什么意? 很简单,看上面的蜂鸣器中断的代码:下面是不是有一个interrupt 1 ? 这个1就代表该序号级别的中断,与图中对应,可以看出,那个函数表示的是Timer0的中断。 还是那张图,先来说说TCON(Timer Control),TCON可以被寻址,也就是说没必要用一个类似于0xff之类的十六进制的数字来控制每个位,再说每个位的内容 TF1(Timer1 Filled):也就是Timer1 数据溢出了,此时它会向CPU提出中断请求,是单片机自动的,没必要控制1! TR1(Timer1 Run): 字面意思,就像那句Run Forrest ! 需要你去声明,例如TR1=1,就是 RUN! TIMER1! 那个Timer就工作了。。 TF0,TR0,那个同上,只不过是角标不一样而已; 在说说TMOD(Timer Mode),Timer Mode没法被寻址,所以必须用一个十六进制数如0xff来控制每一位,进而完成功能实现 1,GATE(基本上没特殊要求的话,GATE这个位直接取0) GATE=0:Timer启动与停止仅仅受TCON寄存器中的TRX(Timer Run 0或者1 , X是角标),控制 ; GATE=1:由TRX和外部中断引脚 INT0或INT1上的电平控制 2 , C/T(cacluate or time ),定时器模式和计数器模式的选择位,作为Timer中断来说,这位通常取0; C/T=1:计数器模式 C/T=0:定时器模式 3, M1M2,工作方式选择位,由这两个位共同决定Timer的工作方式,基本上我们都是用 0 1,废话不说,直接上图 开始分析刚刚上的那个蜂鸣器的中断代码: int main(void) { TMOD=0x01; //0000_0001,相当于只打开了Timer0,并且把它的工作状态设为16位的Timer TH0=(65535-45872)/256;//45872上次的运算结果,就是那个控制50ms的那个数据,除法,将数据 TL0=(65535-45872)%256;//储存进高八位,取余将数据储存进第八位 EA=1;//打开总中断,首要步骤 ET0=1;//打开定时器0中断 TR0=1;//启动定时器0 while(1); return 0; } void T0_time()interrupt 1 { TH0=(65536-45872)/256; TL0=(65535-45872)%256; num++;//不断地累加,到num=20时,重置,20×50ms = 1s if(num==20) { num =0; beep=~beep; } } 总的来说,就是 1,设定TMOD → 2,装入初值(THx,TLx, 45872)→3.打开总中断 EA=1 →4.开启定时器中断→5.启动定时器(TRx)→设定中断函数 (void Tx_time( ) interrupt y, x表示定时器编号,y表示中断序列) 


上一篇:51单片机的中断和定时器、计数器
下一篇:51单片机-定时器1中断
史海拾趣
|
我在原来的公司做的时候,就注意观察公司在管理上的成功和失败的经验教训,并在网络上找很多关于管理的文章。 管理上有很多故事,让我领悟到管理就是设计一个合理的机制。 故事之一:分粥 分粥的故 ...… 查看全部问答> |
|
拿到STM32开发板三天了!写了几个程序!程序简单但对入门还是有点帮助的!我自己下次调试成功了的! 上传供一起刚入门的朋友分享下! 第一天学习:MDK工程建立和GPIO 第二天学习:RCC和按键程序 第三天学习:EXTI程序(一个中断按键程序) 每 ...… 查看全部问答> |
|
程序代码如下: 初始化后寄存器如下:起始地址是0x40005800 00000001 00000024 00004000 00000000 00000000 00000000 00000000 00000708 00000035 我不喜欢用提供的函数, ...… 查看全部问答> |
|
电风扇模拟控制系统设计1.用4个LED显示电风扇的工作状态(1,2,3,4四档风力),显示风类:“自然风”、 “常风”和“睡眠风”。2.设计 “自然风”、 “常风”和“睡眠风” 三个风类键用于设置风类; 设计一个“摇头” 键用于控制电机摇头。 &nb ...… 查看全部问答> |
|
新手提问--想学ARM但是不知道先学ARM7或ARM9好还是先学STM32好--有51和avr经验 想学ARM但是不知道先学ARM7或ARM9好还是先学STM32好。我现在一直在用的是51和AVR。… 查看全部问答> |
|
完成ARM对接口的调用和初始化,和DSP之间数据的传输和处理。 修改buildutils/platform.xs文件来确定codec对应的平台信息。 Var allDevices=new Array(); allDevices[‘OMAP3530’]={platforms: ti.platforms.evm3530 请问我选用的OMAP3530是对 ...… 查看全部问答> |




