单片机延时函数怎么写规范?

[复制链接]
发表于 2025-10-25 14:13:06 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
我们从前在开发产物的时间,肯定会碰到一些延时需求,比如常见的LED闪耀,按键消抖,控制IO口输出时序等等。

别鄙视延时,这个小标题,想做好,以致要思量到步伐架构层面。

在开发板上,大概你用delay死延时,很简朴。

但是有个致命的标题,就是CPU壅闭,须要等延时完,步伐才气往下实验,这种在实际产物大部门情况是不能用的,另有就是这种延时时间精度也不敷,大概你延时500ms,实测550ms~600ms随机跳动。

如果换个主频从12MHz改为24MHz的单片机,全部定时全乱了套,改到你抓狂。

背面工作了,我就通过定时器,以全局变量来计时,然后判定变量值来判定时间,时间精度的标题办理了,但是又陪伴着另一个标题,就是代码可扩展性和可移植性差,换一个项目,要增长新的延时时间,大概换一个单片机,代码又要大改。

本日带你彻底办理这个标题,分享我从前做产物不停在用的定时架构,已经颠末几十个项目批量验证,稳固、可扩展,可移植。

一、架构实现思绪图解
1.1 焦点数据结构体
  1. typedef struct {
  2.     uint16_t Period;        // 定时周期(50μs单位)
  3.     uint16_t CurrentCount;  // 当前计数值
  4.     void (*func)(void);     // 回调函数指针
  5.     TIMER_STATE_TYPEDEF state; // 状态标示
  6. } Stu_TimerTypedef;
  7. volatile Stu_TimerTypedef Stu_Timer[T_SUM]; // T_SUM建议定义8
复制代码

1.2 三层架构计划


二、代码逐行剖析(焦点函数)
2.1 硬件初始化函数
  1. static void hal_timer4Config(void)
  2. {
  3.     // TIM4时钟使能
  4.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  5.    
  6.     TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};
  7.     TIM_TimeBaseStructure.TIM_Period = 50 - 1;  // 50us间隔自动重装载值
  8.     TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/1000000 - 1; // 1MHz时基
  9.     //其它初始化代码
  10. }
复制代码

2.2 定时器管理API
2.2.1 创建定时器
  1. void hal_CreatTimer(TIMER_ID_TYPEDEF id, void (*proc)(void),
  2.                    uint16_t Period, TIMER_STATE_TYPEDEF state)
  3. {
  4.     Stu_Timer[id].state = state;
  5.     Stu_Timer[id].Period = Period;   // 设置周期(50μs*Period)
  6.     Stu_Timer[id].CurrentCount = 0;  // 清空计数
  7.     Stu_Timer[id].func = proc;       // 绑定回调函数
  8. }
复制代码

3.2.2 定时器状态控制
  1. TIMER_RESULT_TYPEDEF hal_CtrlTimerAction(TIMER_ID_TYPEDEF id,
  2.                                        TIMER_STATE_TYPEDEF sta)
  3. {
  4.     if(Stu_Timer[id].func != NULL){
  5.         Stu_Timer[id].state = sta; // 修改运行状态
  6.         return T_SUCCESS;
  7.     }
  8.     return T_FAIL; // 定时器未创建
  9. }
复制代码

3.3 克制处置惩罚焦点
  1. void TIM4_IRQHandler(void)
  2. {
  3.     if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET){
  4.         // 全局中断处理函数
  5.         for(uint8_t i=0; i<T_SUM; i++){
  6.             if(Stu_Timer[i].state == T_STA_START){
  7.                 if(++Stu_Timer[i].CurrentCount >= Stu_Timer[i].Period){
  8.                     Stu_Timer[i].state = T_STA_STOP; // 单次触发模式
  9.                     Stu_Timer[i].func(); // 执行用户回调
  10.                 }
  11.             }
  12.         }
  13.         TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
  14.     }
  15. }
复制代码

三、底子用法示例
3.1 LED闪耀(1Hz)
  1. // 定义LED任务ID
  2. #define LED_TASK_ID 0
  3. // LED回调函数
  4. void LED_Task(void){
  5.     GPIO_WriteBit(GPIOC, GPIO_Pin_13,
  6.                 (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)));
  7. }
  8. int main(void){
  9.     // 硬件初始化
  10.     hal_timerInit();  
  11.     GPIO_Init(GPIOC, GPIO_Pin_13, GPIO_Mode_Out_PP);
  12.    
  13.     // 创建定时器(10000*50μs=500ms)
  14.     hal_CreatTimer(LED_TASK_ID, LED_Task, 10000, T_STA_START);
  15.    
  16.     while(1){
  17.         // 主循环可添加其他任务
  18.         if(需要重启定时器){
  19.             hal_ResetTimer(LED_TASK_ID, T_STA_START);
  20.         }
  21.     }
  22. }
复制代码

3.2 按键消抖(进阶用法)
  1. #define KEY_TASK_ID 1
  2. uint8_t key_state = 0;
  3. void Key_Scan_Task(void){
  4.     static uint16_t press_time = 0;
  5.    
  6.     if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)){
  7.         if(++press_time > 10){ // 50μs*10=0.5ms
  8.             key_state = 1;
  9.         }
  10.     }else{
  11.         press_time = 0;
  12.         key_state = 0;
  13.     }
  14. }
  15. void Init_Key_Scan(void){
  16.     hal_CreatTimer(KEY_TASK_ID, Key_Scan_Task, 10, T_STA_START); // 每0.5ms扫描
  17. }
复制代码
关于这个定时器架构,我在2018年也录了一套比力体系的教程,可滴滴我安排。


以上两种是比力常用了,除了这个,我们无际单片机项目里另有控制单口时序驱动外围芯片的用法,比如语音芯片等等,用起来极其机动。

这种是通过定时器的精准定时,定时使命在定时器克制内里实验,也是有缺点的,如果定时的使命多了,就会影响及时性。

以是,有些定时,不须要要求这么高的,我们一样平常是共同使命的Tick,然后每个使命里设置一个变量,通过递增和递减来延时。



之前有同砚问过我,怎么去验证这个定时器时间准禁绝?

我们在调试延时架构代码的阶段,会通过示波器,共同IO电平翻转去测试,比如10ms翻转一次,看下精度。

近来许多粉丝问我单片机怎么学,我根据本身从业十年履历,累积耗时一个月,经心整理一份「单
片机最佳学习路径+单片机入门到高级教程+工具包」,全部无偿分享给铁粉!!!

除此以外,再含泪分享我压箱底的22个热门开源项目,包罗源码+原理图+PCB+阐明文档,让你敏捷进阶成高手!


教程资料包和具体的学习路径可以看我下面这篇文章的开头。
《单片机入门到高级开挂学习路径(附教程+工具)》
《单片机入门到高级开挂学习路径(附教程+工具)》
《单片机入门到高级开挂学习路径(附教程+工具)》
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表