当前位置: 首页 > article >正文

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 的原因

  1. 引脚资源匹配
    • PA0 是 TIM2 的 通道 1(CH1) 默认复用引脚(无需重映射),可直接输出 PWM。
    • 若使用其他定时器(如 TIM3),需占用不同引脚(如 PA6),可能与其他外设冲突。
  2. 定时器类型与功能需求
    • TIM2 是 通用定时器,支持 PWM 输出、输入捕获等功能,满足基本调速需求。
    • 高级定时器(如 TIM1)功能更复杂(如互补输出),但需额外配置,且引脚可能被占用。
  3. 时钟频率与精度
    • TIM2 挂载在 APB1 总线(默认 36MHz,经倍频后为 72MHz),通过预分频和自动重载值可灵活配置 PWM 频率。
    • 代码中PSC=720-1ARR=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. 选择原则

  1. 功能需求
    • 普通 PWM 输出 → 通用定时器(如 TIM2、TIM3)。
    • 三相电机控制 → 高级定时器(如 TIM1)。
    • 简单定时任务 → 基本定时器(如 TIM6)。
  2. 引脚资源
    • 查看数据手册确认定时器通道对应的 GPIO 引脚(如 TIM2_CH1 对应 PA0)。
    • 避免与其他外设(如 USART、I2C)冲突。
  3. 时钟频率
    • APB1 总线定时器(TIM2~TIM7):默认 36MHz(经倍频后为 72MHz)。
    • APB2 总线定时器(TIM1、TIM8):默认 72MHz。
    • 根据 PWM 频率需求调整PSCARR(频率 = 时钟 /(PSC+1)/(ARR+1))。

三、TIM2 与其他定时器对比

定时器通道数计数器位数引脚(示例)总线适用场景
TIM2432 位PA0(CH1)、PA1(CH2)APB1普通 PWM、高精度计数
TIM3416 位PA6(CH1)、PB0(CH3)APB1普通 PWM
TIM1416 位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 为例)

  1. 修改时钟使能

    运行

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  // TIM3在APB1
    
  2. 调整 GPIO 引脚

    运行

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;  // TIM3_CH1对应PA6
    
  3. 修改输出比较函数

    运行

    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度
}
关键说明:
  1. 舵机控制原理

    • 标准舵机通过 PWM 脉冲宽度控制角度,通常:
      • 0.5ms 脉冲 → 0 度
      • 1.5ms 脉冲 → 90 度
      • 2.5ms 脉冲 → 180 度
    • 需保持 PWM 频率为 50Hz(周期 20ms)。
  2. 代码映射关系

    • PWM_SetCompare2()设置 TIM2 通道 2 的 CCR 值(范围 0~20000)。

    • 计算公式

      Angle/180×2000 + 500
      

      将角度线性映射到脉冲宽度:

      plaintext

      0度   → 500   → 0.5ms  
      180度 → 2500  → 2.5ms  
      
  3. 硬件连接

    • 舵机信号线 → TIM2_CH2 对应引脚(通常为 PA1)。
    • 舵机电源线 → 外部电源(通常 5V)。
    • 舵机地线 → 与 STM32 共地。
  4. 注意事项

    • 确保 PWM 频率为 50Hz(PSC=7199ARR=19999)。
    • 角度超出 0~180 度可能导致舵机过转损坏。
    • 如需更高精度,可调整计算公式或 PWM 分辨率。

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)CCR1TIM_SetCompare1()
通道 2(CH2)CCR2TIM_SetCompare2()
通道 3(CH3)CCR3TIM_SetCompare3()
通道 4(CH4)CCR4TIM_SetCompare4()

二、代码中的通道配置细节

  1. GPIO 引脚选择

    运行

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  // PA2
    

    PA2 是 TIM2_CH3 的默认复用引脚(参考 STM32F103 数据手册)。

  2. 输出比较初始化

    运行

    TIM_OC3Init(TIM2, &TIM_OCInitStructure);  // 初始化TIM2的通道3
    

    TIM_OC3Init() 明确指定配置 通道 3

  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()

四、总结

函数选择由 硬件连接软件配置 共同决定:

  1. 硬件:舵机信号线接 PA2(TIM2_CH3)。
  2. 软件:
    • 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的值
}

相关文章:

STM32标准库-TIM输出比较

文章目录 一、输出比较二、PWM2.1简介2.2输出比较通道&#xff08;高级&#xff09;2.3 输出比较通道&#xff08;通用&#xff09;2.4输出比较模式2.5 PWM基本结构1、时基单元2、输出比较单元3、输出控制&#xff08;绿色右侧&#xff09;4、右上波形图&#xff08;以绿色脉冲…...

科技创新驱动人工智能,计算中心建设加速产业腾飞​

在科技飞速发展的当下&#xff0c;人工智能正以前所未有的速度融入我们的生活。一辆辆无人驾驶的车辆在道路上自如地躲避车辆和行人&#xff0c;行驶平稳且操作熟练&#xff1b;刷脸支付让购物变得安全快捷&#xff0c;一秒即可通行。这些曾经只存在于想象中的场景&#xff0c;…...

figma 和蓝湖 有什么区别

以下是 Figma 和蓝湖的详细对比分析&#xff1a; 核心定位区别 维度Figma蓝湖本质全功能云端设计工具设计协作与交付平台核心功能设计原型协作开发交付设计稿交付标注切图协作设计能力✅ 完整矢量设计工具❌ 无设计功能&#xff08;需导入其他工具文件&#xff09;适用阶段全流…...

SQLServer中的存储过程与事务

一、存储过程的概念 1. 定义 存储过程&#xff08;Stored Procedure&#xff09;是一组预编译的 SQL 语句的集合&#xff0c;它们被存储在数据库中&#xff0c;可以通过指定存储过程的名称并执行来调用它们。存储过程可以接受输入参数、输出参数&#xff0c;并且可以返回执行…...

STM32H562----------ADC外设详解

1、ADC 简介 STM32H5xx 系列有 2 个 ADC,都可以独立工作,其中 ADC1 和 ADC2 还可以组成双模式(提高采样率)。每个 ADC 最多可以有 20 个复用通道。这些 ADC 外设与 AHB 总线相连。 STM32H5xx 的 ADC 模块主要有如下几个特性: 1、可配置 12 位、10 位、8 位、6 位分辨率,…...

uniapp 安卓 APP 后台持续运行(保活)的尝试办法

在移动应用开发领域&#xff0c;安卓系统的后台管理机制较为复杂&#xff0c;应用在后台容易被系统回收&#xff0c;导致无法持续运行。对于使用 Uniapp 开发的安卓 APP 来说&#xff0c;实现后台持续运行&#xff08;保活&#xff09;是很多开发者面临的重要需求&#xff0c;比…...

AI大数据模型如何与thingsboard物联网结合

一、 AI大数据与ThingsBoard物联网的结合可以从以下几个方面实现&#xff1a; 1. 数据采集与集成 设备接入&#xff1a;ThingsBoard支持多种通信协议&#xff08;如MQTT、CoAP、HTTP、Modbus、OPC-UA等&#xff09;&#xff0c;可以方便地接入各种物联网设备。通过这些协议&am…...

【SSM】SpringBoot笔记2:整合Junit、MyBatis

前言&#xff1a; 文章是系列学习笔记第9篇。基于黑马程序员课程完成&#xff0c;是笔者的学习笔记与心得总结&#xff0c;供自己和他人参考。笔记大部分是对黑马视频的归纳&#xff0c;少部分自己的理解&#xff0c;微量ai解释的内容&#xff08;ai部分会标出&#xff09;。 …...

STM32——CAN总线

STM32——CAN总线 1. CAN总线基础概念 1.1 CAN总线简介 控制器局域网&#xff08;Controller Area Network, CAN&#xff09;是由Bosch公司开发的串行通信协议&#xff0c;专为汽车电子和工业控制设计&#xff0c;具有以下核心特性&#xff1a; 多主控制架构&#xff1a;所有…...

嵌入式面试高频!!!C语言(四)(嵌入式八股文,嵌入式面经)

更多嵌入式面试文章见下面连接&#xff0c;会不断更新哦&#xff01;&#xff01;关注一下谢谢&#xff01;&#xff01;&#xff01;&#xff01; ​​​​​​​https://blog.csdn.net/qq_61574541/category_12976911.html?fromshareblogcolumn&sharetypeblogcolumn&…...

数据治理在制造业的实践案例

一、数据治理在制造业的重要性 随着工业4.0的到来,制造业正经历着前所未有的变革。数据治理作为制造业数字化转型的关键组成部分,对提升企业竞争力、优化生产流程、提高产品质量和客户满意度等方面起着至关重要的作用。在制造业中,数据治理不仅涉及到数据的收集、存…...

【强化学习】——03 Model-Free RL之基于价值的强化学习

【强化学习】——03 Model-Free RL之基于价值的强化学习 \quad\quad \quad\quad 动态规划算法是基于模型的算法,要求已知状态转移概率和奖励函数。但很多实际问题中环境 可能是未知的,这就需要不基于模型(Model-Free)的RL方法。 \quad\quad 其又分为: 基于价值(Valu…...

Edge(Bing)自动领积分脚本部署——基于python和Selenium(附源码)

微软的 Microsoft Rewards 计划可以通过 Bing 搜索赚取积分&#xff0c;积分可以兑换礼品卡、游戏等。每天的搜索任务不多&#xff0c;我们可以用脚本自动完成&#xff0c;提高效率&#xff0c;解放双手。 本文将手把手教你如何部署一个自动刷积分脚本&#xff0c;并解释其背…...

html表格转换为markdown

文章目录 工具功能亮点1.核心实现解析1. 剪贴板交互2. HTML检测与提取3. 转换规则设计 2. 完整代码 在日常工作中&#xff0c;我们经常遇到需要将网页表格快速转换为Markdown格式的场景。无论是文档编写、知识整理还是数据迁移&#xff0c;手动转换既耗时又容易出错。本文将介绍…...

VsCode 安装 Cline 插件并使用免费模型(例如 DeepSeek)

当前时间为 25/6/3&#xff0c;Cline 版本为 3.17.8 点击侧边栏的“扩展”图标 在搜索框中输入“Cline” 找到 Cline 插件&#xff0c;然后点击“安装” 安装完成后&#xff0c;Cline 图标会出现在 VS Code 的侧边栏中 点击 Use your own API key API Provider 选择 OpenRouter…...

短视频矩阵系统源码新发布技术方案有那几种?

短视频矩阵运营在平台政策频繁更迭的浪潮中&#xff0c;已成为内容分发的核心战场。行业领先者如筷子科技、云罗抖去推、超级编导等平台&#xff0c;其稳定高效的代发能力背后&#xff0c;离不开前沿技术方案的强力支撑。本文将深入剖析当前主流的六大短视频矩阵系统代发解决方…...

React 第五十二节 Router中 useResolvedPath使用详解和注意事项示例

前言 useResolvedPath 是 React Router v6 提供的一个实用钩子&#xff0c;用于解析给定路径为完整路径对象。 它根据当前路由上下文解析相对路径&#xff0c;生成包含 pathname、search 和 hash 的完整路径对象。 一、useResolvedPath 核心用途 路径解析&#xff1a;将相对…...

【PmHub面试篇】性能监控与分布式追踪利器Skywalking面试专题分析

你好&#xff0c;欢迎来到本次关于PmHub整合性能监控与分布式追踪利器Skywalking的面试系列分享。在这篇文章中&#xff0c;我们将深入探讨这一技术领域的相关面试题预测。若想对相关内容有更透彻的理解&#xff0c;强烈推荐参考之前发布的博文&#xff1a;【PmHub后端篇】Skyw…...

Cursor快速梳理ipynb文件Prompt

1. 整体鸟瞰 请在不运行代码的前提下&#xff0c;总结 <文件名.ipynb> 的主要目的、核心逻辑流程和输出结果。阅读整个项目目录&#xff0c;列出每个 .ipynb / .py 文件的角色&#xff0c;以及它们之间的数据依赖关系&#xff08;输入→处理→输出&#xff09;。2. 结构…...

天机学堂-分页查询

需求 分页查询我的课表 返回&#xff1a; 总条数、总页数、当前页的课表信息的集合 返回的VO&#xff08;已经封装成统一的LearningLessonsVO&#xff09; 定义Controller RestController RequestMapping("/lessons") RequiredArgsConstructor public class Lear…...

业态即战场:零售平台的生意模型与系统设计解构

目录 一、当我们在电商买菜、点外卖时,其实是零售业态在进化 (一)从“商场选货”到“算法推货”:零售的时代已经不同 (二)“控货”和“卖场”——零售的两种基本商业模式 二、四种经典零售业态解析:控货 vs 卖场,地面 vs 线上 (一)地面控货零售:直营模式的黄金…...

微算法科技(NASDAQ:MLGO)基于信任的集成共识和灰狼优化(GWO)算法,搭建高信任水平的区块链网络

随着数字化转型的加速&#xff0c;区块链技术作为去中心化、透明且不可篡改的数据存储与交换平台&#xff0c;正逐步渗透到金融、供应链管理、物联网等多个领域&#xff0c;探索基于信任的集成共识机制&#xff0c;并结合先进的优化算法来提升区块链网络的信任水平&#xff0c;…...

全新Xsens Animate版本是迄今为止最大的软件升级,提供更清晰的数据、快捷的工作流程以及从录制开始就更直观的体验

我们整合了专业人士喜爱的 Xsens 动捕功能&#xff0c;并使其更加完善。全新Xsens Animate版本是我们迄今为止最大的软件升级&#xff0c;旨在提供更清晰的数据、更快捷的工作流程以及从录制开始就更直观的体验。 从制作游戏动画到流媒体直播头像或构建实时电影内容&#xff0…...

大语言模型评测体系全解析(下篇):工具链、学术前沿与实战策略

文章目录 一、评测工具链&#xff1a;从手工测试到自动化工程的效率革命&#xff08;一&#xff09;OpenCompass&#xff1a;开源评测框架的生态构建1. 技术架构&#xff1a;三层架构实现评测自动化2. 开发者赋能&#xff1a;从入门到进阶的工具矩阵 &#xff08;二&#xff09…...

python打卡day46@浙大疏锦行

知识点回顾&#xff1a; 不同CNN层的特征图&#xff1a;不同通道的特征图什么是注意力&#xff1a;注意力家族&#xff0c;类似于动物园&#xff0c;都是不同的模块&#xff0c;好不好试了才知道。通道注意力&#xff1a;模型的定义和插入的位置通道注意力后的特征图和热力图 内…...

C++.OpenGL (1/64) 创建窗口(Hello Window)

OpenGL 创建窗口(Hello Window) 步骤详解与代码实现 #mermaid-svg-436DlGvysFQogISc {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-436DlGvysFQogISc .error-icon{fill:#552222;}#mermaid-svg-436DlGvysFQogISc…...

Excel 发现此工作表中有一处或多处公式引用错误。请检查公式中的单元格引用、区域名称、已定义名称以及到其他工作簿的链接是否均正确无误。弹窗

Excel 提示“发现此工作表中有一处或多处公式引用错误”通常表示公式中存在无效引用。以下是系统化的检查步骤&#xff0c;帮助你定位和修复问题&#xff1a; 1. 检查单元格引用&#xff1a; 无效单元格引用&#xff1a;检查公式中的单元格地址&#xff08;如 A1、B10&…...

NVIDIA DRIVE AGX平台:引领智能驾驶安全新时代

随着科技的不断进步&#xff0c;汽车行业正迎来前所未有的变革&#xff0c;智能驾驶技术成为全球产业竞相布局的焦点之一。然而&#xff0c;这场技术革命的背后&#xff0c;最关键且被广泛关注的是安全性问题。近日&#xff0c;我认真研读了NVIDIA发布的《自动驾驶安全报告》白…...

推荐12个wordpress企业网站模板

WordPress企业网站模板是一种专为企业网站设计的WordPress主题&#xff0c;旨在帮助企业创建专业、美观且易于管理的网站。这些模板通常具备响应式设计、SEO优化、多语言支持等功能&#xff0c;能够满足不同行业和企业的需求。 WordPress企业网站模板的适用场景 企业官网&…...

沙市区举办资本市场赋能培训会 点赋科技分享智能消费新实践

荆州市沙市区&#xff0c;2025年6月5日—— 在沙市区政府主办的“发挥区域性股权市场功能&#xff0c;助力企业拥抱资本市场”专题培训会上&#xff0c;区委副书记、区长郭熙胜强调要充分发挥资本市场服务实体经济功能&#xff0c;推动本土创新企业高质量发展。区内重点企业点赋…...