一、输出比较以及PWM简介
(1) OC(Output Compare)输出比较
(2)PWM(Pulse Width Modulation)脉冲宽度调制
<1>在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
<2>PWM参数:
频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
二、输出比较器框图
(1)输出比较通道(高级)
(2)输出比较通道(同用)
三、输出比较模式
四、PWM基本结构
(1)结构图
(2)参数计算
五、PWM驱动LED舵机以及直流电机
(1)函数讲解
<1>配置输出比较单元
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
<2>给输出比较结构体赋一个默认的值
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
<3>配置强制输出模式
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
<4>配置CCR寄存器的预装功能
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
<5>快速使能
void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
<6>外部事件时清除REF信号
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
<7>单独设置输出比较的极性
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
<8>单独修改输出使能参数
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);
<9>选择输出比较模式用来单独修改输出比较模式
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
<10>用来单独修改CCR寄存器值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
(2)PWM驱动LED呼吸灯代码
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Delay.h"
uint16_t i=0;
void PWMInit(void);
void PwmSetCompare(uint16_t campare);
int main(void)
{
PWMInit();
while(1)
{
for(i=0;i<=100;i++)
{
PwmSetCompare(i);
Delay_ms(10);
}
i=0;
}
}
/***************************************************************
* @briefvoid PWMInit(void)
* @param void
* @note 初始化PWM引脚
* @Sample PWMInit();
**************************************************************/
void PWMInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_InternalClockConfig(TIM2);//选用内部时钟
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式
TIM_TimeBaseInitStruct.TIM_Period=100-1;//周期ARR自动重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//PSC预分频器的值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器的值
//定时频率=72M/(PSC+1)*(ARR+1)
//定时时间=1/[72/(PSC+1)]*(ARR+1)
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;//中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;//
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择分组2
NVIC_Init(&NVIC_InitStruct);
TIM_OCStructInit(&TIM_OCInitStruct);//给该结构体成员都赋一个初值
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//设置输出比较模式
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCNPolarity_High;//设置输出比较的极性
TIM_OCInitStruct.TIM_OutputState=TIM_OSSRState_Enable;//设置输出使能
TIM_OCInitStruct.TIM_Pulse=50; //设置CCR值
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
TIM_Cmd(TIM2,ENABLE);//启动定时器
}
/***************************************************************
* @brief void PwmSetCompare(uint16_t campare);
* @param campare
* @note 设置OCR1的值改变PWM占空比
* @Sample 无
**************************************************************/
void PwmSetCompare(uint16_t campare)
{
TIM_SetCompare1(TIM2,campare);//设置OCR1的值
}
(3)PWM驱动舵机
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Delay.h"
#include "key.h"
uint16_t Angle=0;
void PWMInit(void);
void ServoAngle(uint16_t Angle);
int main(void)
{
PWMInit();
while(1)
{
if (Key_GetNum()==1)
{
Angle+=30;
if (Angle>180)
{
Angle=0;
}
}
ServoAngle(Angle);
OLED_ShowNum(1,7,Angle,3);
}
}
/***************************************************************
* @briefvoid PWMInit(void)
* @param void
* @note 初始化PWM引脚
* @Sample PWMInit();
**************************************************************/
void PWMInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_InternalClockConfig(TIM2);//选用内部时钟
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式
TIM_TimeBaseInitStruct.TIM_Period=20000-1;//周期ARR自动重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//PSC预分频器的值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器的值
//定时频率=72M/(PSC+1)*(ARR+1)
//定时时间=1/[72/(PSC+1)]*(ARR+1)
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;//中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;//
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择分组2
NVIC_Init(&NVIC_InitStruct);
TIM_OCStructInit(&TIM_OCInitStruct);//给该结构体成员都赋一个初值
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//设置输出比较模式
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCNPolarity_High;//设置输出比较的极性
TIM_OCInitStruct.TIM_OutputState=TIM_OSSRState_Enable;//设置输出使能
TIM_OCInitStruct.TIM_Pulse=0; //设置CCR值
TIM_OC2Init(TIM2,&TIM_OCInitStruct);
TIM_Cmd(TIM2,ENABLE);//启动定时器
}
/***************************************************************
* @brief void ServoAngle(uint16_t Angle)
* @param Angle
* @note 设置Angle的值改变舵机的转动角度
* @Sample 无
**************************************************************/
void ServoAngle(uint16_t Angle)
{
TIM_SetCompare2(TIM2,Angle/180*2000+500);//设置OCR2的值
}
(4)PWM驱动直流电机
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Delay.h"
#include "key.h"
int16_t speed=0;
void PWMInit(void);
void PwmSetCompare3(uint16_t campare);
void MotorSetSpeed(int16_t speed);
void MotorInit(void);
int main(void)
{
MotorInit();
while(1)
{
if(Key_GetNum()==1)
{
speed+=30;
if(speed>100)
{
speed=-100;
}
}
MotorSetSpeed(speed);
OLED_ShowNum(1,7,speed,3);
}
}
/***************************************************************
* @briefvoid PWMInit(void)
* @param void
* @note 初始化PWM引脚
* @Sample PWMInit();
**************************************************************/
void PWMInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_InternalClockConfig(TIM2);//选用内部时钟
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式
TIM_TimeBaseInitStruct.TIM_Period=100-1;//周期ARR自动重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//PSC预分频器的值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器的值
//定时频率=72M/(PSC+1)*(ARR+1)
//定时时间=1/[72/(PSC+1)]*(ARR+1)
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;//中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;//
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择分组2
NVIC_Init(&NVIC_InitStruct);
TIM_OCStructInit(&TIM_OCInitStruct);//给该结构体成员都赋一个初值
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//设置输出比较模式
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCNPolarity_High;//设置输出比较的极性
TIM_OCInitStruct.TIM_OutputState=TIM_OSSRState_Enable;//设置输出使能
TIM_OCInitStruct.TIM_Pulse=50; //设置CCR值
TIM_OC3Init(TIM2,&TIM_OCInitStruct);
TIM_Cmd(TIM2,ENABLE);//启动定时器
}
/***************************************************************
* @brief void PwmSetCompare(uint16_t campare);
* @param campare
* @note 设置OCR3的值改变PWM占空比
* @Sample 无
**************************************************************/
void PwmSetCompare3(uint16_t campare)
{
TIM_SetCompare3(TIM2,campare);//设置OCR3的值
}
/***************************************************************
* @brief void MotorInit()
* @param void
* @note 直流电机初始化函数
* @Sample MotorInit( );
**************************************************************/
void MotorInit(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
PWMInit();
}
/***************************************************************
* @brief void MotorSetSpeed(uint16_t speed)
* @param speed
* @note 调节直流电机转速和转向
* @Sample MotorSetSpeed(speed);
**************************************************************/
void MotorSetSpeed(int16_t speed)
{
if(speed>=0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
PwmSetCompare3(speed);
}
else
{
GPIO_SetBits(GPIOA,GPIO_Pin_5);
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
PwmSetCompare3(-speed);
}
}