一、源代码
首先是mod_timer.c文件
/*
文件功能:
提供统一的时间节点
用法介绍:
1.使用Mod_Timer_Init函数进行相关变量初始化
2.将Mod_Timer_1ms_Loop放于1ms循环的中断中
3.通过Mod_Timer_Set_AnyTf设置自由标志的高低电平时间
作者:
春风催雪
更新记录:
2021-11-6>>V0.1:初次使用
2021-12-24>>V0.2:添加任意电平计数的当前电平标志
2022-9-7>>V0.3:将函数Mod_Timer_Set_AnyTf的返回,修改为0或-1
*/
#include "include.h" //头文件统一管理文件
MODTIMER ModTimer;
/*
描述:初始化结构体变量
*/
void Mod_Timer_Init(void)
{
ModTimer.Timer1msTf = 0; //1ms标志
ModTimer.Timer2msTf = 0; //2ms标志
ModTimer.Timer2msCnt = 1; //2ms计数
ModTimer.Timer5msTf = 0; //5ms标志
ModTimer.Timer5msCnt = 2; //5ms计数
ModTimer.Timer10msTf = 0; //10ms标志
ModTimer.Timer10msCnt = 3; //10ms计数
ModTimer.Timer50msTf = 0; //50ms标志
ModTimer.Timer50msCnt = 4; //50ms计数
ModTimer.Timer100msTf = 0; //100ms标志
ModTimer.Timer100msCnt = 5; //100ms计数
ModTimer.Timer200msTf = 0; //200ms标志
ModTimer.Timer200msCnt = 6; //200ms计数
ModTimer.Timer500msTf = 0; //500ms标志
ModTimer.Timer500msReverse = 0; //500ms取反
ModTimer.Timer500msCnt = 7; //500ms计数
ModTimer.Timer1sTf = 0; //1s标志
ModTimer.Timer1sCnt = 8; //1s计数
ModTimer.TimerAnyTf = 0; //任意电平计数重置标志
ModTimer.TimerAnyCnt = 9; //任意电平计数
ModTimer.TimerAnyHighMs = 1; //任意电平标志的置高时间
ModTimer.TimerAnyLowMs = 1; //任意电平标志的置低时间
ModTimer.TimerAnyLevel = 0; //任意电平的当前电平
}
/*
描述:1ms循环执行函数,此函数需要放入1ms的中断中
*/
void Mod_Timer_1ms_Loop(void)
{
ModTimer.Timer1msTf = 1;
ModTimer.Timer2msCnt++;
if(ModTimer.Timer2msCnt > 2)
{
ModTimer.Timer2msTf = 1;
ModTimer.Timer2msCnt = 1;
}
ModTimer.Timer5msCnt++;
if(ModTimer.Timer5msCnt > 5)
{
ModTimer.Timer5msTf = 1;
ModTimer.Timer5msCnt = 1;
}
ModTimer.Timer10msCnt++;
if(ModTimer.Timer10msCnt > 10)
{
ModTimer.Timer10msTf = 1;
ModTimer.Timer10msCnt = 1;
}
ModTimer.Timer50msCnt++;
if(ModTimer.Timer50msCnt > 50)
{
ModTimer.Timer50msTf = 1;
ModTimer.Timer50msCnt = 1;
}
ModTimer.Timer100msCnt++;
if(ModTimer.Timer100msCnt > 100)
{
ModTimer.Timer100msTf = 1;
ModTimer.Timer100msCnt = 1;
}
ModTimer.Timer200msCnt++;
if(ModTimer.Timer200msCnt > 200)
{
ModTimer.Timer200msTf = 1;
ModTimer.Timer200msCnt = 1;
}
ModTimer.Timer500msCnt++;
if(ModTimer.Timer500msCnt > 500)
{
ModTimer.Timer500msTf = 1;
ModTimer.Timer500msReverse = (ModTimer.Timer500msReverse == 1)? 0:1;
ModTimer.Timer500msCnt = 1;
}
ModTimer.Timer1sCnt++;
if(ModTimer.Timer1sCnt > 1000)
{
ModTimer.Timer1sTf = 1;
ModTimer.Timer1sCnt = 1;
}
ModTimer.TimerAnyCnt++;
if(ModTimer.TimerAnyCnt > (ModTimer.TimerAnyHighMs + ModTimer.TimerAnyLowMs)) //大于总时间归零
{
ModTimer.TimerAnyTf = 1;
ModTimer.TimerAnyCnt = 1;
}
if(ModTimer.TimerAnyCnt > ModTimer.TimerAnyHighMs) //判断高低电平
{
ModTimer.TimerAnyLevel = 0;
}
else
{
ModTimer.TimerAnyLevel = 1;
}
}
/*
描述:设置自由时间标志的置位时间和清空时间
Hight:ModTimer.TimerAnyTf的置位时间,单位ms,范围 1~0x7fffffff
Low:ModTimer.TimerAnyTf的清空时间,单位ms,范围 1~0x7fffffff
返回:0表示设置成功,-1表示设置失败
*/
int8_t Mod_Timer_Set_AnyTf(uint32_t Hight, uint32_t Low)
{
if((Hight == 0) || (Hight > 0x7fffffff) || (Low == 0) || (Low > 0x7fffffff)) //确保设置数据不会超范围
{
return -1;
}
ModTimer.TimerAnyHighMs = Hight;
ModTimer.TimerAnyLowMs = Low;
ModTimer.TimerAnyCnt = 1;
ModTimer.TimerAnyTf = 0;
ModTimer.TimerAnyLevel = 0;
return 0;
}
其次是mod_timer.h文件
#ifndef __MOD_TIMER_H__
#define __MOD_TIMER_H__
typedef struct MODTIMERSTRUCT
{
uint8_t Timer1msTf; //1ms标志
uint8_t Timer2msTf; //2ms标志
uint8_t Timer2msCnt; //2ms计数
uint8_t Timer5msTf; //5ms标志
uint8_t Timer5msCnt; //5ms计数
uint8_t Timer10msTf; //10ms标志
uint8_t Timer10msCnt; //10ms计数
uint8_t Timer50msTf; //50ms标志
uint8_t Timer50msCnt; //50ms计数
uint8_t Timer100msTf; //100ms标志
uint8_t Timer100msCnt; //100ms计数
uint8_t Timer200msTf; //200ms标志
uint8_t Timer200msCnt; //200ms计数
uint8_t Timer500msTf; //500ms标志
uint8_t Timer500msReverse; //500ms取反
uint16_t Timer500msCnt; //500ms计数
uint8_t Timer1sTf; //1s标志
uint16_t Timer1sCnt; //1s计数
uint8_t TimerAnyTf; //任意电平计数重置标志
uint8_t TimerAnyCnt; //任意电平计数
uint32_t TimerAnyHighMs; //任意电平的置高时间
uint32_t TimerAnyLowMs; //任意电平的置低时间
uint8_t TimerAnyLevel; //任意电平的当前电平
}MODTIMER;
extern MODTIMER ModTimer;
extern void Mod_Timer_Init(void);
extern void Mod_Timer_1ms_Loop(void);
extern int8_t Mod_Timer_Set_AnyTf(uint32_t Hight, uint32_t Low);
#endif
二、功能描述
1、一般情况下,我们的裸板程序是怎么写的呢?
a、刚开始学习的时候,我们会把所有的功能塞到主函数中执行,把需要定时执行的功能放到定时器中执行。
b、然后随着学习的加深,学会了把功能打包成子函数,这样增加了代码的可读性。
c、再后来,知道了定时器可能因为执行代码太多导致阻塞,所以学会了使用时间标志位(定时器中置位标志,主循环检测对应标志位然后执行对应代码)。
d、使用了标志位之后,就会发现,主循环中的函数并不是都需要一直执行,考虑到CPU占用率,于是给所有的函数都加了标志位。
经过上面一番操作,于是我们的裸板程序结构就变成了,定时器中定时给各个时间标志置位,然后在主循环中循环检测对应的标志,执行对应的函数。
2、今天分享的“定时器模块”,就是实现这种程序结构的一个功能文件。经过相关的配置之后,在主函数中就可以愉快的定时执行函数了。
三、用法介绍
1、第一步,当然是把文件添加到工程里面,然后配置对应的加载。
2、第二步,将函数Mod_Timer_Init放置到初始化的位置,对结构体里面的数据进行初始化。
3、第三步,借助定时器,将函数Mod_Timer_1ms_Loop放置到1ms的循环中。
4、第四步,如果有需要,可以使用函数Mod_Timer_Set_AnyTf,设置一个高低电平定时变化的变量。用来应对特殊的需求。
5、第五步,这时候,在main主循环中,只需要如下使用。
/*10ms例子*/
if(ModTimer.Timer10msTf != 0)
{
... //这里是需要定时执行的代码
ModTimer.Timer10msTf = 0;
}
四、重点介绍
1、如果仔细看了代码,就会发现500ms定时执行还有一个变量Timer500msReverse,它其实是一个定时反转的变量,因为很多的小家电需要定时或者读秒的功能,有了它就不需要单独再去处理。
2、任意电平功能,实际上是定义了两个计数变量,一个代表高电平,另一个代表低电平。两者之和是一个循环,功能相对比较简单。