多路软件定时器(以GD32F470ZGT6为例)一般依赖于一个硬件定时器或者其他时钟源(一般32位单片机开发中,用芯片内部的SysTick定时器)
在中断服务函数中更新检查每一个软件定时器的状态,当其中任何一个软件定时器到达预设时间间隔时,就去执行对应的任务,可以使用回调函数实现,也可以用判断标志位实现(这里以判断标志位为例)
soft_timer.c
#include "board.h"
#include "soft_timer.h"
// 定义软件定时器数组
static software_timer timers[SOFT_TIMER_MAX];
/**
- @brief 初始化单次定时器
- @NOTE None
- @param timer: 要初始化的软件定时器,timeout: 超时时间
- @retval None
*/
void soft_timer_single_init(soft_timer_type timer, uint32_t timeout)
{
soft_timer_interrupt_disable();
if (timer < SOFT_TIMER_MAX)
{
timers[timer].counter = 0;
timers[timer].timeout = timeout;
timers[timer].is_timeout = 0;
timers[timer].is_repeat = 0;
}
soft_timer_interrupt_enable();
}
/**
- @brief 初始化重复定时器
- @note None
- @param timer: 要初始化的软件定时器,timeout: 超时时间
- @retval None
*/
void soft_timer_repeat_init(soft_timer_type timer, uint32_t timeout)
{
soft_timer_interrupt_disable();
if (timer < SOFT_TIMER_MAX)
{
timers[timer].counter = 0;
timers[timer].timeout = timeout;
timers[timer].is_timeout = 0;
timers[timer].is_repeat = 1;
}
soft_timer_interrupt_enable();
}
/**
- @brief 停止一个软件定时器
- @note None
- @param timer:要停止的软件定时器
- @retval None
*/
void soft_timer_stop(soft_timer_type timer)
{
soft_timer_interrupt_disable();
if (timer < SOFT_TIMER_MAX)
{
timers[timer].is_timeout = 0;
timers[timer].counter = 0;
timers[timer].is_repeat = 0;
}
soft_timer_interrupt_enable();
}
/**
- @brief 检查对应的定时器是否超时了
- @note None
- @param timer:要检查的定时器
- @retval None
*/
uint8_t soft_timer_is_timeout(soft_timer_type timer)
{
uint8_t ret = 0;
if (timer < SOFT_TIMER_MAX)
{
ret = timers[timer].is_timeout;
if (ret)
{
timers[timer].is_timeout = 0;
}
}
return ret;
}
/**
- @brief 复位对应的定时器
- @note None
- @param timer:要复位的定时器
- @retval None
*/
void soft_timer_reset(soft_timer_type timer)
{
soft_timer_interrupt_disable();
if (timer < SOFT_TIMER_MAX)
{
timers[timer].counter = 0;
timers[timer].is_timeout = 0;
}
soft_timer_interrupt_enable();
}
/**
- @brief 在GD32的SysTick_Handler中断服务程序中调用,每1ms调用一次,在这个工程里面他在
board.c文件中被定时调用。
- @note None
- @param None
- @retval None
*/
void soft_timer_tick(void)
{
for (soft_timer_type timer = SOFT_TIMER_0; timer < SOFT_TIMER_MAX; ++timer)
{
if (++timers[timer].counter >= timers[timer].timeout)
{
timers[timer].is_timeout = 1;
if (timers[timer].is_repeat)
{
timers[timer].counter = 0;
}
}
}
}
/**
- @brief 在进行软件定时器数值修改时关闭全局中断来保护变量
- @note None
- @param None
- @retval None
*/
static void soft_timer_interrupt_disable(void)
{
__disable_irq(); // 关闭全局中断
}
/**
- @brief 修改完对应软件定时器变量后恢复全局中段
- @note None
- @param None
- @retval None
*/
static void soft_timer_interrupt_enable(void)
{
__enable_irq(); // 开启全局中断
}
soft_timer.h
#ifndef __SOFT_TIMER_H__
#define __SOFT_TIMER_H__
#include "board.h"
// 定义软件定时器的枚举类型
typedef enum
{
SOFT_TIMER_0,
SOFT_TIMER_1,
SOFT_TIMER_2,
SOFT_TIMER_3,
SOFT_TIMER_4,
SOFT_TIMER_5,
SOFT_TIMER_6,
SOFT_TIMER_7,
SOFT_TIMER_8,
SOFT_TIMER_9,
SOFT_TIMER_MAX // 定时器的最大数量
} soft_timer_type;
// 定义软件定时器的结构体
typedef struct
{
volatile uint32_t counter; // 计数器
volatile uint32_t timeout; // 超时时间
volatile uint8_t is_timeout; // 超时标志
volatile uint8_t is_repeat; // 是否重复计数标志(为1是重复定时器)
} software_timer;
void soft_timer_single_init(soft_timer_type timer, uint32_t timeout);
void soft_timer_repeat_init(soft_timer_type timer, uint32_t timeout);
void soft_timer_start(soft_timer_type timer);
void soft_timer_stop(soft_timer_type timer);
uint8_t soft_timer_is_timeout(soft_timer_type timer);
void soft_timer_reset(soft_timer_type timer);
void soft_timer_tick(void);
static void soft_timer_interrupt_disable(void);
static void soft_timer_interrupt_enable(void);
#endif // __SOFT_TIMER_H__
main.c
#include "board.h"
#include "ringbuffer.h"
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
board_init();
bsp_led_init();
bsp_uart_init();
buzzer_init();
// 初始化四个软件定时器
// 设置SOFT_TIMER_0的超时时间为100ms,重复定时器
soft_timer_repeat_init(SOFT_TIMER_0, 100);
// 设置SOFT_TIMER_1的超时时间为200ms,重复定时器
soft_timer_repeat_init(SOFT_TIMER_1, 200);
// 设置SOFT_TIMER_2的超时时间为300ms,重复定时器
soft_timer_repeat_init(SOFT_TIMER_2, 300);
// 设置SOFT_TIMER_3的超时时间为400ms,重复定时器
soft_timer_repeat_init(SOFT_TIMER_3, 400);
while (1)
{
// 检查SOFT_TIMER_0是否超时
if (soft_timer_is_timeout(SOFT_TIMER_0))
{
bsp_led_toggle(LED1);
}
// 检查SOFT_TIMER_0是否超时
if (soft_timer_is_timeout(SOFT_TIMER_1))
{
bsp_led_toggle(LED2);
}
// 检查SOFT_TIMER_0是否超时
if (soft_timer_is_timeout(SOFT_TIMER_2))
{
bsp_led_toggle(LED3);
}
// 检查SOFT_TIMER_0是否超时
if (soft_timer_is_timeout(SOFT_TIMER_3))
{
bsp_led_toggle(LED4);
}
}
}
systick.c
#include <stdint.h>
#include <systick.h>
static __IO uint32_t g_system_tick = 0;
void systick_config(void)
{
/* setup systick timer for 1000Hz interrupts */
if(SysTick_Config(SystemCoreClock / 1000U)) {
/* capture error */
while(1) {
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void)
{
g_system_tick ++;
soft_timer_tick();
}
uint32_t get_system_tick(void)
{
return g_system_tick;
}
/**
* This function will initial GD32 systick.
*/
void systick_init(void)
{
/* NVIC Configuration */
#define NVIC_VTOR_MASK 0x3FFFFF80
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x10000000 */
SCB->VTOR = (0x10000000 & NVIC_VTOR_MASK);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
SCB->VTOR = (0x08000000 & NVIC_VTOR_MASK);
#endif
systick_config();
}
/**
- @brief 用内核的 systick 实现的微妙延时
- @note None
- @param _us:要延时的us数
- @retval None
*/
void delay_us(uint32_t _us)
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
// 计算需要的时钟数 = 延迟微秒数 * 每微秒的时钟数
// 后面的80是补偿值,因为语句运行也需要时间。
// 补偿值是GD32F470在240Mhz运行条件下用逻辑分析仪测出来的。
ticks = _us * (SystemCoreClock / 1000000) - 80;
// 获取当前的SysTick值
told = SysTick->VAL;
while (1)
{
// 重复刷新获取当前的SysTick值
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
tcnt += told - tnow;
else
tcnt += SysTick->LOAD - tnow + told;
told = tnow;
// 如果达到了需要的时钟数,就退出循环
if (tcnt >= ticks)
break;
}
}
}
systick.h
#ifndef __SYSTICK_H__
#define __SYSTICK_H__
#include "gd32f4xx.h"
#include "stdint.h"
#include "stdio.h"
#include "gd32f4xx_libopt.h"
#include "gd32f4xx_exti.h"
#include "soft_timer.h"
void systick_init(void);
uint32_t get_system_tick(void);
void delay_us(uint32_t _us);
#endif
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/overwizard/article/details/142709280
|