当前位置: 首页 > news >正文

3 STM32单片机-delay延时驱动

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 1 工程目录
  • 2 软件编写
    • 2.1 main.c
    • 2.2 board_config
      • 2.2.1 board_config.c
      • 2.2.2 board_config.h
    • 2.3 delay
      • 2.3.1 delay.c
      • 2.3.2 delay.h
    • 2.4 led_driver
      • 2.4.1 led_driver.c
      • 2.4.2 led_driver.h
  • 3 延时验证
  • 总结


前言

在做单片机项目时,延时是经常需要使用到的,在单片机中,有两种定时器,一种是systick定时器,一种是TIM定时器。在这里推荐使用TIM定时器作为系统延时,一方面是systick在RTOS操作系统中默认作为时基了。还有一方面是TIM更加稳定。
在大项目中,TIM2(或其他通用外设定时器)比 SysTick 更适合实现稳定的系统延时,核心原因是:
资源隔离:独立于内核和 RTOS,避免与系统核心功能(如任务调度)冲突;
灵活适配:支持长延时、多场景定时,时钟源选择多样,抗干扰能力强;
可靠兼容:中断机制完善,优先级可控,适配复杂系统的中断协同需求。

基于以上原因,本文使用TIM作为延时函数。
为了将来不更新延时驱动文件,我这里还是封装一下,将来只需要更改板子文件就行了,不需要再次修改延时驱动文件。


1 工程目录

在这里插入图片描述

2 软件编写

2.1 main.c

#include "board_config.h"/************************************************systick 定时器驱动实验现象:LED1闪烁。淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************//************************************* 宏定义 *******************************************************//*********************************** 局部函数 *******************************************************//*
************************************************************
*	函数名称:	main
*
*	函数功能:	
*
*	入口参数:	无
*
*	返回参数:	0
*
*	说明:
************************************************************
*/
int main(void)
{// 初始化所有外设BOARD_InitAll();while (1) {// 闪烁LED1LED_Toggle(&BOARD_LED3);DelayMs(500);}
}

2.2 board_config

2.2.1 board_config.c

#include "board_config.h"/************************************************淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************/// 定义LED对象
LED_TypeDef BOARD_LED1;
LED_TypeDef BOARD_LED2;
LED_TypeDef BOARD_LED3;// 定义蜂鸣器对象
Beep_TypeDef BOARD_BEEP;void BOARD_InitLEDs(void) {// 初始化LED1 (PB0)LED_Init(&BOARD_LED1, GPIOC, GPIO_Pin_0);// 初始化LED2 (PB1)LED_Init(&BOARD_LED2, GPIOB, GPIO_Pin_1);
}void BOARD_InitBeep(void) {// 初始化蜂鸣器 (PB8)Beep_Init(&BOARD_BEEP, GPIOB, GPIO_Pin_8);
}void BOARD_InitDelay(uint8_t timer) {// 初始化延时模块,可选择TIM2/TIM3等Delay_Init(timer);
}void BOARD_InitAll(void) {// 初始化所有外设,使用TIM2作为延时定时器BOARD_InitLEDs();BOARD_InitBeep();BOARD_InitDelay(1);
}    

2.2.2 board_config.h

#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H#include "led_driver.h"
#include "beep_driver.h"
#include "delay.h"/************************************************淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************/// 导出LED对象供外部使用
extern LED_TypeDef BOARD_LED1;
extern LED_TypeDef BOARD_LED2;
extern LED_TypeDef BOARD_LED3;// 导出蜂鸣器对象供外部使用
extern Beep_TypeDef BOARD_BEEP;// 板子初始化函数
void BOARD_InitAll(void);
void BOARD_InitLEDs(void);
void BOARD_InitBeep(void);
void BOARD_InitDelay(uint8_t timer);#endif /* BOARD_CONFIG_H */    

2.3 delay

2.3.1 delay.c

#include "delay.h"/************************************************淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************//** 系统支持的所有定时器配置表 */
const Delay_TimerConfigTypeDef TimerConfigTable[] = {{TIM1,   RCC_APB2Periph_TIM1,   RCC_APB2Periph_TIM1,   RCC_APB2PeriphClockCmd},{TIM2,   RCC_APB1Periph_TIM2,   RCC_APB1Periph_TIM2,   RCC_APB1PeriphClockCmd},{TIM3,   RCC_APB1Periph_TIM3,   RCC_APB1Periph_TIM3,   RCC_APB1PeriphClockCmd},{TIM4,   RCC_APB1Periph_TIM4,   RCC_APB1Periph_TIM4,   RCC_APB1PeriphClockCmd},{TIM5,   RCC_APB1Periph_TIM5,   RCC_APB1Periph_TIM5,   RCC_APB1PeriphClockCmd},{TIM6,   RCC_APB1Periph_TIM6,   RCC_APB1Periph_TIM6,   RCC_APB1PeriphClockCmd},{TIM7,   RCC_APB1Periph_TIM7,   RCC_APB1Periph_TIM7,   RCC_APB1PeriphClockCmd},{TIM8,   RCC_APB2Periph_TIM8,   RCC_APB2Periph_TIM8,   RCC_APB2PeriphClockCmd},{TIM9,   RCC_APB2Periph_TIM9,   RCC_APB2Periph_TIM9,   RCC_APB2PeriphClockCmd},{TIM10,  RCC_APB2Periph_TIM10,  RCC_APB2Periph_TIM10,  RCC_APB2PeriphClockCmd},{TIM11,  RCC_APB2Periph_TIM11,  RCC_APB2Periph_TIM11,  RCC_APB2PeriphClockCmd},{TIM12,  RCC_APB1Periph_TIM12,  RCC_APB1Periph_TIM12,  RCC_APB1PeriphClockCmd},{TIM13,  RCC_APB1Periph_TIM13,  RCC_APB1Periph_TIM13,  RCC_APB1PeriphClockCmd},{TIM14,  RCC_APB1Periph_TIM14,  RCC_APB1Periph_TIM14,  RCC_APB1PeriphClockCmd},
};/** 定时器配置表大小 */
const uint8_t TimerConfigTableSize = sizeof(TimerConfigTable) / sizeof(TimerConfigTable[0]);/** 当前使用的定时器索引 */
static uint8_t currentTimerIndex = 0;/*** @brief  初始化定时器,用于延时功能* @param  timerIndex: 定时器在配置表中的索引* @retval 无*/
void Delay_Init(uint8_t timerIndex)
{if (timerIndex >= TimerConfigTableSize) {// 索引超出范围,使用默认定时器timerIndex = 0;}currentTimerIndex = timerIndex;const Delay_TimerConfigTypeDef* config = &TimerConfigTable[timerIndex];// 使能定时器时钟config->CLKCmd(config->TIMx_CLK, ENABLE);// 停止定时器TIM_Cmd(config->TIMx, DISABLE);// 配置定时器为向上计数模式TIM_InternalClockConfig(config->TIMx);TIM_CounterModeConfig(config->TIMx, TIM_CounterMode_Up);// 设置 PSC 为 71,使计数器时钟为 1MHz (72MHz / 72 = 1MHz)TIM_PrescalerConfig(config->TIMx, 71, TIM_PSCReloadMode_Immediate);// 清除更新标志位TIM_ClearFlag(config->TIMx, TIM_FLAG_Update);
}/*** @brief  微秒级延时函数* @param  us: 延时的微秒数,范围 0 - 65535* @retval 无*/
void DelayUs(uint16_t us)
{if (us == 0) return;const Delay_TimerConfigTypeDef* config = &TimerConfigTable[currentTimerIndex];// 设置自动重载值TIM_SetAutoreload(config->TIMx, us);// 清零计数器TIM_SetCounter(config->TIMx, 0);// 清除更新标志位TIM_ClearFlag(config->TIMx, TIM_FLAG_Update);// 启动定时器TIM_Cmd(config->TIMx, ENABLE);// 等待更新标志位被置位while (!TIM_GetFlagStatus(config->TIMx, TIM_FLAG_Update));// 停止定时器TIM_Cmd(config->TIMx, DISABLE);// 清除更新标志位TIM_ClearFlag(config->TIMx, TIM_FLAG_Update);
}/*** @brief  毫秒级延时函数* @param  ms: 延时的毫秒数* @retval 无*/
void DelayMs(uint16_t ms)
{for (uint16_t i = 0; i < ms; i++){DelayUs(1000);  // 循环调用 1000 微秒延时实现 1 毫秒延时}
}/*** @brief  获取当前使用的定时器索引* @retval 当前使用的定时器在配置表中的索引*/
uint8_t Delay_GetCurrentTimerIndex(void)
{return currentTimerIndex;
}

2.3.2 delay.h

#ifndef DELAY_H
#define DELAY_H#include "system_config.h"/************************************************淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************//** 定时器配置结构体 */
typedef struct {TIM_TypeDef* TIMx;              // 定时器指针uint32_t TIMx_CLK;              // 定时器时钟uint32_t APBxPeriph_CLKCmd;     // 时钟使能函数参数void (*CLKCmd)(uint32_t, FunctionalState); // 时钟使能函数指针
} Delay_TimerConfigTypeDef;/** 系统支持的所有定时器配置表 */
extern const Delay_TimerConfigTypeDef TimerConfigTable[];
extern const uint8_t TimerConfigTableSize;/** 延时函数初始化和操作 */
void Delay_Init(uint8_t timerIndex);
void DelayUs(uint16_t us);
void DelayMs(uint16_t ms);/** 获取当前使用的定时器索引 */
uint8_t Delay_GetCurrentTimerIndex(void);#endif /* DELAY_H */   

2.4 led_driver

2.4.1 led_driver.c

#include "led_driver.h"/************************************************LED灯驱动淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************//*** @brief  初始化LED* @param  led: LED结构体指针* @param  GPIOx: GPIO端口* @param  GPIO_Pin: GPIO引脚* @retval 无*/
void LED_Init(LED_TypeDef* led, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {GPIO_InitTypeDef GPIO_InitStructure;uint32_t RCC_APB2Periph_GPIOx = 0;// 根据GPIO端口确定RCC时钟if (GPIOx == GPIOA) {RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOA;} else if (GPIOx == GPIOB) {RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOB;} else if (GPIOx == GPIOC) {RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOC;} else if (GPIOx == GPIOD) {RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOD;} else if (GPIOx == GPIOE) {RCC_APB2Periph_GPIOx = RCC_APB2Periph_GPIOE;}// 使能GPIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);// 配置GPIO为推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOx, &GPIO_InitStructure);// 初始化LED结构体led->GPIOx = GPIOx;led->GPIO_Pin = GPIO_Pin;led->state = LED_OFF;// 默认关闭LEDGPIO_SetBits(GPIOx, GPIO_Pin);
}/*** @brief  打开LED* @param  led: LED结构体指针* @retval 无*/
void LED_On(LED_TypeDef* led) {GPIO_ResetBits(led->GPIOx, led->GPIO_Pin);led->state = LED_ON;
}/*** @brief  关闭LED* @param  led: LED结构体指针* @retval 无*/
void LED_Off(LED_TypeDef* led) {GPIO_SetBits(led->GPIOx, led->GPIO_Pin);led->state = LED_OFF;
}/*** @brief  切换LED状态* @param  led: LED结构体指针* @retval 无*/
void LED_Toggle(LED_TypeDef* led) {if (led->state == LED_ON) {LED_Off(led);} else {LED_On(led);}
}/*** @brief  获取LED状态* @param  led: LED结构体指针* @retval LED状态*/
LED_State LED_GetState(LED_TypeDef* led) {return led->state;
}

2.4.2 led_driver.h

#ifndef LED_DRIVER_H
#define LED_DRIVER_H#include "system_config.h"/************************************************LED灯驱动淘宝店铺:https://shop475501589.taobao.com/?spm=pc_detail.29232929/evo365560b447259.shop_block.dshopinfo.5dd97dd6JvMuG3咸鱼店铺:https://www.goofish.com/personal?spm=a21ybx.item.itemHeader.1.c17a3da6hy8k28&userId=3890583014哔哩哔哩:https://space.bilibili.com/482024430?spm_id_from=333.788.upinfo.detail.click作者:胜磊电子
************************************************/// LED状态枚举
typedef enum {LED_OFF = 0,LED_ON = 1
} LED_State;// LED结构体定义
typedef struct {GPIO_TypeDef* GPIOx;       // GPIO端口uint16_t GPIO_Pin;         // GPIO引脚LED_State state;           // LED当前状态
} LED_TypeDef;// 函数声明
void LED_Init(LED_TypeDef* led, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void LED_On(LED_TypeDef* led);
void LED_Off(LED_TypeDef* led);
void LED_Toggle(LED_TypeDef* led);
LED_State LED_GetState(LED_TypeDef* led);#endif /* LED_DRIVER_H */

3 延时验证

延时500ms,使用逻辑分析仪采集到的:
在这里插入图片描述
虽然赶不上systick的精度,但是稳定性是极大的提高了。


总结

通过上面这样设置,就可以使用延时函数进行系统延时了,可以随意使用延时所用的定时器,不会和其他资源冲突。

http://www.dtcms.com/a/271548.html

相关文章:

  • langchain从入门到精通(四十)——函数调用技巧与流程
  • 什么是公链?
  • 如何通过配置gitee实现Claude Code的版本管理
  • huggingface 笔记: Trainer
  • 期权盘位是什么意思?
  • 一级缓存与二级缓存深度剖析:作用域、配置与同步方案全解析
  • Unreal Engine 自动设置图像
  • 基于OpenCV的实时人脸检测系统实现指南 ——Python+Haar级联分类器从环境搭建到完整部署
  • 【PTA数据结构 | C语言版】线性表循环右移
  • AI进化论03:达特茅斯会议——AI的“开宗立派”大会
  • 【王阳明代数讲义】心气微积分西方体系汇流历史考述
  • Agent AI(1):多模态交互智能中的背景和动机
  • 2025快手创作者中心发布视频python实现
  • 各类电子设备镜像格式及文件系统统计
  • ETF期权交割日全攻略
  • Linux的 `test`命令(或等价中括号写法 `[空格expression空格]`)的用法详解. 笔记250709
  • 遍历map(LinkedHashMap)
  • 52 spi接口两笔读写耗时多大的问题
  • AP中的Execution Manager“非报告进程”和“伴随进程”概念解析
  • n8n文本语意识别与问题自动补充工作流的深化及企业级部署
  • 代码随想录Day15:二叉树(平衡二叉树、二叉树的所有路径、左叶子之和、完全二叉树的节点个数——全递归版本)
  • 记忆管理框架MemOS——在时序推理上较OpenAI提升159%
  • python+vue的企业产品订单管理系统
  • pytorch常用API
  • [特殊字符] 突破小样本瓶颈:DataDream——用Stable Diffusion生成高质量分类数据集
  • 认证鉴权技术解析:COOKIE | SESSION | TOKEN | JWT | SSO
  • `fatal: bad config value for ‘color.ui‘`错误解决方案
  • 前端UI逻辑复杂可以用什么设计模式
  • 卫星通信终端天线的5种对星模式之二:功率检测型载波跟踪
  • 在Excel用公式计算周次