ARR是啥
自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以直接传送到影子寄存器,也可以在每次发生更新事件
(UEV) 时传送到影子寄存器,这取决于 TIMx_CR1 寄存器中的自动重载预装载使能位 (ARPE)。当>计数器达到上溢值(或者在递减计数时达到下溢值)并且 TIMx_CR1 寄存器中的 UDIS 位为 0时,将发送更新事件。该更新事件也可由软件产生。
计数器时序图,ARPE=0 时更新事件,未预装载
立刻改变ARR重装载值,计数器从当前值计数到36,而不是原来的FF
计数器时序图,ARPE=1 时更新事件(TIMx_ARR 已预装载)
原来ARR的值F5,现在写入36,但是计数器依旧按照原来的计数到F5,溢出后,然后再重新从0开始计数,直到计数到新的ARR-36。
如果没有预装载,此时ARR的值直接更新,而此时计数器已经是F1,超过了新写入的值36,计数器不是直接从零计数,而是一直加到溢出,再从0重新开始计数到ARR,这就造成了一些问题,计数时间不是你想要的,
ARPE,自动重装载使能,默认0,无预装载
通过下边程序进行更改ARPE
/**
* @brief Enables or disables TIMx peripheral Preload register on ARR.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param NewState: new state of the TIMx peripheral Preload register
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
/* Set the ARR Preload Bit */
TIMx->CR1 |= TIM_CR1_ARPE;
}
else
{
/* Reset the ARR Preload Bit */
TIMx->CR1 &= (uint16_t)~TIM_CR1_ARPE;
}
}
援引网友的一段话
https://blog.csdn.net/qq_46015011/article/details/107108739
预加载寄存器是自动重装载寄存器的“影子”,也就是预加载寄存器是自动重装载寄存器的缓冲器。但是自动重装载寄存器不是用户用程序可以直接进行操作的,用户需要借助于预加载寄存器(缓冲区)才能访问它。
其目的是为了保证自动重装载寄存器在合适的时候被修改,不允许其随便被修改,否则可能导致在切换的时候发生事与愿违的结果。
简单来说:没有预加载寄存器,这次修改的值,立马会被执行。而有了预加载寄存器,这次修改值会等到这次执行完后,才去执行。
总结:
因为定时器的周期都比较短,我们可以通过预加载寄存器配合自动重装载寄存器,来更好的操作定时器,以达到我们期望的效果。
下面的这个解释挺好的:
👀使能预装载的意义在于可以多个通道同时输出时,时序能准确地同步。网上的一段有意义的解释是:设计preload register和shadow register的好处是,所有真正需要起作用的寄存器(shadow register)可以在同一个时间(发生更新事件时)被更新为所对应的preload register的内容,这样可以保证多个通道的操作能够准确地同步。如果没有shadow register,或者preload register和shadow register是直通的,即软件更新preload register时,同时更新了shadow register,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上其它因素(例如中断),多个通道的时序关系有可能是不可预知的。可见如果只是单通道输出,多通道输出时没时序精准的同步更新要求,不使能也可以的。
参考文献是这样说的:自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以直接传送到影子寄存器,也可以在每次发生更新事件 (UEV) 时传送到影子寄存器,这取决于 TIMx_CR1 寄存器中的自动重载预装载使能位 (ARPE)。这里对自动重载寄存器执行写入或读取操作时会访问预装载寄存器我很疑惑,TIMx_ARR应该不是它们对应的预装载寄存器,可能是有三个寄存器的,自动重装载寄存器、预装载寄存器、和真正起作用的影子寄存器。希望得到解答。
我李某人遇到的问题
最近因为这个重装载问题困扰了我好久,我此时只想说:
下边就是我做的一些测试,来查找这个问题,因为这个跳变不是一直出现的,一直测测测,yue了
//#define debug_config_init_c//改变引脚的初始化,上下拉等
//#define debug_config_init_h//引脚输入输出,OD开漏无需配置引脚的输入输出,推挽要配置
//#define debug_stm32f4xx_c//增加d2读取时间,未曾跳变,
//#define debug_stm32f4xx_it_c_two//将d1,2读取顺序对调,D2采用平均值
#define debug_stm32f4xx_it_c_500ms//统一定时5ms,大于转换时间1。17ms
#define debug_tiaobian//捕捉跳变
//#define debug_Priority//增加气压计优先级,还会跳变,不是中断引起的
//#define debug_interruppt//只保留气压计中断,未曾跳变,验证是因为被其他中断打断引起的跳变
#define debug_NACK//读取数据结束,按照手册增加这个非应答信号
//#define debug_filter_D2_1//这几个值均不为零,才更新高度,跳变均是0
#define debug_data_type//char接收了一个超范围的值A0-AE,char最大127,
//#define debug_IIC_WaitAck
#define debug_IIC_communicate//更改IIC时序,降低读取数据的频率,增大延时
初心是定时器中断里不断改变ARR的值,达到一个不同定时时间case的切换,执行不同的命令,可是事与愿违,不到2.5ms,直接到了下一个case,因为ARPE默认是0,假如在到达250这个case之前,计数器已经到了248,你直接给了ARR250,这不直接定时时间直接到下一个case喽,不知哪位师兄写的程序害我,哈哈,本来八百多万的数据直接变成了0,这不导致无人机上跳下窜的,虽然控制有滤波,万一跳变过多,没有滤掉呢,一架架飞机炸裂,那我直接跑路吧,也别毕业了。。。
0x52,0xEE,这两个命令之间本来按照程序有一个2.5ms的延时,可是这里没有起作用,导致我这边数据读取到0
增加这个延时的作用就是给气压计一个转换时间,数据转换完成,我再去读取,这倒好,还没转换完我就去读取,可不就是00000,服了
解决方法一
采用固定的定时时间,不来回切换ARR
统一定时5ms
` TIM_TimeBaseStructure.TIM_Period = 499;
TIM_TimeBaseStructure.TIM_Prescaler = 839;
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
case FLAG_IDLING:
// TIM4_Pri->ARR = 500; // 采用固定的定时时间5ms,不来回切换ARR
time4_phaseflag = FLAG_D2_CONVERTING;
break;
解决方法二
计数器先失能,清零计数器,再使能计数器
TIM4->CR1 &= (uint16_t)~TIM_CR1_CEN;//计数器失能
TIM4->CNT = 0;//清零计数器
TIM4->ARR = 250;
MS5611_SendData(0x52); //Command ConvertD2 (OSR=512)
time4_phaseflag = FLAG_D2_CONVERTING;
TIM4->CR1 |= TIM_CR1_CEN;//计数器使能
解决方法三
采用OPM模式
可参考如下文章来源:https://www.toymoban.com/news/detail-764284.html
https://blog.csdn.net/weixin_44057803/article/details/132767653
文章来源地址https://www.toymoban.com/news/detail-764284.html
到了这里,关于STM32 定时器自动重装载寄存器ARR带来的影响,ARPE0和1区别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!