打印
[研电赛技术支持]

多路软件定时器(以GD32F470ZGT6为例)

[复制链接]
957|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-10-8 17:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
多路软件定时器(以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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1899

主题

15571

帖子

11

粉丝