stm32高级定时器 pwm占空比怎么改变
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stm32高级定时器 pwm占空比怎么改变相关的知识,希望对你有一定的参考价值。
参考技术A其他配置好后,用这个函数
本回答被提问者和网友采纳使用 STM32 HAL 定时器和调整 PWM 信号的占空比
【中文标题】使用 STM32 HAL 定时器和调整 PWM 信号的占空比【英文标题】:Using STM32 HAL Timer and Adjusting the Duty Cycle of a PWM signal 【发布时间】:2017-09-14 23:26:34 【问题描述】:我使用STM32Cube初始化代码生成器生成了一个初始化的Timer函数。为了生成固定占空比的 PWM 信号,我在 Timer 初始化函数中添加了 HAL_TIM_Base_Start(&htim1); //Starts the TIM Base generation
和 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1)//Starts the PWM signal generation
,如下所示。
/* Private variables ---------------------------------------------------------*/
int pulse_width=0;
/* TIM1 init function */
static void MX_TIM1_Init(void)
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;//we want a max frequency for timer, so we set prescaller to 0
//And our timer will have tick frequency
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 1066;//max value for timer is 16bit = 65535, TIM_Period = timer_tick_frequency / PWM_frequency - 1
//In our case, for 15Khz PWM_frequency, set Period to TIM_Period = 16MHz / 15KHz - 1 = 1066
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)/* to use the Timer to generate a simple time base for TIM1 */
Error_Handler();
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;//the default clock is the internal clock from the APBx, using this function
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)//Initializes the TIM PWM Time Base according to the specified
//parameters in the TIM_HandleTypeDef and create the associated handle.
Error_Handler();
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
Error_Handler();
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
Error_Handler();
//sConfig: TIM PWM configuration structure
//set duty cycle: pulse_length = ((1066 + 1) * duty_cycle) / (100 - 1)
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = pulse_width;/* 50% duty cycle is 538, set to 0 initially*///
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
Error_Handler();
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
Error_Handler();
sBreakDeadTimeConfig.OffStateRunMode = TIM_Os-s-r_ENABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
Error_Handler();
HAL_TIM_MspPostInit(&htim1);//output pin assignment
HAL_TIM_Base_Start(&htim1); //Starts the TIM Base generation
if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK)//Starts the PWM signal generation
/* PWM Generation Error */
Error_Handler();
/* Start channel 2 */
if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2) != HAL_OK)
/* PWM Generation Error */
Error_Handler();
当我硬编码正确的值以替换sConfigOC.Pulse = pulse_width
中的pulse_width
值时,这足以以上述 cmets 中指定的固定占空比运行 PWM。
在另一个函数中,我有一个算法可以更新pulse_width
全局变量。该函数被调用:adjust_PWM();
。该算法计算从 ADC 测量的值并存储为全局变量。该函数称为:Data_Update();
。在main()
,在所有函数都初始化之后。我没完没了地调用这三个函数
Data_Update();
adjust_PWM();
MX_TIM1_Init();
我尝试过,并在示波器上获得了奇怪的波形,但这可能是因为 ADC 引脚浮动,导致浮动测量干扰算法的占空比。连续调用定时器的初始化也会中断 PWM 信号。有没有更好的方法在运行代码时更改占空比而不使用全局变量,或者每次我想更新占空比时都不初始化计时器。任何链接将不胜感激。
【问题讨论】:
最好的方法是摆脱 ST "HAL" 膨胀软件并直接对寄存器进行编程。这实际上节省了一半的代码。 @Olaf 直接对寄存器进行编程?你能为更注重硬件的人详细说明一下吗? 阅读参考手册(无论如何你必须),只包括来自ST的CMSIS和寄存器定义头文件,并直接写入/读取外围模块的寄存器。作为一个硬件导向的人,这也应该更适合你。这样您就不必摆弄这个过时的软件和硬件,而只需摆弄硬件。 我完全同意@Olaf 关于删除库代码的声明。充其量是一团糟,最坏的情况是一种责任。根据数据表工作并自行设置外围设备,您就知道发生了什么。如果它是一个平台,你将使用很多东西,你最终还是会拥有自己的 HAL 库。 您是否尝试过使用新的pulse_width
值调用 HAL_TIM_PWM_ConfigChannel() 而不是重复调用 MX_TIM1_Init()?
【参考方案1】:
编写您自己的函数来更新控制占空比的寄存器。您必须手动更新相应的 CCRx 寄存器(x 是您正在使用的 PWM 通道,在您的情况下为 CCR1)。
ARR 寄存器是您在根据所需占空比计算 CCR 寄存器的新值时将引用的寄存器。
void adjust_PWM_DC(TIM_HandleTypeDef* const pwmHandle, const float DC)
assert(pwmHandle != NULL);
assert((DC >= 0.0F) && (DC <= 100.0F));
/* The duty cycle value is a percentage of the reload register value (ARR). Rounding is used.*/
uint32_t newRegVal = (uint32_t)roundf((float32_t)(pwmHandle->Instance->ARR) * (DC * 0.01F));
/*In case of the DC being calculated as higher than the reload register, cap it to the reload register*/
if(newRegVal > pwmHandle->Instance->ARR)
newRegVal = pwmHandle->Instance->ARR);
/*Assign the new DC count to the capture compare register.*/
pwmHandle->Instance->CCR1 = (uint32_t)(roundf(newRegVal)); /*Change CCR1 to appropriate channel, or pass it in with function.*/
【讨论】:
虽然 M4F 和 M7 支持浮点,但它们仍然是嵌入式代码的负担。不要使用它们,至少不要在这样的代码中。通常只有***应用程序代码应该处理浮点数并且只有 iff 是必需的.. @Olaf 在某些情况下浮点是危险的,应该避免。尽管在这段说明性代码中它们更容易理解并很好地服务于它们的目的。如果软浮点是一个问题,那么 [0;100] DC 可以映射到 [0;0xFFFFU] 或定点等。虽然这将比硬件浮点慢,后者也保持更高的精度。 浮点处理的速度不是唯一的问题,我没有谈论危险(这是两个问题)。这不是辅导的地方,但有经验的嵌入式程序员会在合理的情况下避免浮动,这通常是问题。 另一个问题是 RAM/堆栈空间。对于 CM4F,FPU 寄存器,例如需要 64 个额外字节的堆栈空间。对于小型设备上的高度并行化 MT 代码(出于成本原因首选),此内存可能是一个主要问题。但这也是额外时钟的时间问题。正如我所写:嵌入式中幸灾乐祸的大多数用法都是由没有经验或懒惰的程序员使用的。恕我直言,但您在此类平台上有多少经验? STM32F7 绝对不是其中之一(尽管 FPU 寄存器占用 128 个字节 (double
)。F4 是边界线。
顺便说一句:定点精度是常数,浮点数是相对的,比较有问题。 32 位定点的精度比 IEEE754 single
在 +/-1E0
附近具有更高的精度。典型的 ADC 和 DAC 无论如何都使用整数或定点。【参考方案2】:
当您想更改设置时不要重新初始化计时器,HAL 有一个专用宏用于此目的,称为:
/**
* @brief Sets the TIM Capture Compare Register value on runtime without
* calling another time ConfigChannel function.
* @param __HANDLE__: TIM handle.
* @param __CHANNEL__ : TIM Channels to be configured.
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @arg TIM_CHANNEL_4: TIM Channel 4 selected
* @param __COMPARE__: specifies the Capture Compare register new value.
* @retval None
*/
#define __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__) \
(*(__IO uint32_t *)(&((__HANDLE__)->Instance->CCR1) + ((__CHANNEL__) >> 2)) = (__COMPARE__))
对于 Timer 1 - Channel 1 和 Timer 1 - Channel 2,它应该如下所示:
Data_Update();
adjust_PWM();
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse_width);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pulse_width);
【讨论】:
以上是关于stm32高级定时器 pwm占空比怎么改变的主要内容,如果未能解决你的问题,请参考以下文章