STM32学习记录-05 -2-TIM输出比较

1 输出比较简介

OC(Output Compare)输出比较

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

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

高级定时器的前3个通道额外拥有死区生成和互补输出的功能

2 PWM简介

PWM(Pulse Width Modulation)脉冲宽度调制

在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域

PWM参数:

     频率 = 1 / TS            占空比 = TON / TS           分辨率 = 占空比变化步距

3 输出比较模式(输出模式控制器)

4 输出比较通道(通用)

左边为CNT计数器和CCR1第一路的捕获/比较寄存器进行比较,当CNT>CCR1或CNT=CCR1时,给输出模式控制器传一个信号后会改变输出oc1ref的高低电平(ref就是指信号的高低电平reference参考信号),上面的ETRF输入为定时器的小功能。ref信号可以前往主模式控制器映射到主模式的TRGO输出。下面一路进行极性选择,寄存器写0信号往上走即电平不翻转,写1信号往下走进行非门取反,然后输出使能电路选择是否输出,最后到OC1引脚即CH1通道引脚。

输出模式控制器:输入CNT和CCR的大小关系,输出ref高低电平

5 输出比较通道(高级)

左边和上方部分与通用定时器电路一样。右边OC1和OC1N外面通常接推挽电路(上管导通下管断开输出高电平,下管导通上管断开输出低电平,上下管都导通短路不允许,上下管都断开高阻态),OC1和OC1N为两个互补的输出端口控制上下管导通和关闭,在控制上下管状态时如果上管关闭瞬间下管立刻打开(由于硬件误差导致时间差),为了避免误差就有死区生成电路(上/下管关闭时延迟一段时间再导通下/上管,避免上下管同时导通的现象)

6 PWM基本结构

左边为时基单元和运行控制部分,再左边为时钟源选择(省略),配置好时基单元,CNT就可以自增运行。下面为输出比较单元(共4路),首先为CCR捕获/比较器,不断进行比较,后面的为输出模式控制器(右上角坐标图蓝色为CNT,黄色为ARR,红色为CCR,绿色为输出),有效电平为高电平,无效电平为低电平(输出占空比由CCR控制,CCR值高占空比大,CCR值低占空比小)。REF为频率可调,占空比也可调的PWM波形,最终经过极性选择,输出使能,最后通过GPIO口。

7 参数计算

8 PWM模块

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

                //四个为配置输出比较模块,OC为Output Compare 输出比较,参数为(TIMx选择定时器,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_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);

                //配置CCR预装功能,影子寄存器

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

                //配置快速使能

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

                //外部事件清除REF信号

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

                //单独设置输出比较极性,NPolarityConfig高级定时器里互补通道的配置

                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);//选择输出比较模式

                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_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

                //使用高级定时器输出PWM需要调用函数使能主输出

        PWM初始化

        (1)RCC开启时钟,打开要用的TIM外设和GPIO外设

                RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

        (2)配置时基单元,包括时钟源选择

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

        (3)配置输出比较单元(CCR值、输出比较模式、极性选择、输出使能)

                TIM_OCInitTypeDef TIM_OCInitStruct;

                TIM_OCStructInit(&TIM_OCInitStruct);//用此函数先全部赋初始值再改要用的

                TIM_OCInitStruct.TIM_OCMode = ;

                        TIM_OCMode_Timing 冻结模式

                        TIM_OCMode_Active相等置有效电平

                        TIM_OCMode_Inactive相等置无效电平

                        TIM_OCMode_Toggle相等电平翻转

                        TIM_OCMode_PWM1 模式1,TIM_OCMode_PWM2模式2

                        TIM_ForcedAction_Active,TIM_ForcedAction_InActive两种强制输出

                TIM_OCInitStruct.TIM_OCPolarity = ;

                        TIM_OCPolarity_High 高极性,REF有效时输出高电平

                        TIM_OCPolarity_Low 低极性,有效电平为低电平

                TIM_OCInitStruct.TIM_OutputState = ;

                        TIM_OutputState_Disable 失能,TIM_OutputState_Enable 使能

                TIM_OCInitStruct.TIM_Pulse = 50;//设置CCR寄存器值

                TIM_OC1Init(TIM2, &TIM_OCInitStruct);

        /*参数计算(频率1KHz,占空比50%)

        PWM频率:        Freq = CK_PSC / (PSC + 1) / (ARR + 1) =72M/720/100=1000

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

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

        */

        (4)配置GPIO,初始化为复用推挽输出

                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

                GPIO_InitTypeDef GPIO_InitStructure;

                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出

                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

                GPIO_Init(GPIOA, &GPIO_InitStructure);

        //若想使用AFIO引脚重映射

                RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

                GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);

                GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

                解除调试端口复用

                GPIO_Remap_SWJ_NoJTRST 解除JTRST调试端口(PB4引脚)

                GPIO_Remap_SWJ_JTAGDisable 解除JTAG调试端口(PA15、PB3、PB4)

                GPIO_Remap_SWJ_Disable 解除全部SWD和JTAG端口(PA13-15、PB3-4)

        (5)运行控制,启动计数器

                TIM_Cmd(TIM2, ENABLE);

1 舵机简介

舵机是一种根据输入PWM信号占空比来控制输出角度的装置

输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms

2 硬件电路

黑色电源负极GND,红色电源正极+5V,黄色PWM信号线

1 直流电机及驱动简介

直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转

直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作

TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向

2 硬件电路

左下角VM为电机电源正极(接大电流电源,和舵机电源保持一致)。VCC逻辑电平输入端(和控制器电源保持一致,如STM32为3.3V)。AO1、AO2、BO1、BO2为两路电机输出,分别接两个电机。PWMA、AIN2、AIN1(控制AO1、AO2)直接接到GPIO口,PWMA要接PWM信号输出端。STBY待机控制引脚,接GND芯片处于待机状态不工作,接逻辑电源VCC芯片正常工作(需要待机模式可接到GPIO口给高低电平控制)。

程序源码

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

/**
  * 函    数:PWM初始化
  * 参    数:无
  * 返 回 值:无
  */
void PWM_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	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);							//将PA1引脚初始化为复用推挽输出	
																	//受外设控制的引脚,均需要配置为复用模式
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	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_TimeBaseInit,配置TIM2的时基单元
	
	/*输出比较初始化*/ 
	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量
	TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值
	                                                                //则最好执行此函数,给结构体所有成员都赋一个默认值
	                                                                //避免结构体初值不确定的问题
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1
	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_OC2Init,配置TIM2的输出比较通道2
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}

/**
  * 函    数:PWM设置CCR
  * 参    数:Compare 要写入的CCR的值,范围:0~100
  * 返 回 值:无
  * 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
  *           占空比Duty = CCR / (ARR + 1)
  */
void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2, Compare);		//设置CCR2的值
}
Servo.c
#include "stm32f10x.h"                  // Device header
#include "PWM.h"

/**
  * 函    数:舵机初始化
  * 参    数:无
  * 返 回 值:无
  */
void Servo_Init(void)
{
	PWM_Init();									//初始化舵机的底层PWM
}

/**
  * 函    数:舵机设置角度
  * 参    数:Angle 要设置的舵机角度,范围:0~180
  * 返 回 值:无
  */
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();		//OLED初始化
	Servo_Init();		//舵机初始化
	Key_Init();			//按键初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Angle:");	//1行1列显示字符串Angle:
	
	while (1)
	{
		KeyNum = Key_GetNum();			//获取按键键码
		if (KeyNum == 1)				//按键1按下
		{
			Angle += 30;				//角度变量自增30
			if (Angle > 180)			//角度变量超过180后
			{
				Angle = 0;				//角度变量归零
			}
		}
		Servo_SetAngle(Angle);			//设置舵机的角度为角度变量
		OLED_ShowNum(1, 7, Angle, 3);	//OLED显示角度变量
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值