03-C语言底层驱动:软件定时器驱动
创建软件定时器,纯C语言,只依赖一个硬件定时器,现在每个单片机至少都有一个定时器吧,所以支持多平台单片机移植。最多可以创建65535个软件定时器,定时精度可以达到硬件定时器的水平,再也不用担心定时器不够用了!
具体实现方法主要通过一个单链表。
头文件:
#ifndef __BSP_SOFTTIMER_H
#define __BSP_SOFTTIMER_H
#ifndef uint32_t
#define uint32_t unsigned long
#endif
#ifndef uint16_t
#define uint16_t unsigned int
#endif
#ifndef uint8_t
#define uint8_t unsigned char
#endif
/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0) /* 使能全局中断 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中断 */
#define SET_BIT(dat,bits) (dat |= (1<<bits))
#define IS_BIT(dat,bits) (dat & (1<<bits))
#define CLEAR_BIT(dat,bits) (dat &= ~(1<<bits))
typedef enum _en_typeTimer{
HARD_TIMER=0,
SOFT_TIMER,
}en_typeTimer;
typedef enum _en_timerRunStatus{
RUNNING = 0,
STOP,
}en_timerRunStatus;
typedef void (*timerFunction) (void *arg);
typedef struct st_timer_ts
{
struct st_timer_ts *nextNode; /*下一定时器结点的地址*/
uint32_t u32DurationTicks; /*定时的时间,一个u32DurationTicks就是周期调用bsp_timerLoop_ToIrq()函数的中断时长*/
uint32_t u32DelayTicks; /*当前定时递减计数值*/
timerFunction timerFunc; /*回调函数地址*/
void * arg; /*传递给回调函数的参数*/
en_typeTimer en_typeTime; /*定时器类型,HARD_TIMER=硬定时器,在定时器中断中执行回调函数,时间精度高。
SOFT_TIMER=软定时器,在main while()大循环中执行回调函数。
*/
en_timerRunStatus en_runSta; /*定时器的运行状态*/
uint8_t u8TimerCtr; /*bit0:1=定时时间到,0=时间未到
bit1:1=循环定时器,0=一次性定时器
*/
}st_timer_t;
void bsp_createTimer(st_timer_t *st_timer, en_typeTimer en_typeTime, timerFunction func, void *arg);
void bsp_timerLoop_ToIrq (st_timer_t *headTimer);
void bsp_softRunTimer(st_timer_t *headTimer);
void bsp_startTime(st_timer_t *st_timer, uint32_t u32DurationTicks);
void bsp_startAutoTime(st_timer_t *st_timer, uint32_t u32DurationTicks);
void bsp_stopTime(st_timer_t *st_timer);
#endif
c文件:
/*
*********************************************************************************************************
*
* 模块名称 : 软件定时器
* 文件名称 : bsp_softTimer.c
* 版 本 : V2.0
* 说 明 : 本文件可以创建65535个软件定时器。定时器的回调函数可以在定时器中断中执行,这种方式定时时间精度高。
* 也可以在main主函数大循环中调用,可以执行一些对时间要求不高的功能。每个定时器的回调函数执行方式可
* 以二选一。
*
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2017-09-07 徐
* V2.0 2019-08-17 徐 增加创建一次性和循环定时器函数,增加停止函数。
*********************************************************************************************************
*/
#include "bsp.h"
static uint16_t s_g_u16TimerCnt = 0;//创建的定时器数量
/*
*********************************************************************************************************
* 函 数 名: bsp_createTimer
* 功能说明: 创建一个软件定时器,此时软件定时器是停止状态。
* 形 参: *st_timer:定时器结构体地址。 en_typeTime:回调函数的执行方式
* func :回调函数地址。 *arg :回调函数的形参。
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_createTimer(st_timer_t *st_timer, en_typeTimer en_typeTime, timerFunction func, void *arg)
{
static st_timer_t *st_pPreTimer = (st_timer_t*)0;
if(s_g_u16TimerCnt != 0) /*第一次进入,nextNode不赋值*/
{
st_pPreTimer->nextNode = st_timer; //上次定时器的nextNode赋值
}
st_pPreTimer = st_timer; //记录本次定时器的地址
s_g_u16TimerCnt++;
st_timer->u32DurationTicks = 0;
st_timer->u32DelayTicks = 0;
st_timer->timerFunc = func;
st_timer->arg = arg;
st_timer->en_typeTime = en_typeTime;
st_timer->en_runSta = STOP;
st_timer->u8TimerCtr = 0;
}
/*
*********************************************************************************************************
* 函 数 名: bsp_startTime
* 功能说明: 启动一个一次性软件定时器。
* 形 参: *st_timer:定时器结构体地址。 u32DurationTicks: 定时时长,单位多少个中断周期。
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_startTime(st_timer_t *st_timer, uint32_t u32DurationTicks)
{
if(st_timer == 0)
return ;
DISABLE_INT(); /*关总中断*/
st_timer->en_runSta = RUNNING;
st_timer->u32DurationTicks = u32DurationTicks;
st_timer->u32DelayTicks = u32DurationTicks;
CLEAR_BIT(st_timer->u8TimerCtr,1);
ENABLE_INT();
}
/*
*********************************************************************************************************
* 函 数 名: bsp_startAutoTime
* 功能说明: 启动一个循环软件定时器。
* 形 参: *st_timer:定时器结构体地址。 u32DurationTicks: 定时时长,单位多少个中断周期。
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_startAutoTime(st_timer_t *st_timer, uint32_t u32DurationTicks)
{
if(st_timer == 0)
return ;
DISABLE_INT(); /*关总中断*/
st_timer->en_runSta = RUNNING;
st_timer->u32DurationTicks = u32DurationTicks;
st_timer->u32DelayTicks=u32DurationTicks;
SET_BIT(st_timer->u8TimerCtr,1);
ENABLE_INT();
}
/*
*********************************************************************************************************
* 函 数 名: bsp_stopTime
* 功能说明: 停止一个软件定时器。
* 形 参: *st_timer:定时器结构体地址。
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_stopTime(st_timer_t *st_timer)
{
st_timer->en_runSta = STOP;
}
/*
*********************************************************************************************************
* 函 数 名: bsp_timerLoop_ToIrq
* 功能说明: 软件定时器逻辑具体实现的函数,必须放在硬件定时器中断中循环调用。
* 形 参: *headTimer:创建的第一个定时器结构体地址。
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_timerLoop_ToIrq(st_timer_t *headTimer)
{
uint16_t j=0;
st_timer_t *timer=headTimer;
for(; j<s_g_u16TimerCnt; j++)
{
if(timer->en_runSta == RUNNING)
{
if ((timer->u32DelayTicks == 0) || (--timer->u32DelayTicks == 0))
{
if(timer->en_typeTime == HARD_TIMER)//硬件定时器,执行回调函数
{
timer->timerFunc(timer->arg);
}
else
{
SET_BIT(timer->u8TimerCtr,0);//软件定时器,在while中执行
}
if(IS_BIT(timer->u8TimerCtr,1)) /*循环定时器重装载计数值*/
{
timer->u32DelayTicks = timer->u32DurationTicks;
}
else /*一次性定时器*/
{
timer->en_runSta = STOP;
}
}
}
timer=timer->nextNode;
}
}
/*
*********************************************************************************************************
* 函 数 名: bsp_softRunTimer
* 功能说明: 遍历软定时器,查询定时时间是否到了,在main.c while{}中执行
* 形 参: *headTimer:创建的第一个定时器结构体地址。
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_softRunTimer(st_timer_t *headTimer)
{
uint16_t j=0;
st_timer_t *timer=headTimer;
for(; j<s_g_u16TimerCnt; j++)
{
if(IS_BIT(timer->u8TimerCtr,0))
{
CLEAR_BIT(timer->u8TimerCtr,0);
timer->timerFunc(timer->arg);
}
timer=timer->nextNode;
}
}
最后来一个简单的例子:
#include "bsp.h"
st_timer_t timer1;
st_timer_t timer2;
void timer1Task(void *arg)
{
printf("time1 run\r\n");
}
void timer2Task(void *arg)
{
printf("time1 run\r\n");
}
int main(void)
{
SysTick_Config(SystemCoreClock / 1000); /*1ms滴答中断定时器*/
bsp_createTimer(&timer1,SOFT_TIMER,timer1Task,(void*)0);
bsp_createTimer(&timer2,HARD_TIMER,timer2Task,(void*)0);
bsp_startTime(&timer1,100); /*100个定时器中断执行一次*/
bsp_startAutoTime(&timer2,500);
while(1)
{
bsp_softRunTimer(&timer1);
}
}
/*
*********************************************************************************************************
* 函 数 名: SysTick_Handler
* 功能说明: 系统嘀嗒定时器中断服务程序。启动文件中引用了该函数。建议中断时间1ms。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void SysTick_Handler(void)
{
bsp_timerLoop_ToIrq(&timer1);
}