单片机怎么做定时器矩阵,彻底解决各种定时问题?
大家好,我是无际。
定时功能非常常用,可以说是刚需,也可以说是很多人的痛点。
做LED闪烁效果要用定时、按键扫描要定时、数码管扫描要定时、滤波要定时等等。
曾经,我在产品开发的时候也被各种定时需求搞得焦头烂额。
还好,后面我自己写了一个定时器的程序架构,今天一步到位,,彻底解决各种定时的问题 。
最近无际单片机编程有几个学员在学习的时候搞不懂这个。
我借此写了这篇文章,然后基于这个文章内容来给学员们直播讲解。
一、为什么我要搞定时器矩阵
定时器矩阵这个概念是我自创的,简单来说就是很多不同定时时间的软件定时器组合。
因为产品开发这么多年,总有乱七八糟的精准定时需求,有50us的,有1ms的,有10ms的,有50ms的,有100ms的等等。
如果没有一个很好的程序架构的话,不同的精准定时需求一多,代码就会很混乱,而且也不好管理,移植性和可扩展性那些就更不用提了。
二、解决需求的思路
然后我就在想,我能不能设计一个定时器的程序架构,让它能够适应所有的精准定时需求。
我的思维雏形大概是这样的。
图左边是定时器时间源, 类似于我们的时钟源,一般我是用单片机定时器中断做个50us的定时,因为用定时器做时间比较精准。
为什么要用50us?因为我产品的RFD波形定时采集频率是50us采一次。
如果你产品没定时这么频繁的功能需求,你完全可以把定时时间源配置成10ms,甚至100ms,这个是根据不同的产品去调整的。
图右边的就是定时器矩阵, 就是各种乱七八糟的不同定时需求组合,比如LED特效定时功能的定时需求、RFD波形定时采集、RFD重复码滤波延时等等。
最终这些定时器矩阵都有一个时间单位/基准,这个时间单位/基准是由定时器时间源提供,如果我配置定时器中断是50us,那定时器矩阵的时间单位就是50us。
有了这种想法以后,剩下的就是考验你的经验和代码水平了。
三、代码设计思路
一个工程师工作越久,做过的项目越多,就要慢慢形成一个面向对象的思维 。
虽然上面雏形出来了,但是我相信很多人依然不知道怎么动手去写代码。
这个是正常的,最好的方法就是先抄后超 。
我是用面向对象的思维去做的 ,对于c语言来说,结构体是实现面向对象最好的方式 。
这里的对象不是你的男女朋友,而是世间万物皆可以当做一个对象。
比如说人是一个对象,这个对象有很多属性 ,比如说性别、年龄、身高、体重等等。
Ok,那在程序里,如何把这个对象的特征用结构体展现出来呢?
可以通过下面这个代码:
那回到我们定时器矩阵这里,我们把定时器矩阵当做一个对象 。
那这个定时器矩阵都需要具备哪些共同的特征 ?
我总结了下面几个:
需要有个变量当做开关标志控制该定时器启动/停止 需要有个变量当做当前的定时值 需要有个变量当做该定时器的定时周期。 定时时间到了以后,需要去执行相应动作,为了灵活使用,需要一个函数指针。那用结构体来表示代码如下:
这里很多人可能有点懵逼,我怎么想不到要这些东西呢?
这个是正常的,不用去纠结,我也不是一开始就把这几个成员都想到的,而是后面做功能的时候慢慢完善的,你刚开始抄我的思维就行了。
后面很多应用都是用这种套路去做的,比如说我们的任务管理、比如菜单这些,用多了自然就熟了,以后你自己也能设计别的对象了。
Ok,这样我们就把定时器矩阵这个对象的特征设计好了。
四、定时器代码实战
1.前面我们用结构体自定义了一个定时器的对象来,下面就要用这个定时器对象”生”出定时器矩阵。
我们直接用定义结构体数组的方式,T_SUM就是我们定时器矩阵的个数,也就是我产品有多少个定时器需求。
后面我们所有的操作都是围绕这个结构体来进行的。
2.配置定时器矩阵时间源,初始化定时器矩阵参数
A). 我们首先要给这个定时器矩阵一个时间源,也就是配置我们要去配置单片机定时器中断。
我们的定时频率配置的是50us,是因为我们产品有的功能最短需要50us的定时。
然后,我们需要写一个初始化函数,去调用这个定时器配置,以及初始化定时器矩阵参数。
B). 然后在这个50us定时器中断函数里,去实现给定时器矩阵定时代码。
这里,我单独写了一个函数。
然后我们在定时器中断函数里调用这个函数,实现给定时器矩阵定时。
3.附加功能
定时器矩阵时间源配置好了,但是我们还需要一些函数来操作定时器矩阵对吧?
A). 编写创建定时器
我希望定时器能像任务一样,想要的时候创建,所以就有了创建定时器函数。
我们创建定时器的时候这样调用就可以了。
B). 复位定时器
如果说我们需要循环定时的话,在定时时间到了以后就需要复位定时器,让定时器重新启动。
除了以上以外,其他功能可以自己去完善,比如说控制定时器状态、删除定时器、获取定时器时间,这里就不一一举例了。
完整的代码和视频教程,大家可以找无际单片机编程来拿。
有了这个定时器程序架构,以后开发产品再也不怕有各种定时需求啦,使用方便,移植性也强,如果加个动态分配,就更完美了。
教你玩单片机之定时器(附程序)
80c51的定时器
80c51单片机内有两个可编程的定时/计数器T0、T1。它们是一个16位计数器,分别由一个高8位和一个低8位的寄存器组成的。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。
定时/计数器的工作原理
定时/计数器实质上是一个加1计数器。它随着计数器的输入脉冲进行自加1,也就是每来一个脉冲,计数器就自动加1,,当加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置1,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。
工作方式寄存器TMOD
GATE:门控制
0时:仅有运行控制位TRx来控制定时/计数器的开启
1时:由TRx和外部中断脉冲计数(用于计算外部中断负跳变 的次数)
C/T:计数器模式和定时器模式选择
0时:选择定时器模式
1时:选择为计数器模式
M1和M0:选择定时/计数器的工作方式
定时器/计数器控制寄存器TCON
IT0和IT1是设置外部中断的触发方式
当其为0时,为低电平触发方式
当其为1时,为负跳变触发方式
IE0和IE1是外部中断标志位
TF0和TF1是定时器的中断标志
TR1和TR0是打开相应的定时器
其他的是定时/计数器的控制
定时/计数器的工作方式
方式1
方式1为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。
方式2
方式2的计数位数是16位,由TL0作为低8位、TH0作为高8位,组成了16位加1计数器 。
方式3
方式3为自动重装初值的8位计数方式。
方式4
方式4只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。
定时器操作步骤:
选择工作方式(设置M1,M0)
选择控制方式(设置GATE)
选择定时器还是计数器模式(设置C/T)
给定时/计数器赋初值(设置THx和TLx)
开启定时器中断(设置ET0或ET1)
开启总中断(设置EA)
打开计数器(设置TR1或TR0)
定时器小程序
void TimerConfiguration()
{
TMOD = 0x01; //定时器0选择工作方式1
TH0 = 0x3C; //设置初始值
TL0 = 0xB0;
EA = 1; //打开总中断
ET0 = 1; //打开定时器0中断
TR0 = 1; //启动定时器0
}
单片机之定时器LED程序
实验效果 :LED每隔500ms左移一次
void main(void)
{
Time=0;
GPIO_LED=0XFE;
TimerConfiguration();
while(1)
{
if(Time==10)
{
GPIO_LED=_crol_(GPIO_LED,1);
Time=0;
}
}
}
void TimerConfiguration()
{
TMOD = 0x01; //选择工作方式1
TH0 = 0x3C; //设置初始值,定时50MS
TL0 = 0xB0;
EA = 1; //打开总中断
ET0 = 1; //打开定时器0中断
TR0 = 1; //启动定时器0
}
void Timer0() interrupt 1
{
TH0 = 0x3C; //设置初始值
TL0 = 0xB0;
Time++;
}
相关问答
51 单片机 T0 定时器 4种方式的 定时 时长分别是多少 - 181****489...这个取决于系统时钟和定时器位数。例如传统89c51单片机(在不考虑新型单片机有分频设置的情况下),12MHz系统时钟,采用8位定时器,最大定时时间为256us...
单片机定时 15s c语言怎么实现方法?单片机定时15sc语言使用定时器来实现单片机定时15sc语言使用定时器来实现
定时器 在 单片机 中程序的运行过程 - yn4Wk5LPWx 的回答 - 懂得我觉得是这样的,单片机的定时器,它的计数过程是相当于电脑里面一个后台运行的东东一样。在计数时单片机同时在执行其他程序,计数周期就是单片机的一...
单片机 是如何实现自动运行程序的?将程序代码编写并存储在单片机的存储器中。然后,通过设置单片机的复位电路,使其在上电或复位时自动开始执行程序。...单片机实现自动运行程序的过程如下:首...
51 单片机 如何编写一个 定时 电机开机时间?要编写一个定时电机开机时间的程序,你可以使用51单片机的定时器功能。首先,设置一个定时器,设定定时时间。然后,在定时器中断服务程序中,将电机的开机信号...
单片机 如何把 定时 器延时写成delay延时那样在主程序里随便调用?你可以在调用函数时启动定时器,并通过中断服务函数判断中断次数是否达到,达到的话就置一个标志位,然后主函数中while判断,不过这太浪费系统资源了,有什么用...
stc15 单片机定时 时间怎么算?单片机的定时时间的计算公式=计数值(定时值)*机器周期=计数值(定时值)*12/晶振频率。上面的两个等号是等价的,因为,单片机的机器周期=12秒/晶振频率...
请问 单片机定时 器的初值是怎么设的?定时器初值=2^n-m*晶振值/分频系数;n:定时器模式,有13,8,16三种;m:要定的时间长度,晶振值:12MHz或6Mhz分频系数:12定义10毫秒;定时器模式1,晶振频率12MHz定时...
51 单片机定时 器一毫秒怎么写?假设晶振为12MHz,不用中断时程序语句如下:TMOD=0x01;//定时器0工作方式1TH0=(65536-1000)/256;//装入初值TL0=(65536-1000)%256;TF...
mcs-51系列 单片机 的 定时 器T1用做 定时 方式时,采用工作方式1,则工作方式控制字为?让我来告诉你答案!答案应该是ATMOD=01100000GC/TM1M0T1T0让我来告诉你答案!答案应该是ATMOD=01100000GC/TM1M0T1T0