STM32学习(三)通用定时器及PWM驱动直流电机实验

(一)TIM通用定时器

在本节的学习中,涉及的知识点很多,大家可以搭配《STM32F10X-中文参考手册》来看,尤其是寄存器说明的部分,希望能对大家有所帮助。

1.定时器分类

STM32F1 系列中,除了互联型的产品,共有 8个定时器,分为基本定时器,通用定时器和高级定时器。 基本定时器 TIM6 和 TIM7 是一个 16位的只能向上计数的定时器,只能定时,没有外部 IO。 通用定时器 TIM2/3/4/5是一个 16位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉, 每个定时器有四个外部IO。高级定时器 TIM1/8是一个 16位的可以向上/下计数的定时器,可以定时,可以输出比较, 可以输入捕捉,还可以有三相无刷电机互补输出信号,每个定时器有8 个外部 IO。  

2.通用定时器功能框图

通用定时器功能框图包含了通用定时器最核心内容,掌握了功能框图,对通用定时器就有一个整体的把握,在编程时思路就非常清晰。图中有些寄存 器是带影子的,表示其有影子寄存器。 

3.通用定时器功能描述 

通用定时器功能复杂,包括TIMx (TIM2、TIM3、TIM4和TIM5),我们将根据通用定时器功能框图,徐徐展开对通用定时器的学习。

3.1时基单元(图中部分1)

可编程通用定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数器可 以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。 计数器、自动装载寄存器和预分频器寄存器可以由软件读写,在计数器运行时仍可以读写。

时基单元包含:

● 计数器寄存器(TIMx_CNT)

● 预分频器寄存器 (TIMx_PSC)

● 自动装载寄存器 (TIMx_ARR)

自动装载寄存器是预先装载的,写或读自动重装载寄存器将访问预装载寄存器。计数器由预分频器的时钟输出CK_CNT驱动,仅当设置了计数器TIMx_CR1寄存器中的计数器使 能位(CEN)时,CK_CNT才有效。

3.1.1预分频器(PSC):

预分频器可以将计数器的时钟频率按1到65536之间的任意值分频。它是基于一个(在TIMx_PSC 寄存器中的)16位寄存器控制的16位计数器。这个控制寄存器带有缓冲器,它能够在工作时被改变。新的预分频器参数在下一次更新事件到来时被采用。有一个输入时钟CK_PSC和一个输出时钟CK_CNT。输入时钟CK_PSC就是上面时钟源的输出,输出CK_CNT则用来驱动计数器CNT计数。 通过设置预分频器PSC的值可以得到不同的CK_CNT, 实际计算为:fCK_CNT=fCK_PSC/(PSC[15:0]+1),可以实现1至65536分频。(加1是因为计数从0开始)

3.1.2计数器模式(CNT)

(1) 递增计数模式下,计数器从0开始计数,每来一个CK_CNT脉冲计数器就增加1,直到计数器的值与自动重载寄存器ARR值相等, 然后计数器又从0开始计数并生成计数器上溢事件,计数器总是如此循环计数。如果禁用重复计数器,在计数器生成上溢事件就马上生成更新事件(UEV); 如果使能重复计数器,每生成一次上溢事件重复计数器内容就减1,直到重复计数器内容为0时才会生成更新事件。

(2) 递减计数模式下,计数器从自动重载寄存器ARR值开始计数,每来一个CK_CNT脉冲计数器就减1,直到计数器值为0, 然后计数器又从自动重载寄存器ARR值开始递减计数并生成计数器下溢事件,计数器总是如此循环计数。如果禁用重复计数器, 在计数器生成下溢事件就马上生成更新事件;如果使能重复计数器,每生成一次下溢事件重复计数器内容就减1,直到重复计数器内容为0时才会生成更新事件。

(3) 中心对齐模式下,计数器从0开始递增计数,直到计数值等于(ARR-1)值生成计数器上溢事件, 然后从ARR值开始递减计数直到1生成计数器下溢事件。然后又从0开始计数,如此循环。每次发生计数器上溢和下溢事件都会生成更新事件。

3.1.3自动重载寄存器(ARR)

自动重载寄存器ARR用来存放与计数器CNT比较的值,如果两个值相等就递减重复计数器。可以通过TIMx_CR1寄存器的ARPE位控制自动重载影子寄存器功能, 如果ARPE位置1,自动重载影子寄存器有效,只有在事件更新时才把TIMx_ARR值赋给影子寄存器。如果ARPE位为0,则修改TIMx_ARR值马上有效。

3.1.4实际单元初始化程序
	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_TimeBaseInit,配置TIM2的时基单元

 (1)时钟分频配置

(2)计数模式

 (3)预分频设置(PSC)

3.2输入捕获

输入捕获可以对输入的信号的上升沿、下降沿或者双边沿进行捕获,常用的有测量输入信号的脉宽,和测量PWM输入信号的频率占空比这两种。

输入捕获的大概的原理就是,当捕获到信号的跳变沿的时候,把计数器CNT的值存到捕获寄存器CCR中,把前后两次捕获到的CCR寄存器中的值相减, 就可以算出脉宽或者频率。

3.2.1输入通道 

信号需要从定时器的外部引脚TIMx_CH1/2/3/4输入。

3.2.2输入滤波器和边沿检测器

输入滤波器可以过滤掉信号的抖动干扰,当存在干扰时我们需要对输入信号进行重新采样,根据取样定律,需要采样频率大于2倍的输入信号的频率。

滤波器的配置由CR1寄存器的位CKD[1:0]和CCMR1/2的位ICxF[3:0]控制。从ICxF位的描述可知, 采样频率fSAMPLE可以由fCK_INT和fDTS分频后的时钟提供, 其中是fCK_INT内部时钟,fDTS是fCK_INT经过分频后得到的频率, 分频因子由CKD[1:0]决定,可以是不分频,2分频或者是4分频。

边沿检测器用来设置信号在捕获的时候是什么边沿有效,可以是上升沿,下降沿,或者是双边沿,具体的由CCER寄存器的位CCxP和CCxNP决定。

3.2.3捕获通道

捕获通道就是图中的IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器CCR1/2/3/4,当发生捕获的时候,计数器CNT的值就会被锁存到捕获寄存器中。

根据上图我们可以发现,每一个输入通道的信号都可以输入给两个输出通道。例如输入通道TIMx_CH1的信号通过TI1FP1和TI1FP2可以进入到捕获通道IC1和IC2。这就是我们将会介绍的PWM捕获。输入通道和捕获通道的映射关系具体由寄存器CCMRx的位CCxS[1:0]配置。

3.3输出比较

输出比较就是通过定时器的外部引脚对外输出控制信号,有冻结、将通道设置为匹配时输出有效电平、 将通道设置为匹配时输出无效电平、翻转、强制变为无效电平、强制变为有效电平、PWM1和PWM2这八种模式。其中PWM使用的最多。

在初始化输出比较单元时,我们需要根据GPIO口选择输出比较通道,具体的对应关系和重映射可以查表了解。

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

在高级定时器中还有死区设置,一般通用定时器也够用了,这里我们就不再介绍了。

(二)PWM实验

1.PWM输入模式

PWM输入模式是输入捕获的特例,只能使用通道1和通道2,需要占用两个捕获寄存器。

当使用PWM输入模式的时候,因为一个输入通道(TIx)会占用两个捕获通道(ICx),所以一个定时器在使用PWM输入的时候最多只能使用两个输入通道(TIx)。

例如,在信号进入TI1通道时,信号会被分为两路,一路是TI1FP1,另外一路是TI1FP2。其中一路为频率,一路为占空比,程序中作为触发输入的为频率,另一路即为占空比。作为触发输入的需要设置极性,一路设置好极性后,另一路会自动设置为相反的极性。

2.PWM输出模式

PWM输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装寄存器ARR的值决定,占空比由比较寄存器CCR的值决定。占空比Duty = CCR / (ARR + 1)。

CCR和ARR共同决定占空比,函数TIM_SetCompare"x"仅设置CCR的值。

PWM模式分为两种,PWM1和PWM2。

根据计数器CNT计数的方向不同还分为边沿对齐模式和中心对齐模式。 一般的电机控制用的都是边沿对齐模式,FOC电机一般用中心对齐模式。

	/*输出比较初始化*/ 
	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_OC3Init(TIM2, &TIM_OCInitStructure);                        //将结构体变量交给TIM_OC3Init,配置TIM2的输出比较通道3

3.具体步骤

(1)开启时钟

(2)GPIO初始化

(2)配置时钟源

(4)时基单元初始化

(5)输出比较初始化  在这里CCR初始值设置为0即可,注意要选择正确的输出比较通道,如果需要的话可以进行重映射,不要使得引脚冲突。

(6)TIM使能   TIM_Cmd

(7)定义PWM_SetCompare3函数,以便设置CCR的值

 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);
	
	//GPIO_SetBits(GPIOA, GPIO_Pin_0);

	
	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;  //PCR
	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);
 }

以上为PWM模块,接下来,我们将CCR的值写入电机驱动模块,通过控制占空比,调节电机速度,需要注意的是,要配置好GPIO引脚的高低电平来控制电机正转反转,千万不要配置反了,还有,PWM的值只能为正值,有需要时加“-”。

void Motor_SetSpeed(int8_t Speed)
{
	if (Speed >= 0)							//如果设置正转的速度值
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_4);	//PA4置高电平
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);	//PA5置低电平,设置方向为正转
		PWM_SetCompare3(Speed);				//PWM设置为速度值
	}
	else									//否则,即设置反转的速度值
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_4);	//PA4置低电平
		GPIO_SetBits(GPIOA, GPIO_Pin_5);	//PA5置高电平,设置方向为反转
		PWM_SetCompare3(-Speed);			//PWM设置为负的速度值,因为此时速度值为负数,而PWM只能给正数
	}
}

这样当输入speed的值时,电机就可以转动了。

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值