目录
前言
单片机的使用很注重时序,特别是我之前博客发过的,使用软件延时达到两个功能同时进行的效果,这种方法时间很难调整的精确,感兴趣的可以看看,所以就要用定时器来更精准的控制时序
定时器
计时的本质是计数
晶振产生时钟,这个时钟的脉冲——加1计数器——到达一定数值后溢出——溢出标志(TF0).
假设触发一次溢出标志要20,那么计100就触发五次标志就行了,但是怎么计5呢?
也就是该如何完成自己想要的计时呢?
很简单,通过特殊功能寄存器配置好初始值就好了
所以,使用定时器的步骤可以分为三步:
- 配置打开计时器
- 设置工作方式
- 设定初始值
初始值计算: a是所选择的重载模式对应的a位寄存器,假如是16位,a的值就是16;x是所需要的时间,单位是微秒;fosc是晶振频率,倘若是12MHz的晶振,此处fosc就填12;最终得到的t就是一个十六位的定时器初始数值,然后将其分给两个八位的特殊功能寄存器TL0与TH0即可。
常用示例(省略版):晶振频率12MHz,在十六位自动重载的模式下,假如要两毫秒,就把一个周期下的晶振次数减去2000微秒,然后再将这个数值分给两个八位的特殊寄存器TL0(低八位)和TH0(高八位)。
示例:要两毫秒
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
定时器的初始值一般可以直接使用烧录软件设定好相关配置后直接生成
void Timer0_Routine() interrupt 1
因为特殊功能寄存器是八位的,所以要分成两部分去配置初始值,前八位放在TH1,后八位放在TL0中。定时器与计数器的本质就是数脉冲,即用整个过程所需的时间 t 除以周期T。
中断
这款单片机有五个中断源,两个外部中断,两个定时器中断,一个串口中断
使用中断的步骤:
- 配置中断
- 什么会触发中断
- 中断响应
中断的响应函数后面得加个特殊的中断向量表,可以简单理解成单片机内部封装好的函数,根据这个interrupt后面的数字去调用指定的中断函数
void Timer0_Routine() interrupt 1
定时器与中断模块化代码展示
定时器初始化配置
void Timer0_Init()//创建精确的时间延时或进行时间相关的任务
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;//允许中断
EA=1;//允许总中断
PT0=0;//配置优先级
}
定时器中断使用模板,在其中写入时间到了需要执行的相应功能即可
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;//配置了静态变量,保证值不丢
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++; //计数器,每次加1微妙
if(T0Count>=1000)
{
T0Count=0;
}
}
杂记
- 假如说单片机要在微秒的情况下工作,则需要使用定时器的工作模式2给定时器的工作模式1不断赋定初始值,一条代码的执行速度接近1微妙,假如是工作在毫秒情况下只需要使用工作方式一就好了
- 在有定时器的程序之中不要同时多个地方都使用delay,多把时序操作写进定时器里面去
- 在使用局部变量的时候一定要考虑是否要保持上次调用该函数留下来的数值,一般都是要的,很多地方用到的话就直接全局变量
- 12MHz的晶振频率可以使得每次加1的时候刚好是1微秒,倘若是11.0952MHz的晶振频率的话就就会导致计时不够准确,但是在配置波特率的时候会准确,这与他们各自的计算公式有关