在学习定时/计数器之前,我们先了解一下在单片机中什么是定时/计数器。
在51单片机中有两个定时/计数器t0和t1,在其增强型的52单片机中有三个定时/计数器t0、t1和t2。
定时/计数器系统是单片机内部的一个独立的硬件系统,其与cpu和晶振通过内部连接相互作用。当cpu开启其功能后,定时计数器便在晶振的作用下开始独立工作。
定时/计数器本质上是一个16位加1计数器,由高8位(th0或th1)和低8位(tl0或tl1)两个寄存器组成。但是由于累加是在晶振的驱动下,所以可以当做计时器。通过设置相应的寄存器可以选择启用其定时功能或者计数功能。当计数器溢出则溢出标志位置1。
在此介绍其两个特殊功能寄存器:tmod-定时计数器工作模式寄存器和tcon-定时/计数器控制寄存器。
tmod-定时/计数器工作模式寄存器 (不可位寻址)
tmod用来确定定时/计数器的工作方式及功能选择。
gate-门控制位
(若gate为0,则定时/计数器启动和暂停只与相应tcon寄存器中的运行控制位有关;若gate为1,则定时计数器启动和暂停由相应tcon寄存器中的运行控制位和外部中断引脚上的电平状态共同控制)
c/t'-定时器模式和计数器模式选择位
(为0定时器模式,为1计数器模式)
m1、m2-工作方式选择位
工作方式1:thx和tlx两个8位寄存器组合构成一个16位定时/计数器。thx存放高8位,tlx存放低8位。
工作方式2:thx存放初值,待tlx累加溢出时,thx内的初值自动重装入tlx开始累加,循环往复。
介绍了应用较多两种工作方式。
定时器的计算
定时/计数器本质上是一个16位加1计数器,在晶振的驱动下,每过一个机器周期(12个时钟周期)就自行加1。因此加1则意味着时间过了12/fs,其中f为晶振频率。假如我们应用定时器模式工作方式1。此模式下定时最长时间为((2^16-1)x12/f)s。本开发板上晶振为11.0592mhz,则最长定时时间约为71ms。所以当定时时间大于71ms时,我们可以迭代使其达到。
假如我们要定时100ms,我们可以定时50ms,再迭代2次。定时50ms要重装初值,假如用t0。定时50ms约需要累加(0.05s/(12/f))=46083次。故需要将(65535-46083)=19452(0x4bfc)装入th0和tl0中。
tcon-定时/计数器控制寄存器 (可位寻址)
tf1-定时计数器1溢出标志位
(为1溢出申请中断。中断方式硬件自动清0,查询方式需软件清0)
tr1-定时计数器1运行控制位
(若gate==1且int1为高电平,tr1为1运行;若gate==0,tr1为1运行;tr1需软件清0关闭)
tf0-定时计数器0溢出标志位
(为1溢出申请中断。中断方式硬件自动清0,查询方式需软件清0)
tr0-定时计数器0运行控制位
(若gate==1且int0为高电平,tr0为1运行;若gate==0,tr0为1运行;tr0需软件清0关闭)
ie1-外部中断1请求标志
(为1表明正在向cpu申请中断,cpu转向中断服务程序后,硬件清0)
it1-外部中断1触发方式选择位
(为1为跳变沿触发方式(负跳变),为0为低电平触发方式)
ie0-外部中断0请求标志
(为1表明正在向cpu申请中断,cpu转向中断服务程序后,硬件清0)
it0-外部中断0触发方式选择位
(为1为跳变沿触发方式(负跳变),为0为低电平触发方式)
定时计数器应用
题目:定时/计数器1做计数器1,工作模式2,使用定时/计数器0做定时器0让led小灯100毫秒闪烁一次,计数器1记录led闪烁次数,并且用数码管实时显示计数数值。硬件需要将p1^0与p3^5连接起来,使计数器得到触发。
查询方式
查询方式就是利用计数器计数溢出会使相应的溢出标志位置1来进行是否计数完成或计时完成。
1/*定时/计数器1做计数器1,工作模式2,使用定时器0让led小灯100毫秒闪烁一次, 2计数器1记录led闪烁次数,并且用数码管实时显示计数数值。*/ 3#include 4#define uchar unsigned char 5#define uint unsigned int 6 7sbit we = p2^7; 8sbit du = p2^6; 9sbit led = p1^0; 10 11uchar code leddata[]={ 12 13 0x3f, //0 14 0x06, //1 15 0x5b, //2 16 0x4f, //3 17 0x66, //4 18 0x6d, //5 19 0x7d, //6 20 0x07, //7 21 0x7f, //8 22 0x6f, //9 23 0x77, //a 24 0x7c, //b 25 0x39, //c 26 0x5e, //d 27 0x79, //e 28 0x71, //f 29 0x76, //h 30 0x38, //l 31 0x37, //n 32 0x3e, //u 33 0x73, //p 34 0x5c, //o 35 0x40, //- 36 0x00, //熄灭 37 0x00 //自定义 38 39 }; 40 41void delay(uint t_ms) //ms级延时 42{ 43 uchar i; 44 while(t_ms--) 45 for(i = 114; i > 0 ; i--); 46} 47 48void display(uchar i) //数码管显示函数 49{ 50 uchar bai, shi, ge; 51 bai = i / 100; //显示百位 52 shi = i % 100 / 10; //显示十位 53 ge = i % 10; //显示个位 54 55 p0 = 0xff; //清除断码 56 we = 1; //打开位选 57 p0 = 0xfe; //1111 1110 58 we = 0; //关闭位选 59 60 du = 1; //打开段选 61 p0 = leddata[bai]; 62 du = 0; //关闭段选 63 delay(5); //延时5毫秒 64 65 p0 = 0xff; //清除断码 66 we = 1; //打开位选 67 p0 = 0xfd; //1111 1101 68 we = 0; //关闭位选 69 70 du = 1; //打开段选 71 p0 = leddata[shi]; 72 du = 0; //关闭段选 73 delay(5); //延时5毫秒 74 75 p0 = 0xff; //清除断码 76 we = 1; //打开位选 77 p0 = 0xfb; //1111 1011 78 we = 0; //关闭位选 79 80 du = 1; //打开段选 81 p0 = leddata[ge]; 82 du = 0; //关闭段选 83 delay(5); //延时5毫秒 84} 85 86void main() 87{ 88 uchar a; //50次数计数 89 tmod = 0x61;//t0为定时器,工作模式1 16位计数器,t1为计数器,工作模式2,8位自动重装 90 th0 = 0x4b; 91 tl0 = 0xfc; //0x4bfc 定时50ms 92 th1 = 20; //8位自动重装 93 tl1 = 0; //当tl1溢出时自动装入th1的值 94 tr0 = 1; //启动t0 95 tr1 = 1; //启动t1 96 while(1) 97 { 98 if(tf0 == 1) //判断t0是否溢出 99 {100 th0 = 0x4b;101 tl0 = 0xfc;//0x4bfc 定时50ms102 tf0 = 0; //清零便于下次判断103 a++; //50毫秒计数加1 104 }105 if(a == 2) //判断是否到100毫秒106 {107 a = 0; //清零便于下次记录50ms的次数108 led = ~led; //闪烁led1109 } 110 display(tl1);//显示t1计数值111 }112}中断方式
中断方式就是利用计数器计数溢出会使相应的溢出标志位置1,申请中断。
1/*定时/计数器1做计数器1,工作模式2,使用定时器0让led小灯100毫秒闪烁一次, 2计数器1记录led闪烁次数,并且用数码管实时显示计数数值。*/ 3#include 4#define uchar unsigned char 5#define uint unsigned int 6 7sbit du = p2^6; 8sbit we = p2^7; 9sbit led = p1^0; 10 11uchar code leddata[]={ 12 13 0x3f, //0 14 0x06, //1 15 0x5b, //2 16 0x4f, //3 17 0x66, //4 18 0x6d, //5 19 0x7d, //6 20 0x07, //7 21 0x7f, //8 22 0x6f, //9 23 0x77, //a 24 0x7c, //b 25 0x39, //c 26 0x5e, //d 27 0x79, //e 28 0x71, //f 29 0x76, //h 30 0x38, //l 31 0x37, //n 32 0x3e, //u 33 0x73, //p 34 0x5c, //o 35 0x40, //- 36 0x00, //熄灭 37 0x00 //自定义 38 39 }; 40 41void delay(uint t_ms) //ms级延时 42{ 43 uchar i; 44 while(t_ms--) 45 for(i = 114; i > 0 ; i--); 46} 47 48void display(uchar i) //数码管显示函数 49{ 50 uchar bai, shi, ge; 51 bai = i / 100; //显示百位 52 shi = i % 100 / 10; //显示十位 53 ge = i % 10; //显示个位 54 55 p0 = 0xff; //清除断码 56 we = 1; //打开位选 57 p0 = 0xfe; //1111 1110百位显示 58 we = 0; //关闭位选 59 60 du = 1; //打开段选 61 p0 = leddata[bai]; 62 du = 0; //关闭段选 63 delay(5); //延时5毫秒 64 65 p0 = 0xff; //清除断码 66 we = 1; //打开位选 67 p0 = 0xfd; //1111 1101十位显示 68 we = 0; //关闭位选 69 70 du = 1; //打开段选 71 p0 = leddata[shi]; 72 du = 0; //关闭段选 73 delay(5); //延时5毫秒 74 75 p0 = 0xff; //清除断码 76 we = 1; //打开位选 77 p0 = 0xfb; //1111 1011个位显示 78 we = 0; //关闭位选 79 80 du = 1; //打开段选 81 p0 = leddata[ge]; 82 du = 0; //关闭段选 83 delay(5); //延时5毫秒 84} 85 86void main() 87{ 88 tmod = 0x61; //t0为定时器,工作模式1 16位计数器,t1为计数器,工作模式2,8位自动重装 89 th0 = 0x4b; 90 tl0 = 0xfc; //0x4bfc 定时50ms 91 th1 = 10; //8位自动重装 92 tl1 = 0; //当tl1溢出时自动装入th1的值 93 ea = 1; //打开总中断允许位 94 et0 = 1; //打开定时/计数器0中断允许位 95 tr0 = 1; //启动t0 96 tr1 = 1; //启动t1 97 while(1) 98 display(tl1); //显示当前计数值 99}100101void timer() interrupt 1102{103 uchar a; //用来记迭代次数104 th0 = 0x4b;105 tl0 = 0xfc;//0x4bfc 定时50ms106 tf0 = 0; //清零便于下次判断107 a++; //50毫秒计数加1 108 if(a==2) //判断是否到100ms109 {110 led=~led;//led灯闪烁111 a=0; //清零重记112 }113}代码亲测有效,请注意硬件电路与代码的对应关系。
iPhone增强版头显:自带位置追踪
德国研究人员正在开发出一种可帮助识别肉类和鱼类是否变质的传感器
智能锁品牌诺托浅析智能指纹锁的未来发展需求趋势
提高电动车电池性能的管理系统
研究人员首次发现两种产生超导现象方法之间的联系
51单片机中定时器/计数器讲解
选择智能指纹锁锁芯的注意事项
基于用于大动态范围气体传感的激光矢量光谱技术
解密“芯”加速 酷睿 i 600系列最新指令集应用指南
小米6plus什么时候上市?小米6plus最新消息:携手小米MIUI9和红米Pro2,本月即将发布?
零售是 AI 应用的巨大舞台
磷化氢残留检测仪的关键技术与应用
小米头戴式耳机轻松版评测 199元很值
MAX6010 微功耗、3V电压基准,为便携式系统提供高PS
微软以创新技术构建低碳绿色美好未来
DPO7054数字示波器介绍
分析三网融合推动ICT产业发展方案
精密温度补偿流量计的设计思想与工作原理
无线网络使用中的问题和解决办法
实现更高的性能和更强的隔离