这里的PWM频率调整 没有考虑到ARR取值范围会溢出的问题 比如说你需要设置1000hz 按理来说 ARR应该是79999 但是实际上TIM-ARR是14463 是因为上限是65535之后溢出所导致的 所以我们要对溢出的ARR进行分频处理
// 原始代码的频率计算
uint32_t arr = clk / Frequency - 1;
没有考虑ARR溢出
ARR寄存器是16位,最大值65535
当频率较低时,arr值会超过65535
例如:80MHz/1000Hz = 80000 > 65535
定时器频率计算公式:f = clk/((PSC+1)*(ARR+1))
预分频器实际值 = 寄存器值 + 1
避免多次除法运算引入误差
直接用目标频率反推ARR值更准确
void pwm_set_frequency(int Frequency)
{
// 获取定时器的时钟频率(假设TIM3使用的时钟频率为TIM3_CLK)
uint32_t TIM3_CLK = HAL_RCC_GetPCLK2Freq(); // 例如80MHz, 需要根据实际情况调整
// 初始化变量
float duty = 0;
uint32_t prescaler = 1;
uint32_t arr;
// 计算ARR和预分频器
arr = TIM3_CLK / (Frequency * prescaler) - 1;
// 如果ARR超出范围,调整预分频器
if (arr > 65535)
{
prescaler = (arr + 65535) / 65535;
arr = TIM3_CLK / (Frequency * prescaler) - 1;
}
// 保存原占空比
duty = (float)TIM3->CCR2 / (TIM3->ARR + 1);
// 设置新的预分频值和ARR
__HAL_TIM_SET_PRESCALER(&htim3, prescaler - 1);
TIM3->ARR = arr;
// 保持占空比不变
TIM3->CCR2 = (arr + 1) * duty;
// 更新寄存器
TIM3->EGR = TIM_EGR_UG;
}
-
获取定时器时钟频率:
uint32_t TIM3_CLK = HAL_RCC_GetPCLK2Freq();获取PCLK2的时钟频率。
-
计算
ARR和预分频器:arr = TIM3_CLK / (Frequency * prescaler) - 1;计算ARR值。- 如果
ARR超出范围,调整预分频器prescaler并重新计算ARR。
-
保存原占空比:
duty = (float)TIM3->CCR2 / (TIM3->ARR + 1);计算当前占空比。
-
设置新的预分频值和
ARR:__HAL_TIM_SET_PRESCALER(&htim3, prescaler - 1);设置新的预分频值。TIM3->ARR = arr;设置新的ARR值。
-
保持占空比不变:
TIM3->CCR2 = (arr + 1) * duty;计算新的CCR2值。
-
触发更新事件,刷新寄存器:
TIM3->EGR = TIM_EGR_UG;触发更新事件,使新的ARR和CCR2生效。
可能还是比较难以理解举个例子
假设我们有一个系统使用 80 MHz 的系统时钟,并且我们希望将 TIM3 的 PWM 频率设置为 100 Hz,但初始计算出的 ARR 超过了 65535。
初始计算
TIM3_CLK = 80000000Frequency = 100Hz- 初始
prescaler = 1 arr = 80000000 / (100 * 1) - 1 = 800000 - 1 = 799999(超过了 65535)
调整预分频器
prescaler = (799999 + 65535) / 65535 = 865534 / 65535 ≈ 13.21,取整后得到prescaler = 14- 重新计算
arr:arr = 80000000 / (100 * 14) - 1 = 80000000 / 1400 - 1 = 57142 - 1 = 57141(现在在有效范围内)
设置新的 ARR 和 PSC
__HAL_TIM_SET_PRESCALER(&htim3, 14 - 1);设置预分频器为 13TIM3->ARR = 57141;设置新的ARR值
-
计算新的预分频器:
prescaler = (arr + 65535) / 65535;- 这行代码的作用是确定最小的整数倍数,使得调整后的
ARR值小于或等于 65535
3010

被折叠的 条评论
为什么被折叠?



