编码器接口简介:
Encoder Interface 编码器接口
编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
每个高级定时器和通用定时器都拥有1个编码器接口
两个输入引脚借用了输入捕获的通道1和通道2
编码器接口基本结构:
工作模式:
正传的状态都向上计数,反转的状态都向下计数
接线图:
函数介绍:
定时器编码器接口配置,第一个参数选择定时器,第二个参数选择编码器模式,后面两个参数分别选择通道1和通道2的极性
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
代码配置:
利用编码器接口进行测速
1.定义结构体变量
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义TimeBase结构体变量
TIM_ICInitTypeDef TIM_ICInitStructure; //定义IC结构体变量
2.RCC开启时钟
开启GPIO和定时器的时钟
//开启RCC时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TIM3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIO A族时钟
3.配置GPIO
这里需要把PA6和PA7配置成输入模式
//GPIO配置
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);//GPIO初始化
4.配置时基单元
这里预分频器我们选择不分频,自动重装一般给最大65536,只需要个CNT执行计数就行
//时基单元配置
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1; //周期 自动重装器ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //预分频器 PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); //TimeBase初始化
5.配置输入捕获单元
这里输入捕获单元只有滤波器和极性这两个参数有用(极性在配置编码器接口模式也可以配置,所以这里就删掉了)
//输入捕获单元配置
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //TIM通道选择,这里选择的是TIM3的CH1通道
TIM_ICInitStructure.TIM_ICFilter = 0xF; //选择输入捕获的滤波器
TIM_ICInit(TIM3,&TIM_ICInitStructure); //IC初始化
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //TIM通道选择,这里选择的是TIM3的CH2通道
TIM_ICInitStructure.TIM_ICFilter = 0xF; //选择输入捕获的滤波器
TIM_ICInit(TIM3,&TIM_ICInitStructure); //IC初始化
6.配置编码器接口模式
后面两个参数可以配置通道1与通道2的极性
//配置编码器接口
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
最后调用TIM_Cmd,启动定时器
//开启定时器
TIM_Cmd(TIM3,ENABLE);
电路初始化完成之后,CNT就会随之编码器的旋转而自增自减,如果想要测量编码器的位置,直接读出CNT的值就行了,如果想测量编码器的速度和方向,那就需要每隔一段固定的闸门时间,取出一次CNT,然后再把CNT清零,这样就是测频法测量速度了
完整代码:
void Encoder_Config(void)
{
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义TimeBase结构体变量
TIM_ICInitTypeDef TIM_ICInitStructure; //定义IC结构体变量
//开启RCC时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TIM3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIO A族时钟
//GPIO配置
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);//GPIO初始化
//时基单元配置
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1; //周期 自动重装器ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //预分频器 PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); //TimeBase初始化
//输入捕获单元配置
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //TIM通道选择,这里选择的是TIM3的CH1通道
TIM_ICInitStructure.TIM_ICFilter = 0xF; //选择输入捕获的滤波器
TIM_ICInit(TIM3,&TIM_ICInitStructure); //IC初始化
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //TIM通道选择,这里选择的是TIM3的CH2通道
TIM_ICInitStructure.TIM_ICFilter = 0xF; //选择输入捕获的滤波器
TIM_ICInit(TIM3,&TIM_ICInitStructure); //IC初始化
//配置编码器接口
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
//开启定时器
TIM_Cmd(TIM3,ENABLE);
}
功能函数:
读取CNT的值,并读取一次便将CNT的值清零
int16_t Encoder_GetTime(void)
{
int16_t temp;
temp = TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3,0);
return temp;
}
Timer函数:
这里用定时中断的方法来测量,其他方法涉及到用delay函数的问题,会堵塞主程序,所以最好是用中断解决
void Timer_Init(void)
{
//---------------------------定义结构体变量-------------------------------
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义TIM结构体变量
NVIC_InitTypeDef NVIC_InitStructure; //定义NVIC结构体变量
//---------------------------定义结构体变量-------------------------------
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开TIM2的外设时钟
//-----------------------------配置时基单元---------------------------------
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1 ; //时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式 这里选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; //周期 就是ARR自动重装器的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //是PSC预分频器的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值(这个是高级寄存器才有的,这里不需要用直接给0)
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //TIM初始化
//-----------------------------配置时基单元---------------------------------
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启更新中断到NVIC通路
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除标志位
//-----------------------------NVIC配置-------------------------------------
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择中断分组2
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);//NVIC初始化
//-----------------------------NVIC配置-------------------------------------
TIM_Cmd(TIM2,ENABLE);//启动定时器
}
中断函数:
int16_t Speed = 0;
//中断函数
void TIM2_IRQHandler(void)
{
//获取中断标志位,判断是否触发中断
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
{
Speed = Encoder_GetTime();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
}
}
主函数代码:
#include "Encoder.h"
#include "timer.h"
int main(void)
{
OLED_Init();
Timer_Init();
Encoder_Config();
OLED_ShowString(1, 1, "Speed:");
while(1)
{
OLED_ShowSignedNum(1, 7, Speed, 5);
}
}