✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
一、概述
在STM32微控制器中,定时器(TIM)是一个非常重要的外设,它具有多种功能,其中输出比较功能是其常用功能之一。输出比较功能可以通过比较定时器的计数值和预设的比较值,来控制定时器对应通道的输出电平,从而实现诸如PWM(脉冲宽度调制)信号生成、方波输出等应用。
二、工作原理
2.1 定时器计数
定时器有一个计数器,它会按照一定的时钟源和预分频系数进行计数。计数器的值会不断递增(或递减,取决于定时器的工作模式),当计数器的值达到自动重载寄存器(ARR)的值时,会产生溢出事件,计数器会重新从0开始计数。
2.2 输出比较
输出比较功能通过比较计数器的值和比较寄存器(CCR)的值来控制输出电平。当计数器的值等于比较寄存器的值时,会根据预先设置的输出比较模式来改变定时器对应通道的输出电平。常见的输出比较模式有:
- 冻结模式:当计数器的值等于比较值时,输出电平保持不变。
- 设置模式:当计数器的值等于比较值时,输出电平被设置为高电平。
- 清除模式:当计数器的值等于比较值时,输出电平被清除为低电平。
- 翻转模式:当计数器的值等于比较值时,输出电平翻转。
三、应用场景
3.1 PWM信号生成
PWM信号在很多领域都有广泛应用,如电机控制、LED亮度调节等。通过输出比较功能可以方便地生成PWM信号,通过改变比较寄存器的值可以调节PWM信号的占空比。
3.2 方波输出
可以通过设置合适的比较值和自动重载值,使定时器输出固定频率和占空比的方波信号。
四、代码实现
以下是一个使用STM32Cube HAL库实现TIM输出比较功能生成PWM信号的示例代码,以STM32F103C8T6为例,假设使用TIM3的通道1输出PWM信号。
4.1 初始化配置
#include "stm32f1xx_hal.h"
TIM_HandleTypeDef htim3;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM3_Init();
// 启动PWM输出
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
while (1)
{
// 这里可以添加其他代码
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM3_Init(void)
{
TIM_OC_InitTypeDef sConfigOC = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 71; // 预分频系数,这里设置为71,定时器时钟频率为72MHz / (71 + 1) = 1MHz
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 999; // 自动重载值,PWM信号的周期为1 / (1MHz / (999 + 1)) = 1kHz
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
sConfigOC.Pulse = 500; // 比较值,占空比为50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
/*Configure GPIO pin : PA6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Error_Handler(void)
{
while(1)
{
}
}
4.2 代码解释
- 定时器初始化:在
MX_TIM3_Init
函数中,首先设置了定时器的预分频系数和自动重载值,确定了PWM信号的频率。然后配置了输出比较模式为PWM模式1,并设置了比较值,从而确定了PWM信号的占空比。 - GPIO初始化:在
MX_GPIO_Init
函数中,将PA6引脚配置为复用推挽输出模式,因为TIM3的通道1对应PA6引脚。 - 启动PWM输出:在
main
函数中,调用HAL_TIM_PWM_Start
函数启动TIM3的通道1的PWM输出。
五、总结
STM32的TIM输出比较功能为开发者提供了一种方便的方式来生成各种波形信号,如PWM信号和方波信号。通过合理配置定时器的参数和输出比较模式,可以满足不同应用场景的需求。在实际应用中,开发者可以根据具体需求调整定时器的预分频系数、自动重载值和比较值,以实现所需的信号频率和占空比。同时,还可以利用定时器的中断功能来实现更复杂的控制逻辑。