1.输出比较简介

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

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

高级定时器的前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 ≥ CCR 时,REF置无效电平

向下计数:CNT > CCR 时,REF置无效电平,CNT ≤ CCR 时,REF置有效电平

      PWM模式2

向上计数:CNT < CCR 时,REF置无效电平,CNT ≥ CCR 时,REF置有效电平

向下计数:CNT > CCR 时,REF置有效电平,CNT ≤ CCR 时,REF置无效电平

通用定时器 

d2a860407c184d399b257bd587ab2546.png 高级定时器

68cbf650f2e74b259223eafd0dd7107d.png

2.PWM简介

PWM 脉冲宽度调制

在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量

PWM参数

频率 = %20_%7BTs%7D                占空比 = %20_%7BTs%7D                分辨率 = 占空比变化步距

3896f9287a6e498baaf4c072b5b19875.png41e2d6a66bc94311af6e6c448f3cd9cc.png

3.PWM基本结构

7fcc390c8707465d90d9b8ff8fa03763.png

PWM频率 = 计数器更新频率:Freq = CK_PSC / ( PSC + 1 ) / ( ARR + 1 )

PWM占空比:Duty = CCR / ( ARR + 1 )

PWM分辨率:Reso = 1 / ( ARR + 1 )

4.相关标准库函数介绍

//配置输出比较模块
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);
//配置强制输出模式,如在运行中想要暂停输出波形并且输出高电平或者低电平
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);
//配置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);
//单独设置输出比较的极性,带N的是高级定时器互补通道的配置
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);

//单独修改输出使能参数
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);

//单独修改输出比较模式
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);

//单独更改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);
//仅高级定时器使用,在使用高级定时器输出PWM时,需要调用该函数使能主输出,否则PWM将不能正常输出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

5.案例

5.1PWM驱动LED呼吸灯

#include "stm32f10x.h"                  // Device header


void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);

	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	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_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);    //给成员赋初始值
    //未列出所有成员,有些成员只有在高级定时器时才用到
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;    //输出比较模式
    //极性选择,High表示REF有效时输出高电平
	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);
	
	TIM_Cmd(TIM2,ENABLE);

}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2,Compare);
}

 5.2PWM驱动舵机

PWM.c

#include "stm32f10x.h"                  // Device header


void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);

	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 20000-1;       //ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;     //PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&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 = 0;        //CCR
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	
	TIM_Cmd(TIM2,ENABLE);

}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2,Compare);
}

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"

void Servo_Init(void)
{
	PWM_Init();
}

void Servo_SetAngle(float angle)
{
	PWM_SetCompare2(angle / 180 * 2000 + 500);
}

main.c

#include "stm32f10x.h"    // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"


uint8_t KeyNum;
float angle;

int main(void)
{
	OLED_Init();
	Servo_Init();
	Key_Init();
	
	OLED_ShowString(1,1,"angle:");
	
	while(1)
	{
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			angle += 30;
			if(angle > 180)
			{
				angle = 0;
			}
		}
		Servo_SetAngle(angle);
		OLED_ShowNum(1,7,angle,3);
	}
}

5.3PWM驱动直流电机

PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		

	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //受外设控制的引脚,均需要配置为复用模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);			
	

	TIM_InternalClockConfig(TIM2);	

	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; 
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;                 //ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;               //PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器
	TIM_TimeBaseInit(TIM2, &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 = 0;								//CCR
	TIM_OC3Init(TIM2, &TIM_OCInitStructure);                    

	TIM_Cmd(TIM2, ENABLE);			
}

void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2, Compare);		//CCR3
}

Motor.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"


void Motor_Init(void)
{
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							
	
	PWM_Init();													
}

void Motor_SetSpeed(int8_t Speed)
{
	if (Speed >= 0)							
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_4);	
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);	
		PWM_SetCompare3(Speed);				//PWM设置为速度值
	}
	else									
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_4);	
		GPIO_SetBits(GPIOA, GPIO_Pin_5);	
		PWM_SetCompare3(-Speed);			//PWM设置为负的速度值,因为此时速度值为负数,而PWM只能给正数
	}
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"

uint8_t KeyNum;		
int8_t Speed;		

int main(void)
{
	
	OLED_Init();		
	Motor_Init();		
	Key_Init();			
	

	OLED_ShowString(1, 1, "Speed:");		
	
	while (1)
	{
		KeyNum = Key_GetNum();				
		if (KeyNum == 1)					
		{
			Speed += 20;					
			if (Speed > 100)				
			{
				Speed = -100;				
			}
		}
		Motor_SetSpeed(Speed);				
		OLED_ShowSignedNum(1, 7, Speed, 3);	
	}
}

作者:尘️

物联沃分享整理
物联沃-IOTWORD物联网 » STM32中TIM输出比较详解

发表回复