stm32 PWM驱动呼吸灯

一、输出比较简介

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

stm32 PWM驱动呼吸灯_第1张图片CCR(捕获/比较寄存器)这里输入捕获和输出比较是共用的,当使用输入捕获时,就是捕获寄存器;当使用输出比较时,就是比较寄存器。在输出比较这里,这部分电路会比较CNT和CCR的值,CNT计数器值自增,CCR是我们给定的一个值,当CNT的值大于,小于或者等于CCR时,输出会被置1,置0,反复下去,就形成了一个电平不断跳变的PWM波形了。这就是输出比较的基本功能了。
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能

stm32 PWM驱动呼吸灯_第2张图片
stm32 PWM驱动呼吸灯_第3张图片死区生成和互补输出主要用来驱动三相无刷电机。

二、PWM简介

PWM(Pulse Width Modulation)脉冲宽度调制
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
PWM参数:
频率 = 1 / TS
占空比 = TON / TS(高电平时间/整个周期时间)
分辨率 = 占空比变化步距

stm32 PWM驱动呼吸灯_第4张图片

三、输出比较通道

stm32 PWM驱动呼吸灯_第5张图片当CNT>CCR1或者CNT=CCR1时,就会传给输出模式控制器一个信号,输出模式控制器就会改变它输出的oc1ref的高低电平。通过极性选择电路,写0电平不翻转,写1电平翻转,最后通过输出使能电路oc1通道输出。
输出模式控制器的具体工作方式:
stm32 PWM驱动呼吸灯_第6张图片我们主要使用PWM模式1和PWM模式2,频率和占空比都可调。一般我们使用向上计数,PWM模式1向上计数模式产生一个PWM波形的过程:
stm32 PWM驱动呼吸灯_第7张图片
配置好时基单元后,CNT计时器就开始不断自增运行了,然后我们给定一个CCR的值。如上图右上角部分,黄线是ARR(自动重装器)的值,红线是CCR的值,蓝线是CNT,下面的绿线是预设输出。
当CNT=CCR时,置低电平。当CNT=ARR时,清0继续自增。由上图可以知道,占空比的值是根据CCR的值来调控的,CCR越大,高电平时间越长,占空比越大。这样持续下去就形成了电平不断跳变的PWM信号,再通过极性选择和输出使能,最终通过GPIO输出。
PWM参数计算:
stm32 PWM驱动呼吸灯_第8张图片PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM频率等于CNT计数更新频率,因为PWM的周期等于CNT计数周期。
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)

四、pwm驱动呼吸灯

步骤:
1.开启时钟,开启定时器时钟和GPIO时钟。
2.初始化时基单元。初始化ARR和PSC的值。
3.初始化GPIO,PWM要通过GPIO输出,配置GPIO。
4.初始化输出比较模块。选择通道,初始化输出比较结构体。
5.启动定时器。启动后就开始输出PWM波形了。
驱动呼吸灯demo:
pwm.c

#include "stm32f10x.h"                  // Device header
 void PWM_Init(void)
 {
    
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;   //输出比较结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	//1.开启时钟,选择内部时钟,TIM2是APB1总线的外设
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//配置GPIO
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //选择复用推挽输出,将引脚控制权交给片上外设,控制PWM输出。
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//2.初始化时基单元
	TIM_InternalClockConfig(TIM2);   //选择内部时钟驱动TIM2的时基单元
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;  //选择时钟分频
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  //计数器模式选择
	//定时时间的公式:CK_CNT_OV = CK_PSC / (PSC + 1) / (ARR + 1),定时1s,也就是1HZ;
	//预分频器和计数器有一个数的偏差,因此要减1,PSC和ARR的取值0~65535;
	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_OCStructInit(&TIM_OCInitStructure);  //给结构体赋初值函数
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  //配置输出比较模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //输出比较极性,高电平
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //输出状态使能
	TIM_OCInitStructure.TIM_Pulse = 50;  //配置CCR寄存器的值  CCR
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);
	//5.启动定时器
	TIM_Cmd(TIM2,ENABLE); 
 }
 
 void PWM_SetCompare1(uint16_t compare)
 {
    TIM_SetCompare1(TIM2,compare);
 }

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "Key.h"
#include "Light_Seror.h"
#include "OLED.h"
#include "PWM.h"


int main(void)
{
	uint16_t i;
	OLED_Init();
	PWM_Init();
	
	while(1)
	{
		for(i = 0;i<=100;i++){
		    PWM_SetCompare1(i);
			Delay_ms(10);
		}	
        for(i = 0;i<=100;i++){
		    PWM_SetCompare1(100-i);
			Delay_ms(10);
		}			
	}
}

注:内容来自博主 【江科大自化协】。本文做学习笔记用。

你可能感兴趣的:(stm32,stm32,单片机,arm)