CH582使用MultiTimer软件定时器

news/2024/12/21 23:35:44/

参考:

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为例,参数是60000SysTick_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: // 只支持串口0break;default:break;}
}

测试效果如下:

在这里插入图片描述


http://www.ppmy.cn/news/896778.html

相关文章

CH582使用EasyLogger

参考: EasyLogger EasyLogger–不一样的打印输出 EasyLogger | 一款轻量级且高性能的日志库(这篇写的挺详细的) 感谢开源项目和其他作者的分享,本文为新手CH582F裸机移植EasyLogger日志库的过程记录。 0.EasyLogger EasyLogger 是…

CH582使用MultiButton

参考: MultiButton MultiButton | 一个小巧简单易用的事件驱动型按键驱动模块 B站视频-第17讲:STM32项目经验分享:MultiButton按键 1/5 感谢开源项目和其他作者的分享,本文为新手CH582F裸机移植MultiButton按键库的过程记录。 0.…

CH582 USB Device CherryUSB

CH582是一款优秀的芯片,它有着极高的性价比,拥有两个USB(HD)和BLE5,本偏文章将介绍如何将CH582的USB移植到一个优秀的开源项目:CherryUSB。 第一步:需要了解CH582的USB外设,我们直接…

582-快速排序算法的思想和性能分析

快速排序算法的思想 下面是一组待排序的序列,我们现在要使用快速排序算法的思想解决 1、我们选取基准数,我们把第一个数字当做基准数 进行元素的调整,对于数组来说,我们要涉及1个范围,用起始下标和末尾下标。 我们用L…

[蓝牙芯片]CH582作为Central连接其他厂芯片Disconnected...Reason:3b解决方案

今天要跟大家分享的是WCH的CH582作为Central连接其他厂芯片peripheral遇到的坑。踩完这个坑,感觉越来越喜欢CH582了。良心的蓝牙芯片,特别是对于我们这些搞电脑游戏外设的开发者来说,真乃国产良“芯”!!! …

D-OJ刷题日记:散列查找实验(闭散列) 题目编号:582

请设计一个整型闭散列表,散列函数为除留余数法,处理冲突时的探查方法为线性探查法,其中散列表的长度、除留余数法的模和关键码的个数由键盘输入,再根据输入由键盘输入所有的关键码。分别对三个待查值在散列表中进行查找&#xff0…

【sgUploadTray】上传托盘自定义组件,可实时查看上传列表进度

【sgUploadTray】上传托盘自定义组件&#xff0c;可实时查看上传列表进度 特性&#xff1a; 可以全屏可以还原尺寸可以最小化可以回到右下角默认位置支持删除队列数据 sgUploadTray源码 <template><div :class"$options.name" :show"show" :size…

库克背刺等等党,iPad新老款全涨价,配件上还想多赚67元

羿阁 衡宇 发自 凹非寺量子位 | 公众号 QbitAI 离离原上谱&#xff0c;库克老贼对iPad全系进行了大涨价&#xff01; 且不论新品&#xff0c;搭载M2芯片的iPad Pro 2022&#xff0c;史无前例6799元起售。 就连在售的产品也应声而涨&#xff01; iPad 9涨价100元&#xff0c;iPa…