定时器TIM配置微妙延时函数
文章目录
开胃小菜(BOOT0、BOOT1)
在STM32系列微控制器中,Boot0和Boot1是两个用于 选择启动模式 的引脚。
主要功能是决定芯片启动时加载哪个存储区域的代码
这两个引脚的状态组合决定了微控制器从哪个内存位置开始执行代码,从而影响启动过程和运行的固件。
Boot0
这个引脚通常用于选择启动模式。
例如,在STM32F103RCT6芯片中
如果Boot0引脚被拉高(通常连接到VCC),则微控制器将从Flash存储器启动;
如果Boot0引脚被拉低(通常连接到GND),则将从SRAM启动。
这是一种常见的配置,但具体行为可能会根据不同的STM32系列略有变化,所以最好查阅相应芯片的数据手册以获取准确信息。
Boot1(如果有)
有些STM32芯片可能还有一个Boot1引脚,用于进一步扩展启动模式的选择。
结合Boot0和Boot1的不同电平状态,可以选择从不同的存储介质启动,如系统存储器、用户闪存或其他。
不同STM32芯片上有不同的配置和选项,Boot0和Boot1的功能,需要查看该芯片的参考手册或数据表来确定
三种定时器
stm32f103芯片一般包含了以下类型的定时器:
高级控制定时器(TIM1,TIM8)
STM32F1系列微控制器中功能最强大的定时器,通常用于电机控制等高级应用,支持多达4路的PWM输出、捕获和比较模式等多种功能。高级控制定时器可以实现复杂的波形生成和电机控制策略,如PID控制、死区时间设置等。
通用定时器(TIM2, TIM3, TIM4, TIM5)
通用定时器是最常用的定时器类型,适用于多种用途,可以用于生成脉冲宽度调制(PWM)信号(PWM输出、输入捕获和输出比较)、计数外部事件等。通用定时器通常具有多个通道,每个通道都可以独立地进行配置和使用。
基本定时器(TIM6, TIM7)
基本定时器相对简单,通常用于 简单的计数 或产生基本的 时间延迟 。它们的功能不如通用定时器丰富,但在一些简单的应用场合非常有用。
TIM6配置Delay_us()
采用的是stm32f103芯片,8M外接晶振,所以系统时钟为72MHz。
使用软件stm32cubeode
.IOS 配置如下:
Prescaler-------------------分频系数
Counter Mode------------计数模式(方向)
Counter Period ----------重装载值
auto-reloadpreload------自动重载预载
Prescaler (分频系数)
设置适当的预分频系数,可以调整定时器计数器的时钟频率,从而改变定时器计数的速度。
确保定时器以所需的频率进行计数,这对于生成精确的时间延迟或周期性事件至关重要。
比如说,上面设置的是72分频,已知系统时钟频率是 72 M H z 72MHz 72MHz
所以定时器时钟就是 72 M H z / 72 = 1 M H z 72MHz/72 = 1MHz 72MHz/72=1MHz ,即 定时器每计数一次耗时 1 u s 1us 1us
Counter Mode (计数模式)
在大多数定时器中,计数模式可以是 向上计数 、向下计数 或 双向计数 。
这决定了定时器计数器的计数方向。
选择正确的计数模式对于满足特定应用的需求非常重要。
向上计数:从0开始计数到65535
向下计数:从65535开始计数到0
双向计数:计数器从一个设定的值开始,向上计数到最大值,然后向下计数到最小值,如此循环。
双向计数通常用于需要测量周期性事件或信号的频率和持续时间
Counter Period (重载值)
定时器计数器在达到该值后产生事件(如中断或复位)的周期长度。
设置合适的重载值定义了定时器计数器的周期,这可以用于生成特定的时间间隔或频率。
通俗来讲
向上计数:计数器从0开始计数,计数到65535(重载值),就会触发事件。
向下计数:计数器从65535(重载值)开始计数,计数到0,就会触发事件。
auto-reload preload (自动重载预载)
当设置此功能时,每当计数器达到预设的重载值(65535)时,它会自动重新加载预设值(65535),从而使定时器能够无缝地继续计数。这允许定时器持续运行,无需软件干预,适用于需要连续或周期性操作的应用。
代码
设置分频系数,由于初始化的时候已经设置好了,这里可以不设置了;
设置重装载值,写延时函数的话,
向上计数这一行绝对不能要
向下技术根据实际情况来设置
写定时器中断服务函数也需要
部分博主无脑搬运,工程师们可要仔细辨认
计数值归零,实际上就是将0赋值给计数器的初始值
可以F12跳转到宏定义
/*** @brief Set the TIM Counter Register value on runtime.* @param __HANDLE__ TIM handle.* @param __COUNTER__ specifies the Counter register new value.* @retval None*/
#define __HAL_TIM_SET_COUNTER(__HANDLE__, __COUNTER__) ((__HANDLE__)->Instance->CNT = (__COUNTER__))
实际上就是一个赋值
写成这样也可以
__HAL_TIM_SET_COUNTER(&htim6,0);//把定时器计数值归零
开启定时器,获取计数值,如果计数值达到输入 u s us us 次,则关闭定时器
__HAL_TIM_GET_COUNTER(&htim6) //获取计数值
重要问题
为什么向上计数时 第201行 不能要?
举个例子:
比如我输入的是1000,也就是Timer6_Delay_us(1000);(即us = 1000;)
我们看看这个函数的原型
/*** @brief Set the TIM Autoreload Register value on runtime without calling another time any Init function.* @param __HANDLE__ TIM handle.* @param __AUTORELOAD__ specifies the Counter register new value.* @retval None*/
#define __HAL_TIM_SET_AUTORELOAD(__HANDLE__, __AUTORELOAD__) \do{ \(__HANDLE__)->Instance->ARR = (__AUTORELOAD__); \(__HANDLE__)->Init.Period = (__AUTORELOAD__); \} while(0)
倒数第二行
(__HANDLE__)->Init.Period = (__AUTORELOAD__); \
Period 是不是很眼熟?-------->重装载值!!!
也就是将重装载值设置成了999(1000-1),每次计数到999,就会从0重新开始
也就是计数值最大只能到达999(1000-1)
再看跳出 while 循环的条件
while(1){Count = __HAL_TIM_GET_COUNTER(&htim6);if(Count > us)break;}
这里的计数值 Count 最大值只能到达999(1000-1),而我们输入的 u s us us == 1000;
那么这个循环就无法终止也就是为什么卡死在这的原因
为什么一开始用着也没什么事呀?运气好呗,没什么干扰
简单粗暴的毫秒延时,取别名
PS:定时器中断服务函数
前面说了,如果需要使用定时器中断服务函数,就需要 第201行 或者 提前就设置好重装载值
什么意思呢?
向上计数,从0计数到重装载值,就会自动触发 定时器中断服务函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim == &htim7) //判断是哪个定时器请求的中断 在这个函数里可以if判断多个定时器请求的中断{//触发事件}
}
H A L HAL HAL 库提供了一个回调函数 HAL_TIM_PeriodElapsedCallback
当定时器的周期完成时,这个回调函数会被调用,触发事件。
即计数器的值达到了自动重载寄存器 ARR 的值并发生溢出或更新事件
这个函数通常在定时器的中断服务例程中被调用,允许用户执行一些事件
参数 htim 是一个指向 TIM_HandleTypeDef
结构体的指针,包含了定时器的控制和状态信息。
这个回调函数通常用于处理定时器周期到达时的中断服务例程(ISR)。
┈┈┈┈▕▔╲┈┈┈┈┈┈┈ ┈┈┈┈▕▔╲┈┈┈┈┈┈┈ ┈┈┈┈▕▔╲┈┈┈┈┈┈┈┈
┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈
┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈
▂▂▂▂╱┈┈▕▂▂▂▂▏┈ ▂▂▂▂╱┈┈▕▂▂▂▂▏┈ ▂▂▂▂╱┈┈▕▂▂▂▂▏┈┈
▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈
▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈
▔▔▔▔╲▂▂▕▂▂▂▂▏┈ ▔▔▔▔╲▂▂▕▂▂▂▂▏┈ ▔▔▔▔╲▂▂▕▂▂▂▂▏┈┈