1什么是编码器接口?
编码器接口接受编码器的正交信号,根据编码器产生的正交信号脉冲控制CNT的自增和自减,从而指示编码器的旋转方向和旋转速度。
每个高级定时器和通用定时器都有一个编码器接口,同时正交编码器产生的正交信号分为正转和反转,通过两个GPIO口产生的正交信号来决定是正转还是反转。
2.编码器接口基本结构
CNT的自增还是自减受编码器控制,输入捕获的前两个通道通过GPIO口连接编码器的A相和B相,再通过滤波器和边沿极性选择,产生TI1FP1和TI2FP2信号通向编码器接口,同时编码器接口根据编码器的旋转方向控制CNT的计数方向,编码器正转,CNT自增,编码器翻转,CNT自减。编码器接口相当于使用了一个带有方向选择的外部时钟。
3.通用定时器基本框图
如下图所示,我们可以看到TIMx_CH1和TIMx_CH2输入捕获的前两个通道,产生TI1FP1和TI2FP2信号通向编码器接口。
4.编码器模块Encoder代码编写
(1).开启RCC时钟,包括GPIO和定时器3的时钟。
//1.开启时钟TIM3的时钟线是APB1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//2.开启GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
(2).配置GPIO,把PA6和PA7引脚配置成输入模式(PA6为TIM3_CH1通道,PA7为TIM3_CH2通道)
GPIO_InitTypeDef GPIO_Inistructure;
GPIO_Inistructure.GPIO_Mode= GPIO_Mode_IPU;//PWM输入设置为上拉输入
GPIO_Inistructure.GPIO_Pin= GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Inistructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Inistructure);//读取结构体的参数
(3).时基单元初始化。配置预分频器,预分频器选择不分频,ARR自动重装值给最大,只配置CNT即可。
//3.时基单元初始化
TIM_TimeBaseInitTypeDef TIM_timBaseInitStructure;
TIM_timBaseInitStructure.TIM_ClockDivision= TIM_CKD_DIV1;//一分频
TIM_timBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
TIM_timBaseInitStructure.TIM_Period=65536-1;//ARR
TIM_timBaseInitStructure.TIM_Prescaler=1-1;//PSC 选择不分频
TIM_timBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器是高级定时器才有的
TIM_TimeBaseInit(TIM3,&TIM_timBaseInitStructure);
(4).配置输入捕获单元(包含滤波器和边沿极性选择)
//4.配置输入捕获单元通道一和通道2
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);//结构体初始化
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//定时器3的通道1
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波器
TIM_ICInitStructure.TIM_ICPolarity= TIM_ICPolarity_Rising;//边沿检测极性选择上升沿触发,代表输入波形极性不翻转
TIM_ICInit(TIM3,&TIM_ICInitStructure);
TIM_ICStructInit(&TIM_ICInitStructure);//结构体初始化
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//定时器3的通道2
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波器
TIM_ICInitStructure.TIM_ICPolarity= TIM_ICPolarity_Rising;//边沿检测极性选择上升沿触发,代表输入波形极性不翻转
TIM_ICInit(TIM3,&TIM_ICInitStructure);
5.配置编码器接口,A/B相均计数,A/B波形输入选择Rising,极性不反转
//5配置编码器接口,A/B相均计数,A/B波形输入选择Rising,极性不反转
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
6. 启动定时器
//6.启动定时器
TIM_Cmd(TIM3,ENABLE);
7.得到CNT的值
//得到CNT的值
int16_t Encoder_Get(void)
{
int16_t temp;
temp=TIM_GetCounter(TIM3);//得到CNT的值
TIM_SetCounter(TIM3,0);//将CNT清0
return temp;
}
5.用TIM2中断函数计数
目的:调用TIM2中断函数,每产生一个更新事件,记一次数,即测速。在TIM2产生的中断函数中,实现对TIM3编码器产生的正交信号进行计数。
在main.c函数中实现TIM2中断函数的调用,在中断函数中实现计数的功能
注:中断函数的更新事件的标志位,在程序进行完之后要对中断标志位进行清除。
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"
int16_t Speed; //定义速度变量
int main(void)
{
OLED_Init();
Timer_Init(); //定时器2初始化
Encoder_Init(); //编码器初始化
/*显示静态字符串*/
OLED_ShowString(1, 1, "Speed:");
while (1)
{
OLED_ShowSignedNum(1, 7, Speed, 5); //不断刷新显示编码器测得的最新速度
}
}
// 函 数:TIM2中断函数
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //判断是否是TIM2的更新事件触发的中断
{
Speed = Encoder_Get(); //每隔固定时间段读取一次编码器计数增量值,即为速度值
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中断标志位
//中断标志位必须清除
//否则中断将连续不断地触发,导致主程序卡死
}
}