STM32快速复习(三)定时器中断(TIM)部分四 TIM编码器接口原理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

Encoder Interface 编码器接口
是定时器的时钟源之一,可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减(不消耗软件资源),从而指示编码器的位置、旋转方向和旋转速度。
当然上面这个功能也可以使用外部中断+软件代码来手动实现,但是stm32开辟出专用的硬件资源,可以减轻软件的消耗。

每个高级定时器和通用定时器都拥有1个编码器接口。注意定时器配置成编码器接口模式后,就干不了别的活了。
两个输入引脚借用了输入捕获的通道1和通道2。
典型应用场景:一般应用在电机控制的项目上。使用PWM驱动电机,再使用定时器的编码器接口测量电机的速度,然后再用PID算法进行闭环控制。一般电机的转速比较高,会使用无接触式的霍尔传感器或光栅来输出包含转速信息的信号(如正交编码器信号)。

在要求不严格的场景下,正交信号的某一路信号便可以传递转速信息,但不能说明旋转方向;要指明旋转方向,可以再添加一路专门用于指示旋转方向的信号,但是这样就不是正交信号了。正交信号使用两路相位相差90°的信号,可以同时说明转速、转向,并且由于其特殊的正交性质,还额外增加了抗干扰的能力。

一、编码器接口?编码器接口如可理解?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结合下图看懂计数原理即可,知道如何判断正转反转。明白计数与编码器原理,基本上再结合电路图和代码库,可以自己看懂甚至写出编码器的代码,这一章就算彻底读懂。
在这里插入图片描述

二、标准库代码

1.标准库涉及代码

TIM_EncoderInterfaceConfig 【常用】:配置编码器接口。
下面是目前还没有涉及到的TIM库函数:
TIM_BDTRConfig :用于配置定时器的 BDTR(Break and Dead-Time Register)寄存器。
TIM_BDTRStructInit :给 BDTR 寄存器的配置参数结构体 TIM_BDTRInitTypeDef 赋一个初值。
TIM_GenerateEvent :强制定时器产生中断。
TIM_DMAConfig :配置TIM模块的 DMA传输功能。stm32中定时器模块可以与 DMA 控制器进行集成,通过 DMA 传输机制实现定时器的计数器值、比较寄存器值等数据的快速传输,
减少 CPU 的负担,提高系统的效率。
TIM_DMACmd :使能或禁用定时器的 DMA 传输功能。
TIM_SelectCOM :选择定时器模块的复合输出模式(Complementary Output Mode)包括主输出模式、复合模式、复合滤波模式等。COM模式可以实现多种输出波形的生成,例如矩
形波、三角波、脉冲波等,同时还可以实现硬件互锁、反相输出、输出极性选择等功能。
TIM_SelectCCDMA :使能或禁用通道比较DMA传输状态。
TIM_UpdateDisableConfig :使能或禁用定时器的更新事件。
TIM_UpdateRequestConfig :配置更新请求(URS)寄存器的功能,从而实现定时器的周期性更新。。
TIM_SelectHallSensor :选择不同的霍尔传感器模式,从而实现电机的精确控制。
TIM_SelectOnePulseMode :选择单脉冲模式,从而实现精确的时间控制。

2.示例代码

代码如下(示例):
放入主函数的代码:

int16_t timer_cnt = 0;//定时器的计数器
int main(void){
//定义旋转编码器的转速(单位:转/分)
float RE_RPM = 0;

//TIM2定时中断后的中断函数-获取计数器的值并清零
void TIM2_IRQHandler(void)
{
   if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
   {
     timer_cnt = EncoderInterface_Get();
     TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
   }
}

EncoderInterface.h

#include "stm32f10x.h" // Device header
//定时器的编码器接口初始化-TIM3-PA6、PA7
void EncoderInterface_Init(void){
//1.开启外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//2.配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//3.配置时基单元-编码器接口托管时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 0xffff;
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//默认不分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//4.配置输入捕获通道
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);//防止没定义的参数影响程序正常运行
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//输入捕获通道1
TIM_ICInitStructure.TIM_ICFilter = 0x3;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;//输入捕获通道2
TIM_ICInitStructure.TIM_ICFilter = 0x3;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
//5.选择编码器接口
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
//6.启动定时器
TIM_Cmd(TIM3, ENABLE);
}
//读取计数器的值并清零
uint16_t EncoderInterface_Get(void){
uint16_t temp = TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3, 0x0000);
return temp;
}

总结

  1. GPIO输入模式。在配置成上拉输入、下拉输入的时候,记得要与外部引脚的默认电平保持一致,防止默认电平打架。不过默认高电平是一种行业习惯。若实在不确定外部引脚默认电平,就选择浮空输入,但缺点就是容易受到噪声的干扰。
  2. 极性的配置。 TIM_EncoderInterfaceConfig 编码器配置中对于极性的配置和输入捕获通道对于极性的配置重复,所以若将编码器配置放在后面,那么在输入捕获通道配置时就无需特别指明极性选择的配置了。
  3. 旋转编码器的段落感。转动一下,计数器会变动4次。这是因为在双边沿都会进行判断计数。
    4. 常用方式!!!把定时器的代码加进来后,中断函数里取CNT值、主函数计算转速。
    两个定时器,一个定时中断,一个编码器接口。每次定时中断读取一次计数器CNT的值并清零,就可以不断地得到相应的速度。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值