一、PWM是什么?
首先,让我们来了解一下PWM的基本原理。PWM,即脉冲宽度调制,是一种通过调节脉冲信号的宽度来达到控制目的的技术。在单片机应用中,PWM常被用于控制电机转速、LED亮度等。简单来说,PWM就是通过改变高电平在一个周期中所占的时间(即脉宽),来调整输出信号的特性。
二、STM32F103C8T6与PWM
STM32F103C8T6作为一款基于ARM Cortex-M3内核的单片机,内置了多个定时器,每个定时器又可以配置为多个PWM通道。这使得它在PWM输出方面具有很大的灵活性。要使用STM32F103C8T6的PWM功能,我们需要对其定时器和PWM通道进行配置。
三、配置STM32F103C8T6的PWM
配置STM32F103C8T6的PWM主要涉及以下几个步骤:
- 初始化定时器:选择一个定时器(如TIM3),设置其时钟源、预分频值和自动重装载值,以确定PWM的频率。
- 配置PWM通道:选择一个PWM通道(如CH1),设置其比较模式和输出模式。比较模式决定了PWM的占空比,而输出模式决定了PWM波形的形状。
- 启动PWM输出:使能定时器和PWM通道,开始PWM波形的输出。
这些配置过程可以通过直接操作寄存器来完成,但对于初学者来说,使用STM32的HAL库会更加简单和直观。
四、示例代码
#include "stm32f10x.h"
void TIM3_PWM_Init(uint16_t prescaler, uint16_t period, uint16_t pulse) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 开启TIM3和GPIOA的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// GPIOA配置:TIM3 CH1 (PA6)
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// TIM3基础配置
TIM_TimeBaseStructure.TIM_Period = period; // 自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = prescaler; // 预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKDIV_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// PWM模式配置:TIM3 CH1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = pulse; // 脉冲宽度(占空比)
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
// 使能TIM3的预装载寄存器
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
// 使能TIM3
TIM_Cmd(TIM3, ENABLE);
// 使能TIM3的CH1输出比较
TIM_CtrlPWMOutputs(TIM3, ENABLE);
}
int main(void) {
// 系统初始化(包括时钟配置,此处省略)
// ...
// 初始化PWM,例如:预分频值为7199,自动重装载值为5000,脉冲宽度为2500(50%占空比)
// 假设APB1时钟为36MHz,则PWM频率为36MHz / (7200 * (5000 + 1)) ≈ 1Hz
TIM3_PWM_Init(7199, 5000, 2500);
while (1) {
// 主循环,可以添加其他任务
}
}