学习笔记:STM32 OC输出比较(PWM)详解
一、输出比较简介
1.1 输出比较功能
OC(Output Compare)输出比较
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置O或翻转的操作,用于输出一定频率和占空比的PWM波形
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
1.2 输出比较结构
触发控制器选择时钟源后传递到定时器的TIMx的时基单元,将预分频信号传递到计数器,计数器比较寄存器比较后输出指定电平,自动重装载计数器载CNT达到一定条件后装载初值
1.2 输出比较计算
PWM参数:频率={\frac{1}{T_S}},占空比={\frac{T_{ON}}{T_S}},分辨率=占空比变化的步距
PWM频率:Freq=CK_PSC/(PSC+1)/(ARR+1)
PWM占空比:Duty=CCR/(ARR+1)
PWM分辨率:Rese=1/(ARR+1)
CK_PSC为预分频时钟频率,PSC为预分频数,ARR为重载计数值,CCR为计数比较值
1.3 输出比较模式
模式 | 描述 |
---|---|
冻结 | CNT=CCR时,REF保持为原状态 |
匹配时置有效电平 | CNT=CCR时,REF置有效有效电平 |
匹配时置无效电平 | CNT=CCR时,REF置无效电平 |
匹配时电平翻转 | CNT与CCR时,REF电平翻转 |
强制为无效电平 | CNT与CCR无效,REF强制为无效电平 |
强制为有效电平 | CNT与CCR无效,REF强制为有效电平 |
PWM模式1 | 向上计数:CNT<CCR时,REF置有效电平,CNT>=CRR时,REF置无效电平;向下计数:CNT>CCR时,REF置无效电平,CNT<=CRR时,REF置有效电平 |
PWM模式2 | 向上计数:CNT<CCR时,REF置无效电平,CNT>=CRR时,REF置有效电平;向下计数:CNT>CCR时,REF置有效电平,CNT<=CRR时,REF置无效电平 |
二、输出比较函数
2.1 输出比较单元结构体
创建输出比较单元结构体
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
输出比较单元结构体变量
typedef struct
{
uint16_t TIM_OCMode; /*!< Specifies the TIM mode.
This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */
uint16_t TIM_OutputState; /*!< Specifies the TIM Output Compare state.
This parameter can be a value of @ref TIM_Output_Compare_state */
uint16_t TIM_OutputNState; /*!< Specifies the TIM complementary Output Compare state.
This parameter can be a value of @ref TIM_Output_Compare_N_state
@note This parameter is valid only for TIM1 and TIM8. */
uint16_t TIM_Pulse; /*!< Specifies the pulse value to be loaded into the Capture Compare Register.
This parameter can be a number between 0x0000 and 0xFFFF */
uint16_t TIM_OCPolarity; /*!< Specifies the output polarity.
This parameter can be a value of @ref TIM_Output_Compare_Polarity */
uint16_t TIM_OCNPolarity; /*!< Specifies the complementary output polarity.
This parameter can be a value of @ref TIM_Output_Compare_N_Polarity
@note This parameter is valid only for TIM1 and TIM8. */
uint16_t TIM_OCIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state.
This parameter can be a value of @ref TIM_Output_Compare_Idle_State
@note This parameter is valid only for TIM1 and TIM8. */
uint16_t TIM_OCNIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state.
This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State
@note This parameter is valid only for TIM1 and TIM8. */
} TIM_OCInitTypeDef;
TIM_OCMode:输出比较模式
参数 | 作用 |
---|---|
TIM_OCMode_Timing | 冻结模式 |
TIM_OCMode_Active | 匹配时置有效电平 |
TIM_OCMode_Inactive | 匹配时置无效电平 |
TIM_OCMode_Toggle | 匹配时电平翻转 |
TIM_OCMode_PWM1 | PWM模式1 |
TIM_OCMode_PWM2 | PWM模式2 |
TIM_OutputState:输出比较状态
参数 | 作用 |
---|---|
TIM_OutputState_Disable | 失能 |
TIM_OutputState_Enable | 使能 |
TIM_OCPolarity:输出比较极性
参数 | 作用 |
---|---|
TIM_OCPolarity_High | 高极性,有效电平是高电平 |
TIM_OCPolarity_Low | 低极性,有效电平是低电平 |
TIM_Pulse:脉冲值,CCR寄存器的值,0x0000~0xFFFF
最后比较输出通道初始化
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
2.2 输出比较单元初始化
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
TIMx为定时器,TIM_OCInitStruct为输出比较单元结构体变量
2.2 输出比较默认初始化
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
将TIM_OCInitStruct变量按默认初始化
2.3 强制输出模式
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
强制输出电平
2.4 输出比较寄存器预装
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
2.6 配置输出比较通道极性
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
2.7 配置输出比较互补通道极性
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
2.8 修改输出比较模式
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
2.9 修改输出比较寄存器值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare);
修改指定定时器TIMx的通道1CH1的输出比较值,如果要修改其他通道的输出比较值可用
TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t compare);
TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t compare);
TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t compare);
一个通用定时器可同时输出4路相同频率、不同占空比的PWM
2.10 使能PWM主输出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
仅高级定时器使用
三、输出比较程序
3.1 开启时钟总线
开启定时器TIM4、GPIOB端口和复用IO的时钟总线
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
3.2 GPIO初始化
根据数据手册查看定时器复用引脚,需要采用复用推挽输出
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
3.3 配置TIM定时器
为定时器TIM4选择内部时钟
TIM_InternalClockConfig(TIM4);
设置定时器TIM4的时基单元,选择时基单元预分频值为720,内部时钟单元频率为72MHz,预分频后为100KHz,选择计数周期(值)为100,输出比较频率为1KHz
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期(值)
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
使用时基单元结构体给TIM4初始化
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
3.4 配置OC单元
输出比较单元输出模式为PWM1模式,输出有效极性为高电平,输出状态为使能,输出比较值为50,意味当TIM计数器值大于50时输出高电平,小于50时输出低电平,由于计数周期为100,所以占空比为50%
TIM_OCInitTypeDef TIM_OCInitStructure;
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;
OC单元结构体初始化
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
开启TIM使能
TIM_Cmd(TIM4, ENABLE);
3.5 例程
该例程可以使GPIOB的GPIO_Pin_6输出占空比为50%,如需修改占空比则可以使用TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)函数修改
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM4);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
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;
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
TIM_Cmd(TIM4, ENABLE);