CH582使用MultiTimer软件定时器

参考:

MultiTimer

MultiTimer v2 重构版本 | 一款可无限扩展的软件定时器

感谢开源项目和其他作者的分享,本文为新手CH582F裸机移植MultiTimer(一个软件定时器扩展模块)的过程记录。

0. MultiTimer

MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。

1. 新建工程

添加MultiTimer源码到新工程中,并添加头文件路径。

在这里插入图片描述

2. 使用MultiTimer

  1. 配置系统时间基准接口,安装定时器驱动;
uint64_t PlatformTicksGetFunc(void)
{
    /* Platform implementation */
}

MultiTimerInstall(PlatformTicksGetFunc);

这里把SysTick设置为了1ms中断一次,将变量tick_1ms_cnt++,实现了MultiTimer的时间基准接口:

// tick_1ms_cnt在SysTick_Handler()中1ms +1
volatile uint64_t tick_1ms_cnt = 0;

/**
 * @description: 配置MultiTimer时间基准接口,以SysTick(1ms)为基础
 * @return {uint64_t}
 */
uint64_t PlatformTicksGetFunc(void)
{
    /* Platform implementation */
    return tick_1ms_cnt;
}

// SysTick中断函数
__INTERRUPT
__HIGH_CODE
void SysTick_Handler()
{
    SysTick->SR = 0;    // 清除中断标志
    tick_1ms_cnt++;
}

注意!

  1. 定时器的时钟频率直接影响定时器的精确度,尽可能采用1ms/5ms/10ms这几个精度较高的tick;

  2. 定时器的回调函数内不应执行耗时操作,否则可能因占用过长的时间,导致其他定时器无法正常超时;

  3. 由于定时器的回调函数是在 MultiTimerYield 内执行的,需要注意栈空间的使用不能过大,否则可能会导致栈溢出。

mian.c

这里我创建了两个Timer对象,Timer1每1s循环触发一次,Timer2在初始化后的第3s时执行一次,并打印出字符串。

定时器循环触发只需要在对应的超时回调函数中,重启自己就可以了。

/*
 * @Author       : stark1898y gg1658608470@gmail.com
 * @Date         : 2022-11-26 15:04:43
 * @LastEditors  : stark1898y gg1658608470@gmail.com
 * @LastEditTime : 2022-11-26 17:15:53
 * @FilePath     : \CH582F_MultiTimer\src\Main.c
 * @Description  : CH582F_MultiTimer基于SysTick
 *
 * Copyright (c) 2022 by stark1898y gg1658608470@gmail.com, All Rights Reserved.
 */

#include "CH58x_common.h"
#include "MultiTimer.h"

// 设定嘀嗒时间 1 ms
#define SYSTICK_INTERVAL (1)

uint8_t TxBuff[] = "This is a tx exam\r\n";
uint8_t RxBuff[100];
uint8_t trigB;

// tick_1ms_cnt在SysTick_Handler()中1ms +1
volatile uint64_t tick_1ms_cnt = 0;

uint8_t timer1_flag = 0;

// 实例化MultiTimer定时器对象
MultiTimer timer1;
MultiTimer timer2;

/**
 * @description: 配置MultiTimer时间基准接口,以SysTick(1ms)为基础
 * @return {uint64_t}
 */
uint64_t PlatformTicksGetFunc(void)
{
    /* Platform implementation */
    return tick_1ms_cnt;
}

/**
 * @description: MultiTimer1的回调函数,1000ms循环触发
 * @param {MultiTimer*} timer
 * @param {void*} user_data
 * @return {void}
 */
void Timer1_Callback(MultiTimer* timer, void* user_data)
{
    timer1_flag = 1;
//    PRINT("MultiTimer1_Callback\r\n");
    // 定时器的回调函数内不应执行耗时操作,否则可能因占用过长的时间,导致其他定时器无法正常超时;

    // 重启该定时器,实现1000ms周期的循环触发
    MultiTimerStart(&timer1, 1000, Timer1_Callback, NULL);
}

/**
 * @description: Timer2的回调函数,打印出来user_data的字符串
 * @param {MultiTimer*} timer
 * @param {void*} user_data  char*
 * @return {*}
 */
void Timer2_Callback(MultiTimer* timer, void* user_data)
{
    PRINT("MultiTimer2_Callback! user_data: %s\r\n", (char*) user_data);
}

/*********************************************************************
 * @fn      main
 *
 * @brief   主函数
 *
 * @return  none
 */
int main()
{
    SetSysClock(CLK_SOURCE_PLL_60MHz);

    //  自动重新加载计数值,计数时钟60M,以1ms为例,参数是60000
    SysTick_Config( GetSysClock() / 1000 * SYSTICK_INTERVAL);  //设定嘀嗒时间1ms

    // 安装定时器驱动
    MultiTimerInstall(PlatformTicksGetFunc);

    /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();

 // 中断方式:接收数据后发送出去
    UART1_ByteTrigCfg(UART_7BYTE_TRIG);
    trigB = 7;
    UART1_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
    PFIC_EnableIRQ(UART1_IRQn);

    PRINT("GetSysClock: %d\n", GetSysClock());
    PRINT("PlatformTicksGetFunc: %d\n", PlatformTicksGetFunc());

    // 设置定时时间1000ms,超时回调处理函数, 用户上下指针,启动定时器;
    MultiTimerStart(&timer1, 1000, Timer1_Callback, NULL);
    MultiTimerStart(&timer2, 5000, Timer2_Callback, "Timer2_Callback 5000ms once!");

    while(1)
    {
        if(timer1_flag)
        {
            timer1_flag = 0;
            PRINT("MultiTimer1_Callback (1000ms)\r\n");
        }

        // 在主循环中调用Timer对象处理函数,处理函数会判断链表上的每个定时器是否超时,如果超过,则拉起注册的回调函数
        MultiTimerYield();
    }
}

// SysTick中断函数
__INTERRUPT
__HIGH_CODE
void SysTick_Handler()
{
    SysTick->SR = 0;    // 清除中断标志
    tick_1ms_cnt++;
}

/*********************************************************************
 * @fn      UART1_IRQHandler
 *
 * @brief   UART1中断函数
 *
 * @return  none
 */
__INTERRUPT
__HIGH_CODE
void UART1_IRQHandler(void)
{
    volatile uint8_t i;

    switch(UART1_GetITFlag())
    {
        case UART_II_LINE_STAT: // 线路状态错误
        {
//            UART1_GetLinSTA();
            break;
        }

        case UART_II_RECV_RDY: // 数据达到设置触发点
            for(i = 0; i != trigB; i++)
            {
                RxBuff[i] = UART1_RecvByte();
                UART1_SendByte(RxBuff[i]);
            }
            break;

        case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成
            i = UART1_RecvString(RxBuff);
            UART1_SendString(RxBuff, i);
            break;

        case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
            break;

        case UART_II_MODEM_CHG: // 只支持串口0
            break;

        default:
            break;
    }
}

测试效果如下:

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用和引用中的内容,CH582开发板中使用定时器是TIM2,并且推荐使用systick定时器来进行精确的延时。所以,CH582定时器延时函数的使用步骤如下: 1. 配置定时器和延时函数:首先需要配置定时器(可以是基本定时器,也可以是TIM2)和串口的配置,同时还需要配置延时函数(推荐使用systick定时器)来实现精确的延时功能。 2. 编写程序:在程序中定义两个IO口,将其连接到Trig引脚上,用于触发定时器。然后,通过调用定时器延时函数,设置需要延时的时间,然后执行延时操作。 需要注意的是,具体的定时器延时函数的编写可能会因为不同的开发板和开发环境而有所不同。因此,在使用定时器延时函数之前,建议查阅开发板的相关文档和资料,以了解具体的函数接口和使用方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [CH582使用MultiTimer软件定时器](https://blog.csdn.net/gg1658608470/article/details/128054432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [STM32单片机 关于超声波模块的学习(1)](https://download.csdn.net/download/weixin_38590520/14032857)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值