STM32-TIM定时器输出比较

目录

一、输出比较简介

二、PWM简介

三、输出比较通道(通用)

四、输出比较通道(高级)

五、输出比较模式

六、PWM基本结构 

七、PWM参数计算

八、外设介绍

8.1 舵机

8.2 直流电机及驱动

九、开发步骤

十、输出比较库函数 

十一、实验

9.1 PWM驱动LED呼吸灯

9.2 PWM驱动舵机

9.3 PWM驱动直流电机


一、输出比较简介

>OC(Output Compare)输出比较
>输出比较可以通过比较CNT与CCR(捕获/比较寄存器)值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
>每个高级定时器和通用定时器都拥有4个输出比较通道
>高级定时器的前3个通道额外拥有死区生成和互补输出的功能

二、PWM简介

>PWM(Pulse Width Modulation)脉冲宽度调制
>在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
>PWM参数:
  频率 = 1 / Ts           占空比 = Ton / Ts           分辨率 = 占空比变化步距
STM32-TIM定时器输出比较_第1张图片STM32-TIM定时器输出比较_第2张图片

三、输出比较通道(通用)

STM32-TIM定时器输出比较_第3张图片

四、输出比较通道(高级)

STM32-TIM定时器输出比较_第4张图片

五、输出比较模式

STM32-TIM定时器输出比较_第5张图片

六、PWM基本结构 

STM32-TIM定时器输出比较_第6张图片

七、PWM参数计算

STM32-TIM定时器输出比较_第7张图片

八、外设介绍

8.1 舵机

STM32-TIM定时器输出比较_第8张图片

STM32-TIM定时器输出比较_第9张图片

8.2 直流电机及驱动

STM32-TIM定时器输出比较_第10张图片

STM32-TIM定时器输出比较_第11张图片

九、开发步骤

①RCC打开时钟,TIM和GPIO外设的时钟打开

②配置时基单元,包括前面的时钟源选择

③结构体配置输出比较单元(CCR,输出比较模式,极性选择,输出使能)

④配置GPIO,PWM对应GPIO初始化为复用推挽输出

⑤运行控制,启动计数器

十、输出比较库函数 

注:标@的为重要,需掌握

@===================输出比较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_OCStructInit(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);

=======================配置快速使能(了解即可)==========================

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);

=======================外部事件清除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);

=======================单独设置输出比较极性=============================

void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);

//N高级定时器互补通道的配置
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);

==========================补充========================================

void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

//仅高级定时器使用,在使用高级定时器输出PWM时,需要调用这个函数,使能主输出,否则PWM将不能正常输出

十一、实验

9.1 PWM驱动LED呼吸灯

PWM.c

#include "stm32f10x.h"                  // Device header

/*PWM初始化*/
void PWM_Init(void)
{
	/*一、RCC开启时钟,TIM与GPIO时钟打开*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
//	/*使用重映射(*_*)*/
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//PA0->PA15,部分重映射S
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//解除JATG调试
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//(*_*)GPIO_Pin_15
	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 = 720 - 1;	//PSC预分频器值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器值
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	/*三、配置输出比较单元(CCR的值(捕获/比较器),输出比较模式,极性选择,输出使能)*/
	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_OC1Init(TIM2,&TIM_OCInitStructure);
	
	/*四、配置GPIO,复用推挽输出*/
	//一处已操作
	
	/*五、运行控制,启动计数器CNT*/
	TIM_Cmd(TIM2,ENABLE);
}
	
/*封装函数->更改CCR值来改变占空比*/
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2,Compare);
}

PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);

#endif

main.c

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

uint8_t i;

int main(void)
{
	OLED_Init();
	PWM_Init();
	
	while (1)
	{
		//CCR增大,逐渐变亮
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(i);
			Delay_ms(10);
		}
		//CCR减小,逐渐变暗
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(100 - i);
			Delay_ms(10);
		}
	}
}

9.2 PWM驱动舵机

实验现象:按下按键,舵机转动固定角度

PWM.c

#include "stm32f10x.h"                  // Device header

/*PWM初始化*/
void PWM_Init(void)
{
	/*一、RCC开启时钟,TIM与GPIO时钟打开*/
	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_1;
	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 = 20000 - 1;		//ARR自动重装器值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;	//PSC预分频器值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器值
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	/*三、配置输出比较单元(CCR的值(捕获/比较器),输出比较模式,极性选择,输出使能)*/
	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(500~2500)
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	
	/*四、配置GPIO,复用推挽输出*/
	//一处已操作
	
	/*五、运行控制,启动计数器CNT*/
	TIM_Cmd(TIM2,ENABLE);
}
	
/*封装函数->更改CCR值来改变占空比*/
void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2,Compare);
}

PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare2(uint16_t Compare);

#endif

Servo.c

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

//舵机初始化(PWM初始化)
void Servo_Init(void)
{
	PWM_Init();
}

/*
舵机设置角度
角度:0-180
CCR:500-2500
*/
void Servo_SetAngle(float Angle)
{
	PWM_SetCompare2(Angle / 180 * 2000 + 500);
}

Servo.h

#ifndef __SERVO_H
#define __SERVO_H

void Servo_Init(void);
void Servo_SetAngle(float Angle);

#endif

Key.c

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

//===按键初始化===//
void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}

//===获取按键返回码===//
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
	{
		Delay_ms(20);//消抖
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0);//如果不松手则卡着
		Delay_ms(20);
		KeyNum = 1;
	}	
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0)
	{
		Delay_ms(20);//消抖
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0);
		Delay_ms(20);
		KeyNum = 2;
	}
	return KeyNum;
}

key.h

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);
	
#endif

main.c

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

uint8_t KeyNum;
float Angle;

int main(void)
{
	OLED_Init();
	Key_Init();
	Servo_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);
	}
}

*OLED显示屏代码请参考本专栏文章STM32-OLED显示屏

9.3 PWM驱动直流电机

实验现象: 按键按下,电机加速,达到最大转速时,再按一下,最大速度反转,按下按键,电机减速

PWM.c

#include "stm32f10x.h"                  // Device header

/*PWM初始化*/
void PWM_Init(void)
{
	/*一、RCC开启时钟,TIM与GPIO时钟打开*/
	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);
	
	/*三、配置输出比较单元(CCR的值(捕获/比较器),输出比较模式,极性选择,输出使能)*/
	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);
	
	/*四、配置GPIO,复用推挽输出*/
	//一处已操作
	
	/*五、运行控制,启动计数器CNT*/
	TIM_Cmd(TIM2,ENABLE);
}
	
/*封装函数->更改CCR值来改变占空比*/
void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2,Compare);
}

PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare3(uint16_t Compare);

#endif

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();
}

/*设置电机速度(-100~100)*/
void Motor_SetSpeed(int8_t Speed)
{
	if(Speed >= 0)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_4);
		GPIO_ResetBits(GPIOA,GPIO_Pin_5);
		PWM_SetCompare3(Speed);
	}
	else
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_5);
		GPIO_ResetBits(GPIOA,GPIO_Pin_4);
		PWM_SetCompare3(-Speed);
	}
}

Motor.h

#ifndef __PWM_H
#define __PWM_H

void Motor_Init(void);
void Motor_SetSpeed(int8_t Speed);

#endif

*按键与OLED显示屏的代码参考之前实验代码

你可能感兴趣的:(STM32,stm32,嵌入式硬件,单片机)