单片机裸机实用组件–软件定时器、时间戳
之前写过一篇关于单片机定时器延时计时功能的博客 ,刚工作的时候搞得现在看来还是比较糙的,是时候整一个新的了。
单片机裸机适用的定时器小组件,通过一个定时器记录系统运行时长,为用户提供一个时间戳信息,当然也有软件定时器功能。
移植教程
- 将 base_timer.c base_timer.h base_timer_port.c 添加到工程中
- 打开 base_timer_port.c 文件,自行实现里面的函数, 其中最重要的是 btimer_port_init(uint32_t clock, uint16_t ticks)函数和 uint32_t btimer_port_get_ticks(void)函数
void btimer_port_init(uint32_t clock, uint16_t ticks)
{
}
uint32_t btimer_port_get_ticks(void)
{
return ;
}
- 将 btimer_ticks();函数添加到定时器中断服务函数中,周期性的执行。
使用说明
- 初始化定时器
void btimer_init(uint32_t clock, uint16_t ticks);
- 定时器初始化后,系统内就存在了一个时基,可以获取系统从定时器初始化到现在的运行 ticks,通过这个时间戳信息,就可以实现各种各样的功能了。
需要注意的是,us和ms相关的函数都是在调用 uint64_t btimer_get_ticks(void); 函数的基础上使用除法实现的,但是没有double FPU的单片机对 uint64_t 的除法运算比较耗时,实测STM32F103 72MHz时, 一次uint64_t 需要50us左右
uint64_t btimer_get_ticks(void);
uint32_t btimer_get_us(void);
uint32_t btimer_get_ms(void);
void btimer_delay_ticks(uint32_t ticks);
void btimer_delay_us(uint32_t us);
void btimer_delay_ms(uint32_t ms);
- 组件内同样也有实现软件定时器,在 base_timer.h 中使能
#define SOFT_TIMER_ENABLE 1
void stimer_init(Stimer_t * stimer, uint16_t ticks, uint8_t count, stimerCallback_t cb);
void stimer_start(Stimer_t * stimer);
void stimer_stop(Stimer_t * stimer);
使用例子
void stimerLed1Callback(void)
{
}
void stimerLed2Callback(void)
{
}
void stimerLed3Callback(void)
{
}
Stimer_t g_stimerLed1, g_stimerLed2, g_stimerLed3;
int main(void)
{
btimer_init(72000000, 1000);
uint64_t ticks1 = btimer_get_ticks();
btimer_delay_us(10000);
uint64_t ticks2 = btimer_get_ticks();
btimer_delay_ms(10);
stimer_init(&g_stimerLed1, 100, COUNTER_MAX, stimerLed1Callback);
stimer_init(&g_stimerLed2, 1000, 1, stimerLed2Callback);
stimer_init(&g_stimerLed3, 1000, COUNTER_MAX, stimerLed3Callback);
stimer_start(&g_stimerLed1);
stimer_start(&g_stimerLed2);
stimer_start(&g_stimerLed3);
while (1)
{
if(stimer_is_timeout(&g_stimerLed2))
{
stimer_init(&g_stimerLed2, 1000, 1, stimerLed2Callback);
stimer_start(&g_stimerLed2);
}
}
}
base_timer.c
#include "base_timer.h"
typedef struct{
uint32_t ulTickPerMicrosecond;
uint32_t ulTickPerMillisecond;
uint32_t ulTickPerHandler;
volatile uint64_t ullTicks;
uint32_t ulDelayOffSet;
}BaseTimerParame_t;
static BaseTimerParame_t s_tTimer;
#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)
static void stimer_ticks(void);
#endif
void btimer_ticks(void)
{
s_tTimer.ullTicks += s_tTimer.ulTickPerHandler;
#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)
stimer_ticks();
#endif
}
void btimer_init(uint32_t clock, uint16_t ticks)
{
if(clock < 1000000ul)
{
s_tTimer.ulTickPerMicrosecond = 1;
}
else
{
s_tTimer.ulTickPerMicrosecond = clock / 1000000ul;
}
if(clock < 1000)
{
while(1);
}
else
{
s_tTimer.ulTickPerMillisecond = clock / 1000;
}
s_tTimer.ullTicks = 0;
s_tTimer.ulTickPerHandler = clock / ticks;
s_tTimer.ulDelayOffSet = 0;
btimer_port_init(clock, ticks);
uint32_t currentTicks1 = 0, currentTicks2 = 0;
for(int i = 0; i < 1000; i++)
{
currentTicks1 = btimer_get_ticks();
btimer_delay_us(1);
currentTicks2 = btimer_get_ticks();
s_tTimer.ulDelayOffSet += (currentTicks2 - currentTicks1 - s_tTimer.ulTickPerMicrosecond);
}
s_tTimer.ulDelayOffSet = (s_tTimer.ulDelayOffSet + 500)/1000;
}
void btimer_deinit(void)
{
btimer_port_deinit();
}
uint64_t btimer_get_ticks(void)
{
uint64_t ticks = 0;
uint32_t timerValue = 0;
do
{
ticks = s_tTimer.ullTicks;
timerValue = btimer_port_get_ticks();
}while(ticks != s_tTimer.ullTicks);
return ticks + timerValue;
}
uint32_t btimer_get_us(void)
{
return btimer_get_ticks()/s_tTimer.ulTickPerMicrosecond;
}
uint32_t btimer_get_ms(void)
{
return btimer_get_ticks()/s_tTimer.ulTickPerMillisecond;
}
void btimer_delay_ticks(uint32_t ticks)
{
uint64_t end = btimer_get_ticks() + ticks - s_tTimer.ulDelayOffSet;
while(btimer_get_ticks() <= end);
}
void btimer_delay_us(uint32_t us)
{
uint64_t end = btimer_get_ticks() + us * s_tTimer.ulTickPerMicrosecond - s_tTimer.ulDelayOffSet;
while(btimer_get_ticks() <= end);
}
void btimer_delay_ms(uint32_t ms)
{
uint64_t end = btimer_get_ticks() + ms * s_tTimer.ulTickPerMillisecond - s_tTimer.ulDelayOffSet;
while(btimer_get_ticks() <= end);
}
#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)
static Stimer_t * s_stimer_head = 0;
static void stimer_ticks(void)
{
Stimer_t * node = s_stimer_head;
while(node)
{
if(node->ucCounter > 0)
{
if(-- node->ulTicks == 0)
{
if(node->ucCounter != COUNTER_MAX)
{
node->ucCounter--;
}
node->ulTicks = node->ulPerLoad;
node->ucFlag = 1;
if(node->stimerCallback != 0)
{
node->stimerCallback((void *)node);
}
if(node->ucCounter == 0)
{
stimer_stop(node);
}
}
}
else
{
stimer_stop(node);
}
node = node->ptNextTimer;
}
}
void stimer_init(Stimer_t * stimer, uint16_t ticks, uint8_t count, stimerCallback_t cb)
{
stimer_port_lock();
stimer->ulTicks = ticks;
stimer->ulPerLoad = ticks;
stimer->ucCounter = count;
stimer->ucFlag = 0;
stimer->stimerCallback = cb;
stimer_port_unlock();
}
void stimer_start(Stimer_t * stimer)
{
stimer_port_lock();
Stimer_t * node = s_stimer_head;
while(node)
{
if(node == stimer)
{
stimer_port_unlock();
return;
}
else
{
node = node->ptNextTimer;
}
}
stimer->ptNextTimer = s_stimer_head;
s_stimer_head = stimer;
stimer_port_unlock();
}
void stimer_stop(Stimer_t * stimer)
{
Stimer_t** curr;
for(curr = &s_stimer_head; *curr; )
{
Stimer_t* entry = *curr;
if (entry == stimer)
{
stimer_port_lock();
*curr = entry->ptNextTimer;
stimer_port_unlock();
return;
}
else
{
curr = &entry->ptNextTimer;
}
}
}
uint8_t stimer_is_timeout(Stimer_t * stimer)
{
uint8_t flag = stimer->ucFlag;
stimer_port_lock();
stimer->ucFlag = 0;
stimer_port_unlock();
return flag;
}
#endif
base_timer.h
#ifndef __BASE_TIMER_H
#define __BASE_TIMER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void btimer_init(uint32_t clock, uint16_t ticks);
void btimer_deinit(void);
uint64_t btimer_get_ticks(void);
uint32_t btimer_get_us(void);
uint32_t btimer_get_ms(void);
void btimer_delay_ticks(uint32_t ticks);
void btimer_delay_us(uint32_t us);
void btimer_delay_ms(uint32_t ms);
void btimer_ticks(void);
#define SOFT_TIMER_ENABLE 1
#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)
#define COUNTER_MAX (0xFF)
typedef void (*stimerCallback_t)(void *);
typedef struct Stimer
{
volatile uint8_t ucCounter;
volatile uint8_t ucFlag;
volatile uint32_t ulTicks;
uint32_t ulPerLoad;
stimerCallback_t stimerCallback;
struct Stimer * ptNextTimer;
}Stimer_t;
void stimer_init(Stimer_t * stimer, uint16_t ticks, uint8_t count, stimerCallback_t cb);
void stimer_start(Stimer_t * stimer);
void stimer_stop(Stimer_t * stimer);
uint8_t stimer_is_timeout(Stimer_t * stimer);
void stimer_port_lock(void);
void stimer_port_unlock(void);
#endif
void btimer_port_init(uint32_t clock, uint16_t ticks);
void btimer_port_deinit(void);
uint32_t btimer_port_get_ticks(void);
#ifdef __cplusplus
}
#endif
#endif
base_timer_port.c
#include "base_timer.h"
void btimer_port_init(uint32_t clock, uint16_t ticks)
{
}
void btimer_port_deinit(void)
{
}
uint32_t btimer_port_get_ticks(void)
{
return ;
}
#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)
void stimer_port_lock(void)
{
}
void stimer_port_unlock(void)
{
}
#endif
|