江科大STM32学习笔记——TIM输出比较

输出比较(Output Compare)

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

 

 PWM波形

 

例:以一个很快的频率让电机通、断、通、断电,那么电机就能都呈现出一个中等速度。

  • 占空比决定了PWM等效出的模拟电压的大小,占空比越高,模拟电压越接近高电压输出。
  • 分辨率就是占空比变化的精细程度

输出比较通道

当CNT计数器和CCR1第一路的捕获/比较寄存器进行比较,当CNT>/=CCR1时,输出模式控制器收到信号,然后改变输出oc1ref信号的高低电平。

然后这个信号一路到主模式控制器去(可以映射到TRGO输出上)

一路通过极性选择电路经过输出使能电路,最后输出到OC1引脚。

可以通过TIMx_CCER寄存器的值来决定是否将oc1ref输出的信号翻转。

输出比较模式

1. 冻结可以用于要暂停一段时间的输出情况

2.匹配时置有/无效电平:可以理解为高/低电平,用于一次性输出,不适合连续波形。

3.输出占空比50%的PWM波形

4.强制:可以用于暂停期间需要保持高/低电平

5.PWM模式1/2主要是极性的区别。可以就选模式1。

参数计算

外接设备(舵机和电机)

给个PWM,输出轴就会固定在一个角度。

上面红色三个引脚控制下面AO的电机,PWMA接PWM输出,而IN引脚可以接GPIO输出,给一个低功率控制信号就能控制电机转动。

输入与输出状态对应关系如右下角所示。

如当IN1置低,IN2置高,PWM为高电平则电机翻转,低电平则电机不转。

代码

1. PWM驱动呼吸灯

OLED部分与之前一样接,灯正极接PA0,负极接GND。

首先初始化PWM,即把输出比较模块打通。

//配置输出比较单元的函数
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);

//单独数值输出比歼的极性(单独修改输出极性)
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);

//以下不常用
//配置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);

//在使用高级定时器时,需调用使能主输出,否则PWM不能正常输出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

1. RCC开启时钟,把要用的TIM外设和GPIO口的时钟打开

2. 配置时基单元,包括时钟源选择。

3. 配置输出比较单元,包括输出比较模式、极性选择、输出使能

4. 配置GPIO,把PWM输出对应的GPIO口初始化为复用推挽输出

查看引脚定义,TIM2的通道1和ETR复用在了PA0端口上。

5. 运行控制,启动计数器输出PWM

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)
	{
		for(i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(i);
			Delay_ms(10);
		}
		for(i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(100 - i);
			Delay_ms(10);
		}			
	}	
	
}

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_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽,将引脚控制权交与片上外设
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	//配置TIM,时基单元
	TIM_InternalClockConfig(TIM2);
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	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;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	//初始化输出比较
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//输出模式PWM1
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//高极性
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//
	TIM_OCInitStruct.TIM_Pulse = 0;	//CCR的值
	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
	
}

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

2. PWM驱动舵机

根据舵机所需高电平时间及相应公式计算出各个寄存器的值。

	TIM_TimeBaseInitStruct.TIM_Period = 2000-1;		//ARR的值		
	TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;	//PSC的值

	TIM_OCInitStruct.TIM_Pulse = 0;	//CCR的值

CCR:500->0°,2500->180°,根据线性关系可计算。

//main.c

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

uint8_t i;
float Angle;

int main(void)
{
	OLED_Init();
	Servo_Init();
	
	Servo_SetAngle(90);
	OLED_ShowString(1,1,"Angle:");
	while(1)
	{
		
		Angle += 30;
		if(Angle > 180)
			Angle = 0;
		Delay_s(5);
		Servo_SetAngle(Angle);
		OLED_ShowNum(2,1,Angle,7);
	}	
	
}

#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_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽,将引脚控制权交与片上外设
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	//配置TIM,时基单元
	TIM_InternalClockConfig(TIM2);
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;	
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 2000-1;		//ARR的值		
	TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;	//PSC的值	
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	//初始化输出比较
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//输出模式PWM1
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//高极性
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//
	TIM_OCInitStruct.TIM_Pulse = 0;	//CCR的值
	TIM_OC2Init(TIM2,&TIM_OCInitStruct);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
	
}

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

3.  PWM驱动电机

TB6612硬件电路如下,根据引脚定义接线。

 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_Pin = GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	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);
	}
	else
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_4);
		GPIO_SetBits(GPIOA,GPIO_Pin_5);
		PWM_SetCompare3(-Speed);
	}
	
}

 main.c

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

uint8_t i;
float Angle;

int main(void)
{
	OLED_Init();
	Motor_Init();
	
	Motor_SetSpeed(-50);
	while(1)
	{

	}	
	
}

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值