【stm32】软件定时器
文章目录
为什么
为什么会想着搞个软件定时器呢?
之前的esp8266模块的通信,用的延时阻塞去实现的,对主程序影响挺大的。想着改改,不想上freertos啥的操作系统,就想着之前看4G模块厂家提供有的4G模块使用例程有用到软件延时去实验通信,随即就有了仿写的想法。
软件定时器
本人理解,其实是对定时器+状态机的一个封装,不阻塞的情况下,实现延时的效果。参考解释可见参考链接,代码实现也几乎全部参考此链接。
相关代码
bsp_soft_timer.h
/**
* author:临木木
* 适用于stm32裸机的软件定时器
* 主程序启用前运行bsp_soft_timer_init()函数初始化软件定时器
* bsp_soft_timer_start()函数开启你所需要的软件定时器,bsp_soft_timer_stop()函数停止,注意SOFT_TIMER_NUM
* bsp_soft_timer_update()函数用于更新软件定时器状态,建议放置在主循环内
* bsp_soft_timer_state_get()函数可用于获取软件定时器现所处的运行状态
* 如无需调用回调函数,可选择设置调用函数为soft_timer_nop_callback()函数来实现
*/
#ifndef __BSP_SOFT_TIMER_H__
#define __BSP_SOFT_TIMER_H__
#define SOFT_TIMER_NUM 3 /* 最大 255 */
typedef enum SOFT_TIMER_STATE
{
SOFT_TIMER_STOPPED = 0, /* 停止 */
SOFT_TIMER_RUNNING = 1, /* 运行 */
SOFT_TIMER_TIMEOUT = 2 /* 超时 */
} SOFT_TIMER_STATE; /* 软件定时器状态 */
typedef enum SOFT_TIMER_MODE
{
SOFT_TIMER_MODE_ONE_SHOT = 0, /* 单次模式 */
SOFT_TIMER_MODE_PERIODIC = 1, /* 周期模式 */
} SOFT_TIMER_MODE; /* 运行模式 */
typedef void (*soft_timer_callback)(void *argv, unsigned short int argc);
void bsp_soft_timer_init
(
void
);
void bsp_soft_timer_start
(
unsigned char id,
unsigned char mode,
unsigned int delay,
soft_timer_callback callback,
void *argv,
unsigned short int argc
);
void bsp_soft_timer_stop
(
unsigned char id
);
void bsp_soft_timer_update
(
void
);
unsigned char bsp_soft_timer_state_get
(
unsigned char id
);
void bsp_soft_timer_nop_callback
(
void *argv,
unsigned short int argc
);
#endif
bsp_soft_timer.c
#include "./soft_timer/bsp_soft_timer.h"
#include <stdio.h>
#include "main.h"
typedef struct stru_soft_timer
{
unsigned char state; /* 状态 */
unsigned char mode; /* 模式 */
unsigned int delay; /* 定时时间 */
unsigned int end_tick; /* 到期时间 */
soft_timer_callback callback; /* 回调函数指针 */
void *argv; /* 回调函数参数指针 */
unsigned short int argc; /* 回调函数参数个数 */
} stru_soft_timer_t;
static stru_soft_timer_t timer[SOFT_TIMER_NUM];
/* bsp_soft_timer_init:初始化软件定时器 */
void bsp_soft_timer_init
(
void
)
{
for (int i = 0; i < SOFT_TIMER_NUM; i++)
{
timer[i].state = SOFT_TIMER_STOPPED;
timer[i].mode = SOFT_TIMER_MODE_ONE_SHOT;
timer[i].delay = 0;
timer[i].end_tick = 0;
timer[i].callback = NULL;
timer[i].argv = NULL;
timer[i].argc = 0;
}
}
/* bsp_soft_timer_start:开启软件定时器
* id 启用的软件定时器编号
* mode 运行模式
* delay 定时时间
* callback 回调函数
* argv 参数
* arvc 参数个数 */
void bsp_soft_timer_start
(
unsigned char id,
unsigned char mode,
unsigned int delay,
soft_timer_callback callback,
void *argv,
unsigned short int argc
)
{
assert_param(id < SOFT_TIMER_NUM);
assert_param(mode == SOFT_TIMER_MODE_ONE_SHOT || mode == SOFT_TIMER_MODE_PERIODIC);
timer[id].state = SOFT_TIMER_RUNNING;
timer[id].mode = mode;
timer[id].delay = delay;
timer[id].end_tick = HAL_GetTick() + delay;
timer[id].callback = callback;
timer[id].argv = argv;
timer[id].argc = argc;
}
/* bsp_soft_timer_update:停止软件定时器
* id 停止的软件定时器编号 */
void bsp_soft_timer_stop
(
unsigned char id
)
{
assert_param(id < SOFT_TIMER_NUM);
timer[id].state = SOFT_TIMER_STOPPED;
}
/* bsp_soft_timer_update:软件定时器状态更新 */
void bsp_soft_timer_update
(
void
)
{
for (int i = 0; i < SOFT_TIMER_NUM; i++)
{
switch (timer[i].state)
{
/* 停止状态 */
case SOFT_TIMER_STOPPED:
break;
/* 运行状态 */
case SOFT_TIMER_RUNNING:
if (timer[i].end_tick <= HAL_GetTick())
{
timer[i].state = SOFT_TIMER_TIMEOUT;
timer[i].callback(timer[i].argv, timer[i].argc); /* 调用回调函数 */
}
break;
/* 超时状态 */
case SOFT_TIMER_TIMEOUT:
if (timer[i].mode == SOFT_TIMER_MODE_ONE_SHOT)
{
timer[i].state = SOFT_TIMER_STOPPED;
}
else if (timer[i].mode == SOFT_TIMER_MODE_PERIODIC)
{
timer[i].state = SOFT_TIMER_RUNNING;
timer[i].end_tick = HAL_GetTick() + timer[i].delay;
}
break;
default:
break;
}
}
}
/* bsp_soft_timer_update:获取软件定时器状态
* id 获取软件定时器编号 */
unsigned char bsp_soft_timer_state_get
(
unsigned char id
)
{
return timer[id].state;
}
/* soft_timer_nop_callback:空回调函数 */
void bsp_soft_timer_nop_callback
(
void *argv,
unsigned short int argc
)
{
__NOP();
}
使用例程
// 初始化
bsp_soft_timer_init();
bsp_soft_timer_start(0, SOFT_TIMER_MODE_PERIODIC, 500, bsp_soft_timer_nop_callback, NULL, 0);
// 主函数
while (1)
{
...
bsp_soft_timer_update();
if (bsp_soft_timer_state_get(0) == SOFT_TIMER_TIMEOUT)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 翻转指示灯
}
...
}