STM32标准库-TIM输出比较
文章目录
- 一、输出比较
- 二、PWM
- 2.1简介
- 2.2输出比较通道(高级)
- 2.3 输出比较通道(通用)
- 2.4输出比较模式
- 2.5 PWM基本结构
- 1、时基单元
- 2、输出比较单元
- 3、输出控制(绿色右侧)
- 4、右上波形图(以绿色脉冲为例)
- 2.6参数计算
- 三、舵机
- 3.1简介
- 3.2硬件电路
- 四、直流电机及驱动
- 硬件电路
- 1、引脚定义
- 2、电路连接
- 功能总结
- 应用
- 五、PWM驱动LED呼吸灯
- 5.1接线图
- 六、PWM驱动舵机
- 6.1接线图
- 6.2代码
- 关键说明:
- 七、PWM驱动直流电机
- 7.1接线图
- 7.2代码
- **一、定时器通道与函数的对应关系**
一、输出比较
二、PWM
2.1简介
2.2输出比较通道(高级)
2.3 输出比较通道(通用)
2.4输出比较模式
2.5 PWM基本结构
1、时基单元
PSC(预分频器):对输入时钟分频,降低计数器频率(CK_CNT = f_clk/(PSC+1))。
CNT(计数器):按CK_CNT递增(向上计数),范围0~ARR,溢出后重置。
ARR(自动重装器):存储计数器最大值,决定 PWM 周期(T=(ARR+1)/CK_CNT)。
2、输出比较单元
CCR(捕获 / 比较寄存器):存储比较值,决定占空比(Duty=CCR/(ARR+1))。
比较逻辑:
CNT<CCR:REF输出有效电平(高,占空比时段)。
CNT≥CCR:REF输出无效电平(低,剩余时段)。
3、输出控制(绿色右侧)
极性选择:翻转REF电平(如有效设为低,实现反向 PWM)。
输出使能:控制 PWM 是否输出到 GPIO。
4、右上波形图(以绿色脉冲为例)
蓝色斜线(CNT):计数器值(0→99→0 循环,ARR=99)。
红色水平线(CCR=30):比较阈值(占空比 30%)。
- 绿色脉冲(REF):
CNT<30:高电平(有效,30% 占空比)。
CNT≥30:低电平(无效,70% 占空比)。
周期:由ARR+1=100决定(假设CK_CNT=10kHz,周期 10ms)。
- 图形线条含义
蓝色(CNT):定时器计数器值(线性递增,循环)。
红色(CCR):比较阈值(占空比参考线)。
黄色(ARR):代表自动重装器(ARR)的数值,即计数器(CNT,蓝色斜线)的上限值(如图中ARR=99)。计数器在0~ARR范围内循环递增,当CNT达到ARR时重置,形成 PWM 周期。
绿色(REF):输出比较单元生成的 PWM 参考波形(经极性和使能后输出到 GPIO)。
- 功能总结
周期:由ARR和PSC控制,决定 PWM 频率。
占空比:由CCR控制,调节输出脉冲宽度。
应用:电机调速、LED 调光等,通过 GPIO 输出 PWM 波形。
2.6参数计算
- 核心公式:
频率:Freq = CK_PSC / (PSC+1)/(ARR+1)(CK_PSC为输入时钟,PSC预分频,ARR自动重装)。
占空比:Duty = CCR/(ARR+1)(CCR比较值,决定脉冲宽度)。
分辨率:Reso = 1/(ARR+1)(占空比最小可调精度)。
- 图中波形:
蓝色(CNT):计数器值(0→ARR 循环)。
黄色(ARR):计数器上限(如 99)。
红色(CCR):比较阈值(如 30,占空比 30%)。
绿色(PWM):输出波形(高电平时段为CCR,低电平为ARR-CCR)。
通过配置PSC、ARR、CCR,可计算并生成所需频率和占空比的 PWM 信号。
三、舵机
3.1简介
3.2硬件电路
四、直流电机及驱动
硬件电路
1、引脚定义
- 电源与控制:
VM:电机驱动电压输入(4.5~10V,为电机供电)。
VCC:逻辑电平输入(2.7~5.5V,模块内部逻辑电源)。
GND:电源地(共地)。
STBY:待机控制(高:工作;低:待机,电机停转)。
- 1 路电机(左):
PWMA:PWM 调速输入(占空比控制转速)。
AIN1/AIN2:方向控制(正反转、刹车等,见真值表)。
AO1/AO2:电机驱动输出(连接电机绕组)。
- 2 路电机(右):
PWMB:PWM 调速输入(右路电机)。
BIN1/BIN2:方向控制(右路电机)。
BO1/BO2:电机驱动输出(右路电机)。
2、电路连接
电源:3V3 接 VCC(逻辑),VM 需外接电机电源(图中未画),GND 共地。
控制信号:PA0~PA7 连接 STM32 GPIO(如 PWMA→PA0,AIN1→PA1 等),输出 PWM 和电平。
电机:AO1/AO2、BO1/BO2 接左右电机绕组,驱动运转。
三、真值表(下方,以 1 路为例)
功能总结
调速:通过 PWMA/PWMB 的 PWM 占空比调节电机转速(占空比↑→转速↑)。
方向控制:AIN1/AIN2(BIN1/BIN2)的电平组合决定电机正反转、刹车或停止。
电源管理:VM(功率)与 VCC(逻辑)分离,确保控制稳定,STBY 实现待机节能。
应用
电机驱动:直流电机的速度、方向控制(如智能车、机械臂)。
状态切换:通过 STBY 引脚实现模块待机,降低功耗或安全停机。
五、PWM驱动LED呼吸灯
5.1接线图
PWM.c
#include "stm32f10x.h" // Device header/*** 函 数:PWM初始化* 参 数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,重映射必须先开启AFIO的时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //将JTAG引脚失能,作为普通GPIO引脚使用/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为复用推挽输出 //受外设控制的引脚,均需要配置为复用模式 /*配置时钟源*/TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}
在 STM32F103C8T6 中选择 TIM2 作为 PWM 输出的原因及定时器选择原则如下:
一、选择 TIM2 的原因
- 引脚资源匹配
- PA0 是 TIM2 的 通道 1(CH1) 默认复用引脚(无需重映射),可直接输出 PWM。
- 若使用其他定时器(如 TIM3),需占用不同引脚(如 PA6),可能与其他外设冲突。
- 定时器类型与功能需求
- TIM2 是 通用定时器,支持 PWM 输出、输入捕获等功能,满足基本调速需求。
- 高级定时器(如 TIM1)功能更复杂(如互补输出),但需额外配置,且引脚可能被占用。
- 时钟频率与精度
- TIM2 挂载在 APB1 总线(默认 36MHz,经倍频后为 72MHz),通过预分频和自动重载值可灵活配置 PWM 频率。
- 代码中
PSC=720-1
、ARR=100-1
,计算得 PWM 频率为 1kHz(72MHz/720/100=1kHz),适用于多数电机控制。
二、STM32 定时器分类与选择原则
1. 定时器分类
类型 | 数量 | 功能特点 |
---|---|---|
高级定时器 (TIM1、TIM8) | 2 | - 支持互补输出(用于三相电机) - 带死区时间控制 - 含刹车功能 |
通用定时器 (TIM2~TIM5) | 4 | - 支持 PWM 输出、输入捕获 - 16 位 / 32 位计数器(TIM2、TIM5 为 32 位) |
基本定时器 (TIM6、TIM7) | 2 | - 仅支持定时功能 - 用于 DAC 触发、ADC 采样等 |
低功耗定时器 (TIM9~TIM14) | 6 | - 部分支持 PWM 输出 - 用于低功耗场景 |
2. 选择原则
- 功能需求:
- 普通 PWM 输出 → 通用定时器(如 TIM2、TIM3)。
- 三相电机控制 → 高级定时器(如 TIM1)。
- 简单定时任务 → 基本定时器(如 TIM6)。
- 引脚资源:
- 查看数据手册确认定时器通道对应的 GPIO 引脚(如 TIM2_CH1 对应 PA0)。
- 避免与其他外设(如 USART、I2C)冲突。
- 时钟频率:
- APB1 总线定时器(TIM2~TIM7):默认 36MHz(经倍频后为 72MHz)。
- APB2 总线定时器(TIM1、TIM8):默认 72MHz。
- 根据 PWM 频率需求调整
PSC
和ARR
(频率 = 时钟 /(PSC+1)/(ARR+1))。
三、TIM2 与其他定时器对比
定时器 | 通道数 | 计数器位数 | 引脚(示例) | 总线 | 适用场景 |
---|---|---|---|---|---|
TIM2 | 4 | 32 位 | PA0(CH1)、PA1(CH2) | APB1 | 普通 PWM、高精度计数 |
TIM3 | 4 | 16 位 | PA6(CH1)、PB0(CH3) | APB1 | 普通 PWM |
TIM1 | 4 | 16 位 | PA8(CH1)、PA9(CH2) | APB2 | 互补输出、三相电机控制 |
四、代码中 TIM2 配置解析
运行
// 1. 时钟使能(TIM2挂载在APB1)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);// 2. GPIO配置(PA0作为TIM2_CH1的复用引脚)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;// 3. PWM频率计算(72MHz/(720*100)=1kHz)
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // PSC
五、如何切换定时器(以 TIM3 为例)
-
修改时钟使能:
运行
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // TIM3在APB1
-
调整 GPIO 引脚:
运行
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // TIM3_CH1对应PA6
-
修改输出比较函数:
运行
TIM_OC1Init(TIM3, &TIM_OCInitStructure); // 改为TIM3 TIM_SetCompare1(TIM3, Compare); // 改为TIM3
总结
选择 TIM2 是因为其引脚(PA0)与功能(普通 PWM)匹配需求,且无需重映射。实际开发中,需根据 引脚资源、功能需求 和 时钟频率 综合选择定时器类型及通道。
/**
- 函 数:PWM设置CCR
- 参 数:Compare 要写入的CCR的值,范围:0~100
- 返 回 值:无
- 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
-
占空比Duty = CCR / (ARR + 1)
*/
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare); //设置CCR1的值
}
==PWM.h==```c
#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);#endif
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"uint8_t i; //定义for循环的变量int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化PWM_Init(); //PWM初始化while (1){for (i = 0; i <= 100; i++){PWM_SetCompare1(i); //依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮Delay_ms(10); //延时10ms}for (i = 0; i <= 100; i++){PWM_SetCompare1(100 - i); //依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗Delay_ms(10); //延时10ms}}
}
六、PWM驱动舵机
6.1接线图
6.2代码
PWM.c
#include "stm32f10x.h" // Device header/*** 函 数:PWM初始化* 参 数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1引脚初始化为复用推挽输出 //受外设控制的引脚,均需要配置为复用模式/*配置时钟源*/TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/ TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值TIM_OC2Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC2Init,配置TIM2的输出比较通道2/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}/*** 函 数:PWM设置CCR* 参 数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比* 占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM2, Compare); //设置CCR2的值
}
Servo.c
#include "stm32f10x.h" // 包含STM32F10x系列设备头文件
#include "PWM.h" // 包含PWM驱动头文件(提供PWM输出功能)/*** 函数:舵机初始化* 功能:配置PWM输出,为舵机控制提供基础* 说明:依赖PWM模块,需确保PWM输出引脚连接到舵机信号线*/
void Servo_Init(void)
{PWM_Init(); // 调用PWM初始化函数(配置TIM2通道2,频率50Hz)
}/*** 函数:舵机角度设置* 参数:Angle - 目标角度(0~180度)* 功能:将角度值转换为对应PWM占空比,控制舵机旋转* 公式:占空比 = Angle/180×2000 + 500* - 0度 → 500(对应0.5ms脉冲)* - 180度 → 2500(对应2.5ms脉冲)*/
void Servo_SetAngle(float Angle)
{// 角度转占空比计算(舵机标准:0.5ms~2.5ms脉冲对应0~180度)// PWM频率50Hz(周期20ms),ARR=19999 → 每1个计数值对应20ms/20000=0.001ms// 0.5ms → 500,2.5ms → 2500PWM_SetCompare2(Angle / 180 * 2000 + 500);// 示例:// Angle=0 → 500/20000=2.5%占空比 → 0.5ms脉冲 → 舵机0度// Angle=90 → 1500/20000=7.5%占空比 → 1.5ms脉冲 → 舵机90度// Angle=180 → 2500/20000=12.5%占空比 → 2.5ms脉冲 → 舵机180度
}
关键说明:
-
舵机控制原理:
- 标准舵机通过 PWM 脉冲宽度控制角度,通常:
- 0.5ms 脉冲 → 0 度
- 1.5ms 脉冲 → 90 度
- 2.5ms 脉冲 → 180 度
- 需保持 PWM 频率为 50Hz(周期 20ms)。
- 标准舵机通过 PWM 脉冲宽度控制角度,通常:
-
代码映射关系:
-
PWM_SetCompare2()
设置 TIM2 通道 2 的 CCR 值(范围 0~20000)。 -
计算公式
Angle/180×2000 + 500
将角度线性映射到脉冲宽度:
plaintext
0度 → 500 → 0.5ms 180度 → 2500 → 2.5ms
-
-
硬件连接:
- 舵机信号线 → TIM2_CH2 对应引脚(通常为 PA1)。
- 舵机电源线 → 外部电源(通常 5V)。
- 舵机地线 → 与 STM32 共地。
-
注意事项:
- 确保 PWM 频率为 50Hz(
PSC=7199
,ARR=19999
)。 - 角度超出 0~180 度可能导致舵机过转损坏。
- 如需更高精度,可调整计算公式或 PWM 分辨率。
- 确保 PWM 频率为 50Hz(
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"uint8_t KeyNum; //定义用于接收键码的变量
float Angle; //定义角度变量int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化Servo_Init(); //舵机初始化Key_Init(); //按键初始化/*显示静态字符串*/OLED_ShowString(1, 1, "Angle:"); //1行1列显示字符串Angle:while (1){KeyNum = Key_GetNum(); //获取按键键码if (KeyNum == 1) //按键1按下{Angle += 30; //角度变量自增30if (Angle > 180) //角度变量超过180后{Angle = 0; //角度变量归零}}Servo_SetAngle(Angle); //设置舵机的角度为角度变量OLED_ShowNum(1, 7, Angle, 3); //OLED显示角度变量}
}
七、PWM驱动直流电机
7.1接线图
7.2代码
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"uint8_t KeyNum; //定义用于接收按键键码的变量
int8_t Speed; //定义速度变量int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化Motor_Init(); //直流电机初始化Key_Init(); //按键初始化/*显示静态字符串*/OLED_ShowString(1, 1, "Speed:"); //1行1列显示字符串Speed:while (1){KeyNum = Key_GetNum(); //获取按键键码if (KeyNum == 1) //按键1按下{Speed += 20; //速度变量自增20if (Speed > 100) //速度变量超过100后{Speed = -100; //速度变量变为-100//此操作会让电机旋转方向突然改变,可能会因供电不足而导致单片机复位//若出现了此现象,则应避免使用这样的操作}}Motor_SetSpeed(Speed); //设置直流电机的速度为速度变量OLED_ShowSignedNum(1, 7, Speed, 3); //OLED显示速度变量}
}
Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"/*** 函 数:直流电机初始化* 参 数:无* 返 回 值:无*/
void Motor_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA4和PA5引脚初始化为推挽输出 PWM_Init(); //初始化直流电机的底层PWM
}/*** 函 数:直流电机设置速度* 参 数:Speed 要设置的速度,范围:-100~100* 返 回 值:无*/
void Motor_SetSpeed(int8_t Speed)
{if (Speed >= 0) //如果设置正转的速度值{GPIO_SetBits(GPIOA, GPIO_Pin_4); //PA4置高电平GPIO_ResetBits(GPIOA, GPIO_Pin_5); //PA5置低电平,设置方向为正转PWM_SetCompare3(Speed); //PWM设置为速度值}else //否则,即设置反转的速度值{GPIO_ResetBits(GPIOA, GPIO_Pin_4); //PA4置低电平GPIO_SetBits(GPIOA, GPIO_Pin_5); //PA5置高电平,设置方向为反转PWM_SetCompare3(-Speed); //PWM设置为负的速度值,因为此时速度值为负数,而PWM只能给正数}
}
在这段代码中选择 TIM_SetCompare3()
函数是因为 PWM 输出使用了 TIM2 的通道 3(CH3),对应 GPIO 引脚为 PA2。具体分析如下:
一、定时器通道与函数的对应关系
STM32 的定时器每个通道都有独立的 捕获 / 比较寄存器(CCR),用于控制 PWM 的占空比。不同通道需使用对应的设置函数:
定时器通道 | 对应的 CCR 寄存器 | 设置函数 |
---|---|---|
通道 1(CH1) | CCR1 | TIM_SetCompare1() |
通道 2(CH2) | CCR2 | TIM_SetCompare2() |
通道 3(CH3) | CCR3 | TIM_SetCompare3() |
通道 4(CH4) | CCR4 | TIM_SetCompare4() |
二、代码中的通道配置细节
-
GPIO 引脚选择:
运行
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PA2
PA2 是 TIM2_CH3 的默认复用引脚(参考 STM32F103 数据手册)。
-
输出比较初始化:
运行
TIM_OC3Init(TIM2, &TIM_OCInitStructure); // 初始化TIM2的通道3
TIM_OC3Init()
明确指定配置 通道 3。 -
占空比设置函数:
运行
void PWM_SetCompare3(uint16_t Compare) {TIM_SetCompare3(TIM2, Compare); // 设置通道3的CCR3寄存器 }
必须使用
TIM_SetCompare3()
才能修改通道 3 的 CCR 值,从而控制 PA2 引脚的 PWM 占空比。
三、若误用其他通道函数会怎样?
- 若调用
TIM_SetCompare1()
:
会修改 通道 1(CCR1) 的值,但通道 1 对应 PA0 引脚,与代码中配置的 PA2 无关。此时 PA2 的 PWM 占空比不会变化。 - 若需使用通道 1:
需将 GPIO 配置为 PA0,并调用TIM_OC1Init()
和TIM_SetCompare1()
。
四、总结
函数选择由 硬件连接 和 软件配置 共同决定:
- 硬件:舵机信号线接 PA2(TIM2_CH3)。
- 软件:
- 用
TIM_OC3Init()
初始化通道 3。 - 用
TIM_SetCompare3()
修改通道 3 的 CCR 值。
- 用
这样才能正确控制 PA2 的 PWM 输出,驱动舵机。
PWM.c
#include "stm32f10x.h" // Device header/*** 函 数:PWM初始化* 参 数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA2引脚初始化为复用推挽输出 //受外设控制的引脚,均需要配置为复用模式/*配置时钟源*/TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/ TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值TIM_OC3Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC3Init,配置TIM2的输出比较通道3/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}/*** 函 数:PWM设置CCR* 参 数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比* 占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2, Compare); //设置CCR3的值
}