学习STM32第六天

本文详细解释了TIM(高级定时器和通用定时器)的输出比较机制,包括不同模式下的工作原理,以及如何通过PWM控制LED呼吸灯、舵机和直流电机。文章还提供了实验案例和代码示例,展示了如何配置定时器以实现各种设备的精确控制。
摘要由CSDN通过智能技术生成

TIM基础

1、TIM输出比较

输出比较可以通过比较CNT和CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作
用于输出一定频率和占空比的PWM波
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出功能
PWM即脉冲宽度调制,其中“分辨率”这一参数指占空比变化的步距

  1. 通用定时器输出比较通道
    通用定时器输出比较通道
    通过CNT与CCR寄存器值的比较,输出模式控制器会改变其输出OC1REF(REF)的高低电平,然后由TIMx_CCER选择器对其选择,最后驱动输出使能电路。输出模式可以设置极性最终输出之前也可以设置极性。其中输出比较模式有以下情况,通过TIMx_CCMR寄存器进行配置
    输出比较模式
  • 冻结
    CNT=CCR时,REF保持上一个状态,可起到暂停输出的功能
  • 匹配时置有效电平
    置高电平
  • 匹配时置无效电平
    置低电平
  • 匹配时电平翻转
    电平翻转
  • 强制为无效电平
    功能同冻结,起到锁定的作用
  • 强制为有效电平
    同上
  • PWM模式1
  1. 向上计数
    C N T < C C R CNT < CCR CNT<CCR时,REF置有效电平; C N T ≥ C C R CNT \ge CCR CNTCCR时,REF置无效电平
  2. 向下计数
    C N T > C C R CNT > CCR CNT>CCR时,REF置有效电平; C N T ≤ C C R CNT \le CCR CNTCCR时,REF置无效电平
  • PWM模式2
  1. 向上计数
    C N T < C C R CNT < CCR CNT<CCR时,REF置无效电平; C N T ≥ C C R CNT \ge CCR CNTCCR时,REF置有效电平
  2. 向下计数
    C N T > C C R CNT > CCR CNT>CCR时,REF置无效电平; C N T ≤ C C R CNT \le CCR CNTCCR时,REF置有效电平

一般向上计数用得多,PWM模式1和PWM模式2原理相同,就是极性相反。PWM基本结构如下
PWM基本结构
由图可知,配置完时基单元后,CNT开始不断自增运行,然后进入CCR捕获/比较器。共有四路输出比较单元,其中CCR可自己设置。这里选择的是PWM模式1,具体PWM波产生如右上,其中蓝色是CNT,黄色是ARR,红色就是CCR。CNT小于CCR时,输出高电平;CNT大于CCR时,输出低电平。CCR可控制PWM占空比。REF然后进入极性选择输出使能,最后通向GPIO。PWM参数计算如下
PWM参数计算
其中PWM波频率即为CNT计数频率,并且需要满足CCR要小于ARR,ARR越大那么CCR变化的范围就越大,对应的分辨率就越大。这里记住50Hz 就是周期为 20ms

  1. 高级定时器输出比较通道
    高级定时器输出比较通道
    图中输出使能电路的输出OC1和OC1N是两个互补的输出端口,分别控制外部上下两路大功率MOS管(一般是电机驱动模块)。死区发生器是为了杜绝上下两路MOS管同时导通而造成器件发热的现象,即一个MOS关闭的时候,通过延迟一小段时间,再导通另外一个MOS管,从而达到互补输出的效果。

二、实验案例

  1. PWM驱动LED呼吸灯
    本实验案例旨在驱动一个GPIO端口的LED实现呼吸灯效果,实现流程大致如下
    /*
    RCC开启TIM外设和GPIO时钟
    配置时基单元
    配置输出比较单元
    配置GPIO
    运行控制
    */
    其中函数TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct)给输出比较单元配置默认值,使用此函数可避免对非必要成员赋值。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//TIM2_CH1的引脚可复用在PA0
	//具体引脚配置应根据数据手册配置
	
//	//TIM2还可重映射到PA15引脚上
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);//将TIM2重映射
//	//由于PA15引脚上电默认复用为了调试端口,需要关闭调试端口复用
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	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);//使用内部时钟
	//这里时基单元配置,CNT计数周期T = 1/1000,ARR = 99
	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_ClearFlag(TIM2, TIM_FLAG_Update);								//清除更新中断标志位
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);							//开启中断到NVIC的通路
	
	//配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);						//第二种分组方式
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	//配置输出比较单元OC
	//由于这里使用的通用定时器,只需配置必需的即可
	//结构体其他的成员赋值0即可,所有成员都必须赋值
	//或者使用函数TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct)
	//就可以只需配置通用定时器的参数
	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_OutputNState_Enable;//输出状态,即输出使能
	//设置捕获比较寄存器值,是16位的范围,上面设置的ARR = 99,分辨率为0.01
	//PWM频率 = CNT频率 = 1000
	TIM_OCInitStructure.TIM_Pulse = 0;//CCR值,用于控制占空比
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);//由于是通道1,这里使用函数TIM_OC1Init()
	
	TIM_Cmd(TIM2, ENABLE);
//为实现呼吸灯效果,就需要不断改变CCR
void PWM_SetComparel(uint8_t Compare)
{	//设置捕获比较器1寄存器的值
	//输出比较单元有4个,即有4个通道
	//PA0在CH1通道,所以这里使用函数TIM_SetCompare1();
	TIM_SetCompare1(TIM2, Compare);
}
  1. PWM驱动舵机
    舵机是一种根据输入PWM信号占空比来控制输出角度的装置。输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms。这里给出江协科舵机资料图片
    PWM舵机
//选择通用定时器TIM2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//输出引脚为PA1
	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);//内部时钟TIM2
	//要求舵机周期为20ms,则频率为50Hz
	//配置时基单元,CNT频率 = 72000000/(72*20000)
	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);
	
	//配置输出比较单元OC
	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,对应0.5ms~2.5ms,对应着舵机的0~180度
	//如果使用多路PWM输出,则需增加相应的初始化代码即可
	//占空比由各自CCR决定,但是他们的相位同步
//	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);
//	TIM_OC3Init(TIM2, &TIM_OCInitStructure);
//	TIM_OC4Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
void PWM_SetCompare2(uint16_t Compare)
{
	//PA1在TIM2_CH2通道,这里使用函数TIM_SetCompare2()
	TIM_SetCompare2(TIM2, Compare);
}

//设置舵机角度
//定时器 ARR + 1 = 20000
//设置CCR = 500 时对应0度,CCR = 2500 时对应180度
void Servo_SetAngle(float Angle)
{	//对Angle进行缩放加偏移转换为CCR
	PWM_SetCompare2(Angle / 180 * 2000 + 500);
}

  1. PWM驱动直流电机
    直流电机由电机驱动进行操作,江协科课程中采用TB6612双路直流电机驱动芯片,引脚说明如下
    PWM直流电机驱动
    主要代码如下
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	//这里使用TIM2的3通道
	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;
	//这里给出的PWM频率为20KHz
	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);
	//赋值CCR3,即设置占空比
void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2, Compare);
}

//通过PA4和PA5控制电机正反转
	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)
	{
		//通过PA4控制正转
		GPIO_SetBits(GPIOA, GPIO_Pin_4);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
		PWM_SetCompare3(Speed);
	}
	else
	{
		//通过PA5控制反转
		GPIO_ResetBits(GPIOA, GPIO_Pin_4);
		GPIO_SetBits(GPIOA, GPIO_Pin_5);
		PWM_SetCompare3(-Speed);
	}
}
  • 36
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值