stm32:PWM原理 及 呼吸灯实现

早上好啊,大伙。上一期说完了定时器的原理和模板。这一期就来运用一下定时器来实现一些模块的功能。

对于定时器的一大应用就是PWM波调速,通过PWM调速能够实现很多模块的使用。所以今天这一期我们就来讲讲什么是PWM,讲完之后给大伙用PWM做一个呼吸灯。

文章目录

什么是PWM

PWM 也就是脉冲宽度调制,是一种通过调节数字信号的脉冲宽度来控制模拟设备的技术。其核心思想是快速切换电源的通断,通过改变高电平(导通)与低电平(关断)的时间比例(即占空比),来模拟不同的平均电压或功率输出。

不知道大家前面有没有学过数码管,用一个寄存器控制多个数码管就是通过快速变换,来实现多个数码管的显示。

再比如说,我们看的动漫也是这样实现的。

PWM的频率

单位时间内(通常为1秒)脉冲信号重复的次数,单位为赫兹(Hz)。

频率 = 1 周期 频率 = \frac{1}{周期} 频率=周期1

PWM的周期

一个完整脉冲循环(从高电平开始到下一个高电平开始)的时间长度,单位为秒(s)。

周期 = 1 频率 周期 = \frac{1}{频率} 周期=频率1

举个栗子

频率 ------

若频率为 1 kHz(1000 Hz),则周期为:
周期 = 1 1000 = 0.001 秒 周期 = \frac{1}{1000} = 0.001秒 周期=10001=0.001秒

周期 ------

若周期为 20 μs(微秒),则频率为:
频率 = 1 T = 1 20 × 1 0 − 6 = 50   kHz \text{频率} = \frac{1}{T} = \frac{1}{20 \times 10^{-6}} = 50\,\text{kHz} 频率=T1=20×10−61=50kHz

PWM的占空比

是一个脉冲周期内,高电平的时间与整个周期时间的比例

单位: % (0%-100%)

表示方式:20%

周期: 一个脉冲信号的时间 , 1s内测周期次数等于频率
脉宽时间: 高电平时间

上图中,脉宽时间占总周期时间的比例,就是占空比。

PWM原理

利用快速开关电源的通断,通过改变高电平持续时间占整个周期的比例(占空比),控制输出到负载的平均电压或功率。

OC(Output Compare)输出比较

输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形

每个高级定时器和通用定时器都拥有4个输出比较通道

高级定时器的前3个通道额外拥有死区生成和互补输出的功能

PWM(Pulse Width Modulation)脉冲宽度调制

在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域

PWM参数:

频率 = 1 / TS
占空比 = TON / TS
分辨率 = 占空比变化步距

输出比较通道(通用)框图


PWM代码实现

第一步、添加上期的 TIM 时钟的代码

这一步就不放代码。

就需要把ARR和PSC调一下,改成我们所想要的就行了。

c 复制代码
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;					//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;				//预分频器,即PSC的值

第二步、确定输出比较通道

每一个输出比较通道都有它对应的引脚口,可以看一下下面的引脚图 ------

例如说,下面 TIM2 的几个 OC 通道。

这里我们就用 TIM2 的 OC1 通道为例。

c 复制代码
void PWM_Init(void)
{
	Timer_Init();													//导入之前写的TIM时钟定义
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOB的时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出	
																	//受外设控制的引脚,均需要配置为复用模式
}

第三步、OC 通道初始化

在OC的初始化里面有很多的参数都是高级定时器里面才会用的,所以我们就挑出其中通用定时器里的参数来进行配置 ------

  1. TIM_OCMode,输出比较模式。

TIM_OCMode_Timing 定时模式

TIM_OCMode_Active 激活模式

TIM_OCMode_Inactive 非激活模式

TIM_OCMode_Toggle 翻转模式

TIM_OCMode_PWM1 PWM模式1

TIM_OCMode_PWM2 PWM模式2

  1. TIM_OCPolarity,输出极性。

TIM_OCPolarity_High 高极性

TIM_OCPolarity_Low 低极性

  1. TIM_OutputState,输出使能。

TIM_OutputState_Disable 失能

TIM_OutputState_Enable 使能

  1. TIM_Pulse,初始CCR值。

下面看看代码吧 ------

c 复制代码
void PWM_Init(void)
{
	Timer_Init();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOB的时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出	
																	//受外设控制的引脚,均需要配置为复用模式
	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量
	TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值
	                                                                //则最好执行此函数,给结构体所有成员都赋一个默认值
	                                                                //避免结构体初值不确定的问题
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
}

第四步、PWM配置CCR的值

需要注意的是 ------

CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比。
占空比 ( D u t y ) = C C R / ( A R R + 1 ) 占空比(Duty) = CCR / (ARR + 1) 占空比(Duty)=CCR/(ARR+1)

c 复制代码
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);		//设置CCR2的值
}

OK,到这里我们PWM的配置就完成了。

使用PWM实现呼吸灯

下面我们来看看怎么用刚才实现的PWM来做呼吸灯。

TIM的代码可以看上一期的内容 ------
stm32教程:TIM定时器详解 & TIM时钟计时代码模板

里面的Timer.c就按照上面说的改,这里就不放了。其它代码的完整版在下面。

PWM.c

c 复制代码
#include "stm32f10x.h"                  // Device header
#include "Timer.h"
#include "PWM.h"

void PWM_Init(void)
{
	Timer_Init();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOB的时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出
																	//受外设控制的引脚,均需要配置为复用模式
	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量
	TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值
	                                                                //则最好执行此函数,给结构体所有成员都赋一个默认值
	                                                                //避免结构体初值不确定的问题
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值
	
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);		//设置CCR2的值
}

PWM.h

c 复制代码
#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);


#endif

main.c

c 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"

uint16_t i = 0;

int main()
{
	OLED_Init();//函数定义初始化
	PWM_Init();
	

	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
		}
	}
	
}

总结

OKK,这一期的内容就这么多,其实还是容易的对吧。

如果需要工程的文件的可以私信我,或者在评论区里留言,我都会提供。

感谢大伙观看,别忘了三连支持一下

大家也可以关注一下我的其它专栏,同样精彩喔~

下期见咯~

相关推荐
教练、我想打篮球6 分钟前
04 基于 STM32 的时钟展示程序
stm32·单片机·嵌入式硬件
大鱼YY12 分钟前
STM32系统定时器以及微秒延时函数分析
stm32·滴答定时器
芯岭技术40 分钟前
普冉MS32C001单片机,国产32位单片机,芯片特性和功能介绍
单片机·嵌入式硬件
ThreeYear_s1 小时前
基于FPGA婴儿安全监护系统(蓝牙小程序监测)
fpga开发·小程序
吸纹鸽2 小时前
蓝桥杯FPGA赛道第二次模拟题代码
fpga开发·蓝桥杯
吃货界的硬件攻城狮3 小时前
【STM32 学习笔记】ADC数模转换器
笔记·stm32·单片机·学习
9527华安4 小时前
Altera系列FPGA实现图像视频采集转HDMI/LCD输出,提供4套Quartus工程源码和技术支持
fpga开发·ov5640·quartus·altera
156082072196 小时前
FPGA_Verilog实现QSPI驱动,完成FLASH程序固化
fpga开发
小昭dedug6 小时前
功能安全的关键——MCU锁步核技术全解析(含真实应用方案)
单片机·嵌入式硬件
负里557 小时前
STM32-模电
嵌入式硬件