1> 系统定时器概述
为了解决51单片机内部定时器不足,基于SysTick系统嘀嗒的基础上,模拟出多路定时器;
51单片机内部定时器通常有3路:
Timer1:用于串口时钟;
Timer2:用于系统嘀嗒时钟SysTick;
Timer0:用于其他;
2> 系统定时器-数据类型
typedef void (*function)(void);
#define Function(address) (*((function)address)) ()
typedef struct
{
ushort16_t Times;
function Function;
}TimerStruct;
#define TimerSum 0x4 // 定时器数量,不超过8
static uchar8_t idata State = 0; // 工作标记寄存器,共8路,置1使能
static TimerStruct idata TimerBlock[TimerSum]; // 注册函数及次数存储数组
4路定时器;
3> 系统定时器-启动
typedef enum
{
TimerSystick = 0, // 系统节拍中处理
TimerMessage = 1 // while(1)循环中消息处理
}TimerModeEnum;
static TimerModeEnum idata Mode; // 工作模式
/**
* @brief 软件定时器
* @mode 2种处理方式:
* 1> 直接在节拍中断中处理,适合费用低的
* 2> 在消息中处理,适合处理费用高的
* @times 延时节拍数,以系统节拍为但我 times*100ms
* @registerFunction 回调执行函数;
* @retval 返回ID号,从0开始,失败则返回invalid(-1)
*/
uchar8_t TimerStart(TimerModeEnum mode, ushort16_t times, function registerFunction)
{
uchar8_t i;
EnterCritical();
for(i = 0; i < TimerSum; i++)
{
if(!GET_BIT(State, i))
{
TimerBlock[i].Times = times; // 注册节拍次数
TimerBlock[i].Function = registerFunction; // 注册回调函数
if(mode) // 工作模式
SET_BIT(Mode, i);
else
CLEAR_BIT(Mode, i);
SET_BIT(State, i); // 置位开启
ExitCritical();
return(i);
}
}
ExitCritical();
return(invalid);
}
4> 系统定时器-任务函数
软件定时器是基于SysTick实现计时,所以必须要一个任务函数
void Timer_Task(void)
{
uchar8_t i = 0;
uchar8_t stateBackup;
if (State == 0x00) {
return; // 状态表为空,跳出
}
stateBackup = State; // 复制一份状态表
while (stateBackup)
{
if ((stateBackup & 0x01) == 1)
{
if ((--TimerBlock[i].Times) == 0) // 计数递减到0时
{
if (GET_BIT(Mode, i)) // 获取工作模式
QUEUE_Post(MessageTimer, (ushort16_t)TimerBlock[i].Function);
else
(TimerBlock[i].Function)(); // 系统节拍中处理
CLEAR_BIT(State, i); // 关闭这一路定时器
}
}
stateBackup = stateBackup >> 1;
i++;
}
}
5> 系统定时器-停止函数
/**
* @brief 关闭某一路定时器
* @id TimerStart执行后返回的id,0,1,2...
* @retval 无
*/
void TimerStop(uchar8_t id)
{
if (id >= TimerSum) return;
EnterCritical();
CLEAR_BIT(State, id);
ExitCritical();
}