提示:一般情况下我们会设计一个硬件电路模块来自动完成简单重复而高频的计算
一、为什么通常情况下不使用外部中断来对编码器的脉冲进行计数?
电机高速旋转过程中会在短时间产生成千上万个脉冲信号,如果频繁调用中断进行累加运算会占用一定的软件资源;
一般情况下我们会设计一个硬件电路模块来自动完成上述简单重复而高频的计算;
二、编码器速度测量程序设计思路
每隔一段实际取一次值就可以得到编码器旋转的速度了;
编码器接口(Encoder Interface),编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或者自减,从而指示编码器的位置、旋转方向和旋转速度;
每个高级定时器和通用定时器都拥有一个编码器接口;
两个输入引脚借用了输入捕获的通道1和通道2;
注意CH3和CH4引脚不能接编码器
每个高级定时器和通用定时器都拥有一个编码器接口;
三、正交编码器
正交编码器的接口:
A相 B相 编码器电源 GND Z相(编码器0位置的输出,每转到一个固定的位置的时候输出一个脉冲,一般用于位置测量,校准0位置用的。)
正交信号精度更高:
A、B相都可以计次,相当于频率提高了一倍;
正交信号可以抗噪声:
正交信号的两个信号必须是交替跳变的,可以设计成一个抗噪声电路;
65535的补码为-1,如果想读取到负数,可以将编码器的uint_16类型强行转换为int_16类型;
读取编码器计数次数库函数:
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx)
四、初始化流程
①RCC开启时钟,开启GPIO和定时器的时钟;
②配置GPIO,把PA6和PA7 配置成输入模式;
③配置时基单元,预分频器一般选择不分频(PSC = 0),自动重装一般给最大值65535(0~2^16-1);
④配置输入捕获单元,这里输入捕获单元只有滤波器和极性有用,后面的参数没有用到,与编码器无关;
⑤配置编码器接口模式
⑥调用TIM_Cmd启动定时器;
编码器初始化需要调用到的库函数
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
获取定时器CNT的计数值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
五、STM32正交编码器输入捕获模式配置示例
代码如下(示例):
/**
* @brief 正交编码器输入捕获初始化,采用PA6、PA7捕获编码器A相与B相数据;
注意PA6与PA7不可以随意更换,PA6->TIM3的CH1 PA7->TIM3的CH2;
* @param 无
* @retval 无
*/
void Encoder_Init_IC(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA的外设时钟
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;//设置上拉输入模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;//选中GPIO口
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能定时器TIM3的外设时钟
//TIM_InternalClockConfig(TIM3);//选择内部时钟驱动TIM3的时钟单元,定时器上电默认使用内部时钟,这句话可以不写
//TIM_ETRConfig(TIM3,TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted,0x0F);//选择外部时钟驱动TIM3的时钟单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//滤波器的采样时钟分频系数,跟时基单元关联不大,决定了滤波器的输入时钟频率(越低滤波输出越稳定,同时延迟会增大)
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//选择向上计数
TIM_TimeBaseInitStruct.TIM_Period = 65535;//ARR自动重装器的值,取值0~65535,10KHZ/10000=1HZ
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;//预分频器的值,取值0~65535,72MHZ/7200=10KHZ
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器的值,高级定时器特有的配置,这里用不上
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICStructInit(&TIM_ICInitStruct);//给结构体赋初始值,主要是为了防止结构体不完整导致出错
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;//指定配置1~4哪一个通道
TIM_ICInitStruct.TIM_ICFilter = 0xF;//选择输入捕获的滤波器,数值越大滤波效果越好(一般滤波器的采样频率会远高于信号频率,此处滤波器不会改变输入信号的频率,而是滤除高频噪声使得输入信号更加平滑)
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//这里的上升沿代表高低电平极性不反转
//TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分配器会改变输入信号的频率,这里需要每次信号触发都有效,所以选择不分频
//TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//选择信号从哪一路引脚输入,可以选择直连通道或者交叉通道(DirectTI表示直连通道,InDirectTI表示交叉通道)
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;//指定配置1~4哪一个通道
TIM_ICInitStruct.TIM_ICFilter = 0xF;//选择输入捕获的滤波器,数值越大滤波效果越好(一般滤波器的采样频率会远高于信号频率,此处滤波器不会改变输入信号的频率,而是滤除高频噪声使得输入信号更加平滑)
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//这里的上升沿代表高低电平极性不反转
//TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分配器会改变输入信号的频率,这里需要每次信号触发都有效,所以选择不分频
//TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//选择信号从哪一路引脚输入,可以选择直连通道或者交叉通道(DirectTI表示直连通道,InDirectTI表示交叉通道)
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_Cmd(TIM3,ENABLE);//启动定时器TIMx 这里的上升沿代表高低电平极性不反转
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12 ,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//写入到TIMCmd后防止被覆盖
}
/*
在输入捕获的模式下如果想获取编码器的位置信息可以直接读出CNT的值;
如果想获取编码器的速度和方向,需要每隔一段固定的闸门时间,去除一次CNT再把CNT清零;
上述测量速度即测频法;
*/
总结
以上就是今天要讲的内容,本文简单介绍了STM32中编码器的使用方式。