32.PWM输出原理与配置

PWM输出原理与配置

参考资料
STM32Fx开发板:
《STM32Fx开发指南-HAL库版本》-第13章 PWM输出实验
STM32Fxx官方资料:
《STM32Fxx中文参考手册》-第23章 通用定时器

笔记基于正点原子官方视频
视频连接https://www.bilibili.com/video/BV1Wx411d7wT?p=71&spm_id_from=333.1007.top_right_bar_window_history.content.click
如有侵权,联系删除

一、通用定时器PWM概述

1.STM32 PWM工作过程

在这里插入图片描述
在这里插入图片描述

ARR的值决定着PWM波的周期,CRRx决定着PWM的占空比
当曲线大于CCRx时输出高电平,小于CCRx输出低电平,即形成PWM波,调节CCRx的值可以实现占空比的调节

2.STM32 PWM工作过程(通道1为例)

在这里插入图片描述

CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。
CCMR1: OC1M[2:0]位:
对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】
CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。
CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。

3.PWM模式1 & PWM模式2

寄存器TIMx_CCMR1的OC1M[2:0]位来分析:
在这里插入图片描述
在这里插入图片描述

4.STM32 PWM 总结

PWM模式
脉冲宽度调制模式可以生成一个信号,该信号频率由TIMx_ARR寄存器值决定,其占空比则由TIMx_CCRx寄存器值决定。
通过向TIMx_CCMRx寄存器中的OCxM位写入110 (PWM模式1)或111(PWM模式2),可以独立选择各通道(每个OCx输出对应一个PWM)的PWM模式。必须通过将TIMx_CCMRx寄存器中的OCxPE位置1使能相应预装载寄存器,最后通过将TIMx_CR1寄存器中的ARPE位置1使能自动重载预装载寄存器。

STM32 定时器输出通道引脚
在芯片的数据手册中查看
在这里插入图片描述

二、常用寄存器和库函数配置

1.通用定时器基本函数和定义所在文件

stm32fxxx_hal_tim.c
位置:工程文件 - HALLIB - stm32fxxx_hal_tim.c
stm32fxxx_hal_tim.h
位置:工程文件 - HALLIB - stm32fxxx_hal_tim.c - stm32fxxx_hal_tim.h

2.定时器PWM时基参数初始化函数

函数体:HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
位置:工程文件 - HALLIB - stm32fxxx_hal_tim.c
在这里插入图片描述

该函数和HAL_TIM_Base_Init函数作用一样,不同的是引导调用不同的回调函数

typedef struct
{
	uint32_t Prescaler;					 //预分频系数
	uint32_t CounterMode;			 //计数模式:向上/下
	uint32_t Period; 						//自动装载值
	uint32_t ClockDivision; 			//时钟分频因子:定时器时钟与数字滤波器分频比
	uint32_t RepetitionCounter; 	//重复计数次数:高级定时器使用
} TIM_Base_InitTypeDef;
3.定时器PWM时基参数初始化回调函数:

函数体:void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim);
位置:工程文件 - HALLIB - stm32fxxx_hal_tim.c

主要用来编写定时器时钟使能等。

__HAL_RCC_TIM3_CLK_ENABLE();//定时器3时钟使能
4.PWM输出比较通道参数配置函数:

函数体:HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef* sConfig, uint32_t channel);
位置:工程文件 - HALLIB - stm32fxxx_hal_tim.c
在这里插入图片描述

typedef struct
{
	uint32_t OCMode;			 //模式PMW1 OR PWM2 
	uint32_t Pulse;				 //设置比较值
	uint32_t OCPolarity; 		//输出比较极性
	uint32_t OCNPolarity; 
	uint32_t OCFastMode; 
	uint32_t OCIdleState; 
	uint32_t OCNIdleState; 
	} TIM_OC_InitTypeDef; 

入门阶段配置前三个即可

5.使能定时器和PWM输出比较通道:

函数体:HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
函数体:HAL_StatusTypeDef HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
此函数同时开启了定时器PWM通道的输出比较中断

6.PWM输出配置步骤

①使能定时器时钟和通道IO口时钟。
②配置IO口复用映射:

HAL_GPIO_Init();

③初始化PWM时基参数:

HAL_TIM_PWM_Init();

④初始化PWM通道参数:

HAL_TIM_PWM_ConfigChannel();

⑤使能定时器PWM

HAL_TIM_PWM_Start();

三、PWM输出实验

要求:
使用定时器PWM功能,输出占空比可变的PWM波,用来驱动LED灯,从而达到LED亮度由暗变亮,又从亮变暗,如此循环。
以前文按键输入实验为模板,在此基础上进行更改

1.清理main.c函数,引入相关库

如下图:
在这里插入图片描述

添加定时器下相关库文件
在这里插入图片描述

2.初始化PWM时基参数:

HAL_TIM_PWM_Init();

1)搭建定时器基本框架

在这里插入图片描述

2)调用HAL_TIM_PWM_Init();

位置:工程文件 - HALLIB - stm32f4xx_hal_tim.c
在这里插入图片描述

可见HAL_TIM_PWM_Init();中定义的变量时一个TIM_HandleTypeDef类型的结构体指针,这里我们需要在main.c函数里定义一个TIM3_PWM_Handler
TIM_HandleTypeDef TIM3_PWM_Handler;

3)对结构体指针的成员变量进行配置

下面对结构体指针的成员变量进行配置
Instance配置过程同上一小节

TIM3_PWM_Handler.Init配置
主要配置三个变量,跟上一小节类似


Prescaler			预分频系数(PSC)
CounterMode	计数模式
Period				自动装载值(ARR)
	TIM3_Handler.Init.Prescaler = 9000 - 1;
	TIM3_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM3_Handler.Init.Period = 5000 - 1;

即Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk
Tout(溢出时间)=(5000)(9000)/90x10^6=0.5s
这里PWM波的周期即是 1/Tout(溢出时间)


具体设置如下:
TIM3_PWM_Handler.Init.Prescaler = 90 - 1;
TIM3_PWM_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM3_PWM_Handler.Init.Period = 500 - 1;

最终代码如下

TIM_HandleTypeDef TIM3_PWM_Handler;

void TIM3_PWM_Init (void)
{
	TIM3_PWM_Handler.Instance = TIM3;						//初始化TIM3
	TIM3_PWM_Handler.Init.Prescaler = 90 - 1;				//预分频系数(PSC)
	TIM3_PWM_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;	//计数模式
	TIM3_PWM_Handler.Init.Period = 500 - 1;					//自动装载值(ARR)
	HAL_TIM_PWM_Init(&TIM3_PWM_Handler);
}
3.初始化PWM通道参数:

HAL_TIM_PWM_ConfigChannel();
位置:工程文件 - HALLIB - stm32f4xx_hal_tim.c
在这里插入图片描述

HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef*sConfig, uint32_t Channel)
可见函数里面有三个变量,根据形式进行配置
第一个参数是TIM的结构体指针,前面已经定义好了,这里直接用就行:&TIM3_PWM_Handler

第二个是TIM_OC的结构体指针,这里我们要自己定义一个
TIM_OC_InitTypeDef TIM3_OC_Init;
TIM3_OC_Init.OCMode //模式PMW1 OR PWM2
TIM3_OC_Init.Pulse //设置比较值
TIM3_OC_Init.OCPolarity //输出比较极性

查看OCMode定义如下,这里选择TIM_OCMODE_PWM1
在这里插入图片描述

查看OCPolarity定义如下,这里选择TIM_OCPOLARITY_LOW
在这里插入图片描述

下面设置Pulse,即设计比较值,前文提到过,ARR的值决定着PWM波的周期,CRRx决定着PWM的占空比,这里ARR是Period 自动装载值,CRRx是Pulse设置比较值
我们设置占空比为50%,前文ARR设置的是500,这里CRRx即要取250。
配置好代码如下:

	TIM3_OC_Init.OCMode = TIM_OCMODE_PWM1;				 //模式PMW1 OR PWM2 
	TIM3_OC_Init.Pulse = 250;							 //设置比较值,和ARR相比即是占空比
	TIM3_OC_Init.OCPolarity = TIM_OCPOLARITY_LOW;		 //输出比较极性

第三个是定时器通道,查看定义来进行设置,这里选择通道4
在这里插入图片描述
在这里插入图片描述

PWM通道参数设置完毕代码如下

TIM_OC_InitTypeDef TIM3_OC_Init;

void TIM3_PWM_Init (void)
{
	TIM3_OC_Init.OCMode = TIM_OCMODE_PWM1;				 //模式PMW1 OR PWM2 
	TIM3_OC_Init.Pulse = 250;							 //设置比较值,和ARR相比即是占空比
	TIM3_OC_Init.OCPolarity = TIM_OCPOLARITY_LOW;		 //输出比较极性
	HAL_TIM_PWM_ConfigChannel(&TIM3_PWM_Handler,&TIM3_OC_Init,TIM_CHANNEL_4);				//初始化PWM通道参数
}

在这里插入图片描述

4.使能定时器时钟和通道IO口时钟、配置IO口复用映射

这一部分跟上一小节一样,稍微修改成自己所需的口即可,下面直接看代码

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	if (htim -> Instance == TIM3)				//判断定时器3是否上报中断
	{
		GPIO_InitTypeDef GPIO_Initure;			//初始化GPIO口
		__HAL_RCC_TIM3_CLK_ENABLE();			//使能定时器TIM3时钟
		__HAL_RCC_GPIOB_CLK_ENABLE();			//使能IO口GPIOB时钟
		
		GPIO_Initure.Pin=GPIO_PIN_1;			//PB1
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
		GPIO_Initure.Speed=GPIO_SPEED_FAST;		//高速
		GPIO_Initure.Alternate=GPIO_AF2_TIM3;	//复用为TIM3
		HAL_GPIO_Init(GPIOB,&GPIO_Initure);	   	//初始化PB1
	}
}

在这里插入图片描述

5.使能定时器PWM

HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
位置:工程文件 - HALLIB - stm32f4xx_hal_tim.c - stm32f4xx_hal_tim.h

查看uint32_t Channel定义,这里选择TIM3的TIM_CHANNEL_4
在这里插入图片描述

代码如下:

	HAL_TIM_PWM_Start(&TIM3_PWM_Handler,TIM_CHANNEL_4);		//选择TIM3的TIM_CHANNEL_4,定时器3的通道4

在这里插入图片描述

6.编写中断服务函数

我们定义一个可以返回变量compare的新的函数体,让CCR4指向compare,这样改变compare的值即可改变CCR4的值,即改变占空比
代码如下:

void TIM_SetTIM3Compare4(u32 compare)
{
	TIM3->CCR4 = compare;		//将compare指向CCR4,操控compare的值来控制占空比
}
7.编写main函数

首先在main中初始化定时器
TIM3_PWM_Init(); //初始化TIM3定时器

然后在while循环中按照要求编写可以改变占空比的代码
代码如下:

int main(void)
{
    u8 dir=1;						//决定方向,自加还是自减,即变亮还是变暗
    u16 led0pwmval=0;  				//决定亮度
	
	HAL_Init();                     //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    LED_Init();                     //初始化LED 
    KEY_Init();                     //初始化按键
	TIM3_PWM_Init();				//初始化TIM3定时器
	
    while(1)
    {
		delay_ms(10);	 	
		if(dir)
		{
			led0pwmval++;					//dir==1 led0pwmval递增
		}
		else 
		{
			led0pwmval--;					//dir==0 led0pwmval递减 
		}
		if(led0pwmval>300)
		{	
			dir=0;							//led0pwmval到达300后,方向为递减
		}
		if(led0pwmval==0)
		{	
			dir=1;							//led0pwmval递减到0后,方向改为递增
		}
		TIM_SetTIM3Compare4(led0pwmval);	//调用中断服务函数,并将led0pwmval的值返回过去
    }
}

至此,所有代码编写完毕,main.c代码如下

 #include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"

TIM_HandleTypeDef TIM3_PWM_Handler;
TIM_OC_InitTypeDef TIM3_OC_Init;

void TIM3_PWM_Init (void)
{
	TIM3_PWM_Handler.Instance = TIM3;						//初始化TIM3
	TIM3_PWM_Handler.Init.Prescaler = 90 - 1;				//预分频系数(PSC)
	TIM3_PWM_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;	//计数模式
	TIM3_PWM_Handler.Init.Period = 500 - 1;					//自动装载值(ARR)
	HAL_TIM_PWM_Init(&TIM3_PWM_Handler);
	
	TIM3_OC_Init.OCMode = TIM_OCMODE_PWM1;				 //模式PMW1 OR PWM2 
	TIM3_OC_Init.Pulse = 250;							 //设置比较值,和ARR相比即是占空比
	TIM3_OC_Init.OCPolarity = TIM_OCPOLARITY_LOW;		 //输出比较极性
	HAL_TIM_PWM_ConfigChannel(&TIM3_PWM_Handler,&TIM3_OC_Init,TIM_CHANNEL_4);				//初始化PWM通道参数
	
	HAL_TIM_PWM_Start(&TIM3_PWM_Handler,TIM_CHANNEL_4);		//选择TIM3的TIM_CHANNEL_4,定时器3的通道4
}

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == TIM3)				//判断定时器3是否上报中断
	{
		GPIO_InitTypeDef GPIO_Initure;			//初始化GPIO口
		__HAL_RCC_TIM3_CLK_ENABLE();			//使能定时器TIM3时钟
		__HAL_RCC_GPIOB_CLK_ENABLE();			//使能IO口GPIOB时钟
		
		GPIO_Initure.Pin=GPIO_PIN_1;			//PB1
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
		GPIO_Initure.Speed=GPIO_SPEED_FAST;		//高速
		GPIO_Initure.Alternate=GPIO_AF2_TIM3;	//复用为TIM3
		HAL_GPIO_Init(GPIOB,&GPIO_Initure);	   	//初始化PB1
	}
}

void TIM_SetTIM3Compare4(u32 compare)
{
	TIM3->CCR4 = compare;		//将compare指向CCR4,操控compare的值来控制占空比
}

int main(void)
{
    u8 dir=1;						//决定方向,自加还是自减,即变亮还是变暗
    u16 led0pwmval=0;  				//决定亮度
	
	HAL_Init();                     //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    LED_Init();                     //初始化LED 
    KEY_Init();                     //初始化按键
	TIM3_PWM_Init();				//初始化TIM3定时器
	
    while(1)
    {
		delay_ms(10);	 	
		if(dir)
		{
			led0pwmval++;					//dir==1 led0pwmval递增
		}
		else 
		{
			led0pwmval--;					//dir==0 led0pwmval递减 
		}
		if(led0pwmval>300)
		{	
			dir=0;							//led0pwmval到达300后,方向为递减
		}
		if(led0pwmval==0)
		{	
			dir=1;							//led0pwmval递减到0后,方向改为递增
		}
		TIM_SetTIM3Compare4(led0pwmval);	//调用中断服务函数,并将led0pwmval的值返回过去
    }
}

四、在STM32CubeMX中配置PWM

详细可参考:H:\2技术书籍\STM32F429开发指南 - STM32F429开发指南-HAL库版本_V1.1 - 13.5 STM32CubeMX 配置定时器 PWM 输出功能
在这里插入图片描述
请添加图片描述

在这里插入图片描述
在这里插入图片描述

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值