自动装载寄存器 (TIMx_ARR)、预分频器寄存器(TIMx_PSC)解析

本文解析了STM32定时器中自动重装载寄存器的作用,如何确保计数精度,并介绍了预分频器的原理及在定时器频率调整中的应用。探讨了预分频器的工作机制、分频系数设置与更新事件触发,以及为何需要影子寄存器来实现精确计时和同步功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个自动重装载寄存器(TIMx_ARR),他的作用是什么,我想从名字的角度去分析,为什么叫自动重装载寄存器那?我认为,这是因为这个寄存器里存储了CNT计数器的值,CNT随着时钟精确的计数,向上,向下,或者双向,那么例如是向下计数,当计数到0后,这时CNT寄存器里是0,从哪里再重新倒数那?怎么办,难道产生一事件,人为的从新给个数值,重新倒数.那得多费劲,怎么办那就重新装载原先的那个值呗,而这个值放在另一个寄存器中,因为这个值是重新装载时需要的值,也就叫这个寄存器为自动重装载寄存器,自动就是不用人为去再给啊?而这个寄存器还有个影子,什么是影子就是和我一样的家伙,为什么要有个影子寄存器,玩单片机的必须要有个概念,就是精准,因为单片机都可以是us级别的,它都那么精准了,而你却没有那么精准的概念,你就操纵不好它,发挥不了他的潜力.影子寄存器就是为了精准,假如向上计数,你想想,计数器正在计数,一直都在朝着自动重装载计数器的值去努力,正在计着那,突然你改了这个值,改小了,我发现我超过去了,怎么办?或者改大了,我继续增大的话,那我这次计数算什么?所以要自动重装载计数器的值不能随意改?,可以在计数到原来的自动重装载计数器值的时候,再更改,这样更准确.当然不求准确的话,也可直接就给值,这就是影子寄存器的作用,它的本尊,可以被用户什么时候修改都行,,可是这个影子可以根据需要时再修改,这就是影子的作用,为的就是精确,当然还有一种功能就是同步.stm32中有很多影子寄存器,比如还有预分频器中也有,同理分频不是你什么时候想分就分的,你得等它完成一次计数后再分吧。

 在STM32的定时器中,预分频器(Prescaler-PSC)用来将定时器时钟源进行分频输出。预分频器的值由寄存器TIMx_PSC设定,是一个16位正整数值。在STM32系统中,定时器的时钟源为内部时钟时,其频率一般都比较高,以STM32F103的TIM1为例,其总线时钟最大为72MHz,体现在16位的定时器上的效果就是从0计数到65535上溢只需要0.9毫秒。如果我们需要更长时间的定时间隔,那么就需要预分频器对时钟进行分频处理,以降低定时器时钟(CK_CNT)的频率。除此之外,也可以通过配置预分频器,来获取想要的定时器时钟频率。依然以上边的TIM1为例,如果我们想获取一个精确的1ms中断,如果不分频,72MHz的时钟对应每周期1/72us,十分不利于计算。这时候使用预分频器将其72分频后为1MHz,每周期1us,1000个计时周期即为1ms,这样既便于计算,定时也更加精确。预分频器的工作的工作原理是,定时器时钟源每tick一次,预分频器计数器值+1,直到达到预分频器的设定值,然后再tick一次后计数器归零,同时,CNT计数器值+1。由此可以看出,因为达到最大值后还要再tick一次才归零,所以定时器时钟频率应该为Fosc/(PSC+ 1)。其中Fosc是定时器的时钟源。比如想对时钟源进行72分频,那么预分频器的值就应该设置为71。预分频器值寄存器TIMx_PSC存在影子寄存器(官方翻译为缓冲功能),所以在定时器启动后更改TIMx_PSC的值并不会立即影响当前定时器的时钟频率。要等到下一个更新事件(UEV)发生时才会生效。比如下边这张图就体现了将分频系数由1修改为2(即TIMx_PSC由0更改为1)时整个定时器的时序图。

更新事件(UEV)则由TIMx_CR1寄存器中的UDIS位控制,在启用时,会通过以下两种方式触发 :

  • 计数器上溢
  • 手动将 TIMx_EGR 寄存器中的UG 位置 1

与尔分享,有错误请请指正!

#include "./BSP/TIM/gtim.h" TIM_HandleTypeDef g_timx_pwm_chy_handle; /* 定时x句柄 */ void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc) { TIM_OC_InitTypeDef timx_oc_pwm_chy = {0}; /* 定时PWM输出配置 */ g_timx_pwm_chy_handle.Instance = GTIM_TIMX_PWM; /* 定时 */ g_timx_pwm_chy_handle.Init.Prescaler = psc; /* 定时分频 */ g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */ g_timx_pwm_chy_handle.Init.Period = arr; /* 自动装载值 */ HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle); /* 初始化PWM */ timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1; /* 模式选择PWM1 */ timx_oc_pwm_chy.Pulse = 0; /* 设置比较值,此值用来确定占空比 */ timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_HIGH; /* 输出比较极性为低 */ HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, GTIM_TIMX_PWM_CHY); /* 配置TIMx通道y */ HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY); /* 开启对应PWM通道 */ } /** * @brief 定时底层驱动,时钟使能,引脚配置 此函数会被HAL_TIM_PWM_Init()调用 * @param htim:定时句柄 * @retval 无 */ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { if (htim->Instance == GTIM_TIMX_PWM) { GPIO_InitTypeDef gpio_init_struct; GTIM_TIMX_PWM_CHY_GPIO_CLK_ENABLE(); /* 开启通道y的CPIO时钟 */ GTIM_TIMX_PWM_CHY_CLK_ENABLE(); gpio_init_struct.Pin = GTIM_TIMX_PWM_CHY_GPIO_PIN; /* 通道y的CPIO口 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推完输出 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ HAL_GPIO_Init(GTIM_TIMX_PWM_CHY_GPIO_PORT, &gpio_init_struct); } } gtim_timx_pwm_chy_init(500 - 1, 72 - 1); 现在是这样配置的,请你
最新发布
03-30
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值