一、PWM的基本概念
1、什么是PWM
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是在具有惯性的系统中利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换和电机控速等的许多领域中。
在我的理解上,PWM是一个模拟电压控制,主要是将硬件中单一的高电平或低电平模拟成一个准确的电压值,怎么实现的呢?主要是靠占空比以及高频率来实现的,比如3V的高电平当一个周期中有效电平(高电平)只占三分之一时,就认为他只有1V,因为刷新频率很快所以得以实现。
2、PWM参数
(1)频率 = 1 / Ts(是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);)
(2)占空比 = Ton / Ts(有效电平与周期之比)
(3)分辨率 = 占空比变化步距
二、PWM的基本原理
1、PWM的基本结构
黄线:ARR重装载值 蓝线:CNT计数值 红线:CCR的值
此图为高电平为有效电平,低于CCR的值时为有效电平(高电平),高于CCR的值为无效电平(低电平)
2、参数计算
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)
注:CK_PSC为时钟频率,PSC预分频值,ARR重装载值
三、代码实例
1、PWM驱动呼吸灯
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //使能tim2时钟
TIM_InternalClockConfig(TIM2); //选择内部时钟驱动
TIM_TimeBaseInitTypeDef TIM_InitStructrue; //配置时钟单元
TIM_InitStructrue.TIM_ClockDivision = TIM_CKD_DIV1; //配置滤波器
TIM_InitStructrue.TIM_CounterMode = TIM_CounterMode_Up; //计数方式采用向上计数
TIM_InitStructrue.TIM_Period = 100 - 1; // 自动重装载值,ARR
TIM_InitStructrue.TIM_Prescaler = 720-1; //预分频系数,PSC
TIM_InitStructrue.TIM_RepetitionCounter = 0; //高级定时器的重复次数计数
TIM_TimeBaseInit(TIM2,&TIM_InitStructrue);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_Cmd(TIM2,ENABLE); //启动定时器
TIM_OCInitTypeDef TIM_InitStructure; //带N和Idlest参数都为高级定时器的参数
TIM_OCStructInit(&TIM_InitStructure); //给结构体附初始值
TIM_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置输出比较的模式
TIM_InitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //设置输出比较的极性,设置有效点平为高电平
TIM_InitStructure.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能
TIM_InitStructure.TIM_Pulse = 90; //设置CCR
TIM_OC1Init(TIM2,&TIM_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //因为GPIOA0为TIM2_CH1的通道
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2,Compare); //程序运行中设置CCR的值控制占空比,近似想象改变输出电压
}
2、PWM驱动舵机
(1)关于舵机:舵机是一种根据输入PWM信号占空比来控制输出角度的装置 输入PWM信号要求:周期为20ms(50HZ),高电平宽度为0.5ms~2.5ms,我采用的是180°舵机
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //使能tim2时钟
TIM_InternalClockConfig(TIM2); //选择内部时钟驱动
TIM_TimeBaseInitTypeDef TIM_InitStructrue; //配置时钟单元
TIM_InitStructrue.TIM_ClockDivision = TIM_CKD_DIV1; //配置滤波器
TIM_InitStructrue.TIM_CounterMode = TIM_CounterMode_Up; //计数方式采用向上计数
TIM_InitStructrue.TIM_Period = 20000 - 1; // 自动重装载值,ARR
TIM_InitStructrue.TIM_Prescaler = 72 - 1; //预分频系数,PSC
TIM_InitStructrue.TIM_RepetitionCounter = 0; //高级定时器的重复次数计数
TIM_TimeBaseInit(TIM2,&TIM_InitStructrue);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_Cmd(TIM2,ENABLE); //启动定时器
TIM_OCInitTypeDef TIM_InitStructure; //带N和Idlest参数都为高级定时器的参数
TIM_OCStructInit(&TIM_InitStructure); //给结构体附初始值
TIM_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置输出比较的模式
TIM_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置输出比较的极性,设置有效点平为高电平
TIM_InitStructure.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能
TIM_InitStructure.TIM_Pulse = 0; //设置CCR,500~2500
TIM_OC2Init(TIM2,&TIM_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
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);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2,Compare);
}
//舵机驱动
void Servo_Init(void)
{
PWM_Init();
}
/*
0°--》500 CCR
180°--》 2500 CCR
*/
void Servo_SetAngle(float Angle) //设置角度
{
PWM_SetCompare2(Angle / 180 * 2000 + 500);
}