前言
之前接手的一个STM32项目里使用的,感觉写的挺好,用起来,比较的简单,适合裸机下的定时任务的实现。
软件定时器,可以设置时间,设置定时器超时函数,实现定时功能。可以开启,可以停止。
比不上操作系统RTOS里的定时器Timer,但可以用于简单的定时通知的实现。
代码
timer_drv.h
#ifndef __TIMER_DRV_H__
#define __TIMER_DRV_H__
#include "stm32f10x.h"
/* 软件定时器时钟节拍单位 */
#define TIME_BASE_1S 1 //1秒
/* 软件定时器数量 */
#define TIMER_NUM 5
typedef void TIMER_CALLBACK(void);
typedef struct softTimer
{
uint8_t state; //状态
uint8_t mode; //模式
uint32_t match; //到期时间
uint32_t period; //定时周期
TIMER_CALLBACK *cb; //回调函数指针
void *argv; //参数指针
uint16_t argc; //参数个数
}softTimer;
typedef enum tmrState
{
SOFT_TIMER_STOPPED = 0, //停止
SOFT_TIMER_RUNNING, //运行
SOFT_TIMER_TIMEOUT //超时
}tmrState;
typedef enum tmrMode
{
MODE_ONE_SHOT = 0, //单次模式
MODE_PERIODIC, //周期模式
}tmrMode;
void tickCnt_Update(void);
uint32_t tickCnt_Get(void);
void softTimer_Init(void);
void soft_timers_init(void);
uint8_t softTimer_GetState(uint16_t id);
void app_timer_create(uint16_t id, tmrMode mode, TIMER_CALLBACK *cb);
void app_timer_start(uint16_t id, uint32_t delay);
void app_timer_stop(uint16_t id);
void softTimer_Update(void);
#endif
timer_drv.c
#include "timer_drv.h"
static volatile uint32_t tickCnt = 0; //软件定时器时钟节拍
static softTimer timer[TIMER_NUM]; //软件定时器数组
/*****************************************************
* function: 更新时钟节拍
* param:
* return:
* note: 需在定时器中断内执行
******************************************************/
void tickCnt_Update(void)
{
tickCnt++;
}
/*****************************************************
* function: 获取时钟节拍
* param:
* return: 时钟节拍
* note:
******************************************************/
uint32_t tickCnt_Get(void)
{
return tickCnt;
}
/*****************************************************
* function: 软件定时器初始化
* param:
* return:
* note:
******************************************************/
void softTimer_Init(void)
{
uint16_t i;
for(i=0; i<TIMER_NUM; i++)
{
timer[i].state = SOFT_TIMER_STOPPED;
timer[i].mode = MODE_ONE_SHOT;
timer[i].match = 0;
timer[i].period = 0;
timer[i].cb = NULL;
timer[i].argv = NULL;
timer[i].argc = 0;
}
}
/*****************************************************
* function: 获取软件定时器状态
* param: 软件定时器ID
* return: 定时器状态
* note:
******************************************************/
uint8_t softTimer_GetState(uint16_t id)
{
return timer[id].state;
}
void app_timer_create(uint16_t id, tmrMode mode, TIMER_CALLBACK *cb)
{
assert_param(id < TIMER_NUM);
assert_param(mode == MODE_ONE_SHOT || mode == MODE_PERIODIC);
timer[id].state = SOFT_TIMER_STOPPED;
timer[id].mode = mode;
timer[id].cb = cb;
}
/*****************************************************
* function: 启动软件定时器
* param1: 软件定时器ID
* param2: 定时器模式
* param3: 延时时间(对周期定时器,亦是周期时间),单位TIME_BASE_1S
* param4: 回调函数指针
* param5: 回调函数参数:参数指针
* param6: 回调函数参数:参数长度
* return:
* note:
******************************************************/
void app_timer_start(uint16_t id, uint32_t delay)
{
assert_param(id < TIMER_NUM);
timer[id].match = tickCnt_Get() + delay;
timer[id].period = delay;
timer[id].state = SOFT_TIMER_RUNNING;
}
/*****************************************************
* function: 停止软件定时器
* param: 软件定时器ID
* return:
* note:
******************************************************/
void app_timer_stop(uint16_t id)
{
assert_param(id < TIMER_NUM);
timer[id].state = SOFT_TIMER_STOPPED;
}
/*****************************************************
* function: 更新软件定时器状态
* param:
* return:
* note:
******************************************************/
void softTimer_Update(void)
{
uint16_t i;
for(i=0; i<TIMER_NUM; i++)
{
switch (timer[i].state)
{
case SOFT_TIMER_STOPPED:
break;
case SOFT_TIMER_RUNNING:
if(timer[i].match <= tickCnt_Get())
{
timer[i].state = SOFT_TIMER_TIMEOUT;
timer[i].cb(); //执行回调函数
}
break;
case SOFT_TIMER_TIMEOUT:
if(timer[i].mode == MODE_ONE_SHOT)
{
timer[i].state = SOFT_TIMER_STOPPED;
}
else
{
timer[i].match = tickCnt_Get() + timer[i].period;
timer[i].state = SOFT_TIMER_RUNNING;
}
break;
default:
//printf("timer[%d] state error!\r\n", i);
break;
}
}
}
运行条件
还需要定时执行:void tickCnt_Update(void);
我这里是整秒的定时,放在了RTC 中断里面。
扫描二维码关注公众号,回复:
12476039 查看本文章
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_WaitForLastTask();
tickCnt_Update();
}
}
操作实例
首先需要初始化定时器,创建定时器,可以是单次,或周期性的
uint8_t g_sys_timers_flag; //系统软件定时
uint8_t SYS_TIMER_ID = 0x00; //系统定时器ID
void soft_timers_init(void)
{
softTimer_Init();
app_timer_create(SYS_TIMER_ID, MODE_PERIODIC, sys_timer_update_handler);
}
void sys_timer_update_handler(void)
{
timer_flag_update_handler(); //软件定时器超时回调函数
}
/**@brief Function for starting timers.
*/
void sys_timers_start(void)
{
if(g_sys_timers_flag == 0x00)
{
app_timer_start(SYS_TIMER_ID, SYS_TIMER_INTERVAL);
g_sys_timers_flag = 0x01;
}
}
/**@brief Function for stop timers.
*/
void sys_timers_stop(void)
{
if(g_sys_timers_flag == 0x01)
{
app_timer_stop(SYS_TIMER_ID);
g_sys_timers_flag = 0x00;
}
}
总结
使用比较的简单灵活,适合裸机下的定时消息的触发。
可以根据需求参考使用。