STM32 高级定时器 输出PWM波

本文围绕STM32高级定时器展开,介绍了其输出比较功能框架,包括时基模块、比较寄存器、死区发生器和输出控制。阐述了配置PWM波的结构体,给出编程目标及步骤,还提及PWM波频率和占空比的计算方法,最后说明部分未详细介绍的寄存器和后续计划。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如有错误,还请大佬指出

目录

1.定时器引脚图

2.总体框架

2.1时基模块

2.2比较寄存器

2.3死区发生器

2.4输出控制

3.结构体

4.编程

5.说明


1.定时器引脚图

2.总体框架

注:高级定时器除了通用定时器所具有的输入捕获和输出比较功能外,另外还添加了可编程死区互补输出、重复计 数器、带刹车 (断路) 功能,本文章只截取了其中的输出比较框图。

我将高级定时器的框架分为4个部分:时基模块、比较寄存器、死区发生器、输出控制。

2.1时基模块

高级定时器时钟源有4个,这里仅介绍内部时钟源

 时基单元框架如图

将此分为4部分:1.预分频器PSC,可实现1-65536的分频。2.计数器 CNT:三种计数模式,递增计数模式、递减计数模式和递增/递减 (中 心对齐) 计数模式。3.自动重载寄存器 ARR及4.重复计数器 RCR

这里与基本定时器不一样的就是三种计数模式及重复计数器。

通俗来讲就是,循环从0(或最大值)往上(或往下数),当数到最大值(或0),可以发生中断或者事件,而当使用了重复计数器后,数特定的遍数会产生中断1或者事件。其中往上或者往下计数则取决于计数模式。

而本次输出PWM波,不需要采用中断,只需其计数功能即可。

2.2比较寄存器

当计数器 CNT 的值跟比较寄存器 CCR 的值相等的时候,输出参考信号 OCxREF 的信号的极性 就会改变,其中 OCxREF=1(高电平)称之为有效电平,OCxREF=0(低电平)称之为无效电平。

此处输出的信号为OCxREF.

在进入死区发生器之前,可以设置输出比较模式,对于输出PWM波而言,有两个模式可供选择,分别为PWM1,PWM2

2.3死区发生器

在经过死区发生器之后会产生两路带死区的互补 信号 OCx_DT 和 OCxN_DT。如果没有加入死区控制,那么进入输出控制电 路的信号就直接是 OCxREF。

单纯的PWM波,此处不做详细介绍。

2.4输出控制

由死区发生器输出的信号会被分成两路,一路是原始信号,一路是被反向的信号,具体的由寄存器 CCER 的位 CCxP 和 CCxNP 控制。经过极性选择的信号是否由 OCx 引脚输出到外部引脚 CHx/CHxN (即是否使能),则由寄存器 CCER 的位 CxE/CxNE 配置。

3.结构体

typedef struct
{
  uint16_t TIM_Prescaler;        //时钟预分频,对应PSC
                                 
  uint16_t TIM_CounterMode;      //时钟计数模式,对应3中计数方法
                                 
  uint16_t TIM_Period;           //定时器周期,对应ARR寄存器
                                                             
  uint16_t TIM_ClockDivision;    //时钟分频,设置定时器时钟 CK_INT 频率与死区发生器以及数字滤 
                                 //波器,采样时钟频率分频比。可以选择 1、2、4 分频。

  uint8_t TIM_RepetitionCounter; //重复计数器,对应RAR
                                                                 
} TIM_TimeBaseInitTypeDef;       

typedef struct
{
  uint16_t TIM_OCMode;          //输出模式,PWM1及PWM2,对应寄存器CCMR1->OCxM
                             
  uint16_t TIM_OutputState;     //比较输出使能,对应CCER->CCxE
                             
  uint16_t TIM_OutputNState;    //比较互补输出使能,对应CCER->CCxNE
                              
  uint16_t TIM_Pulse;           //脉冲宽度,即比较寄存器的值,对应CCR1
                             
  uint16_t TIM_OCPolarity;      //输出极性,对应CCER->CCxP

  uint16_t TIM_OCNPolarity;     //互补输出极性,对应CCER->CCxP

  uint16_t TIM_OCIdleState;     //空闲状态比较输出状态,对应CR2->OIS1

  uint16_t TIM_OCNIdleState;    //空闲状态下比较互补输出状态,对应CR2->OIS1N
                               
} TIM_OCInitTypeDef;

 配置pwm的结构体主要用到两个,一个是时基初始化的结构体,一个是输出比较的结构体,时基初始化的结构体

其中输出比较的结构体对应图中的寄存器如下图

 但是我们除了要配备这两个结构体之外,还有一个寄存器要使能 

对应BDER->MOE寄存器,官方介绍如下图

 就是使能输出引脚

4.编程

总结一下,编程的目标:

1.对通道的GPIO引脚进行配置

2.对两个结构体进行配置

3.使能时钟源,使能输出通道

以下程序配置的为1Khz,占空比为40%的PWM波

void advance_tim1_gpio_config(void)
{
	//1.结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//2.开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	//3.配置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		
	//4.初始化
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//5.使能(无)	
}

void advance_tim1_mode_config()
{
	//1.结构体,时基结构体及输出比较结构体
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	//2.开时钟,TIM1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	
	//3.配置及初始化
	/*--------------------时基结构体初始化-------------------------*/
	// PWM 信号的频率 F = TIM_CLK/{(ARR+1)*(PSC+1)}
	
	TIM_TimeBaseStructure.TIM_Period = 9;	                      //ARR寄存器的值
	TIM_TimeBaseStructure.TIM_Prescaler = 7199;	                  //PSC分频的值
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //向上计数
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;                //重复计数器为0
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
	
	/*--------------------输出比较结构体初始化-------------------*/
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;             //输出模式:PWM1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 4;			                  //设置占空比
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //有效电平
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;  //空闲时比较输出状态
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);

	//4.使能,此处使能为将内部时钟作为TIM1时钟源的使能
	TIM_Cmd(TIM1, ENABLE);									      //使能计数器
	TIM_CtrlPWMOutputs(TIM1, ENABLE);				              //使能输出通道
}

说明:ARR寄存器与PSC寄存器都是从0开始计数,所以值要减一。

PWM波频率=TIM_CLK/{(ARR+1)*(PSC+1)}

其中TIM_CLK一般是APB2的频率,因为TIM1挂载在APB2中,APB2一般为72Mhz

占空比=TIM_OCInitStructure.TIM_Pulse/(ARR+1)

个人配置PWM波,一般如以下步骤

1.确认PWM波的频率

2.确认PWM波的精度(对应ARR寄存器)

3.确认占空比,TIM_OCInitStructure.TIM_Pulse

另外,有一个函数专门修改占空比(即修改TIM_OCInitStructure.TIM_Pulse的值),我之前不知道,还自己写了一个(大家避坑)

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);

5.说明

除了本文章说明的寄存器,还有一些预装载函数,如TIM_OC1PreloadConfi();

等,此函数对应CCMR->OC1PE,但是我暂时并不需要此功能,所以不做详细介绍。 

官方说明如下:此外,对于时基单元,个别寄存器下有阴影,对应影子寄存器,也不作详细介绍。

后续会出一篇PWM波控制电调的文章。

参考文献有《STM32F10x-中文参考手册》《STM32库开发实战指南——基于野火指南者开发板》

要在STM32上使用定时器1输出PWM信号,你可以按照以下步骤进行操作: 1. 配置GPIO引脚:选择一个可用的GPIO引脚作为PWM信号的输出引脚,并将其设置为复用功能模式。 2. 配置定时器:使用定时器1并将其配置为PWM模式。设置定时器的预分频器、计数模式和自动重装载值。 3. 配置通道:选择一个通道(例如通道1)并配置其相关的占空比、极性和输出模式。 4. 启动定时器:使能定时器1。 下面是一个简单的示例代码,演示如何在STM32上使用定时器1输出PWM信号: ```c #include "stm32f4xx.h" void TIM1_PWM_Init(void) { // 步骤1: 配置GPIO引脚 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1); // 步骤2: 配置定时器 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Prescaler = 0; // 无预分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period = 99; // 自动重装载值,决定 PWM 的周期 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // 步骤3: 配置通道 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_Pulse = 50; // 占空比,决定 PWM 的高电平时间 TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); // 步骤4: 启动定时器 TIM_Cmd(TIM1, ENABLE); } int main(void) { // 初始化定时器1 PWM TIM1_PWM_Init(); while (1) { // 在这里可以进行其他操作 } } ``` 请根据你的具体需求,修改占空比和周期的值以达到所需的PWM输出效果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值