一、概述
1、Encoder Interface 编码器接口概念
- 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
- 每个高级定时器和通用定时器都拥有1个编码器接口
- 两个输入引脚借用了输入捕获的通道1和通道2(只能是通道1)
正交编码器:
其实只测其中一相就能测出速度,两相可以知道编码器正传还是反转。
编码器接口基本结构:
2、工作模式
TI1指的是通道1, TI2指的是通道2。
TI1和TI2均不反相(反相就是电平翻转):
TI或TI2 反相:
虽然TI1的波形在图里没有翻转,但是你会发现,TI1上升沿,TI2为低电平,应该为向上计数,而图中是向下计数,所以TI1或TI2反相为反相计数器才会向下计数,可以对着表格测试一下。CNT向上计数表示编码器正转,CNT向下计数表示编码器反转。
二、用旋转编码器进行手动模拟
完整代码如下:
- 定时器定时1s
Timer.c:
cpp
#include "stm32f10x.h" // Device header
extern uint16_t Num;
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStructure;
//1.配置时钟,用那个外设
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//2.内部时钟配置
TIM_InternalClockConfig(TIM2);
//3.配置时基单元
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //滤波频率
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //计数方式
TIM_TimeBaseInitStruct.TIM_Period=10000-1; //自动重装载寄存器ARR
TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0; //这个是高级定时器才用的,这里不用,给0
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清除中断标志位
//4.配置中断输出控制,打开中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//5.NVIC配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_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);
//6.启动定时器
TIM_Cmd(TIM2,ENABLE);
}
Timer.h:
cpp
#ifndef _TIMER_H
#define _TIMER_H
void Timer_Init(void);
#endif
- 编码器接口
Encoder.c:
这里没有考虑定时器溢出情况。
cpp
#include "stm32f10x.h" // Device header
void Encoder_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
//1.配置时钟,用那个外设
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//2.配置时基单元
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //滤波频率
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //计数方式,向上
TIM_TimeBaseInitStruct.TIM_Period=65535-1; //自动重装载寄存器ARR,让CNT达到最大量程
TIM_TimeBaseInitStruct.TIM_Prescaler=1-1; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//3.初始化捕获单元
TIM_ICStructInit(&TIM_ICInitStruct); //对结构体进行初始化,防止产生其他影响
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1; //选择输入通道
TIM_ICInitStruct.TIM_ICFilter=0xF; //滤波
//TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //选择极性,上升沿
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel=TIM_Channel_2; //选择输入通道
TIM_ICInitStruct.TIM_ICFilter=0xF; //滤波
//TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising; /选择极性,上升沿,表示电平不反相
TIM_ICInit(TIM3,&TIM_ICInitStruct);
//4.配置编码器接口
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,
TIM_ICPolarity_Falling,TIM_ICPolarity_Rising);
//5.启动定时器
TIM_Cmd(TIM3,ENABLE);
}
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp=TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3,0);
return Temp;
}
Encoder.h:
cpp
#ifndef _ENCODER_H
#define _ENCODER_H
int16_t Encoder_Get(void);
void Encoder_Init(void);
#endif
main.c:
cpp
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "delay.h"
#include "Timer.h"
#include "Encoder.h"
int16_t speed;
int main(void)
{
OLED_Init();
Timer_Init();
Encoder_Init();
OLED_ShowString(1,1,"CNT:");
while(1)
{
OLED_ShowSignedNum(1,5,speed,5);
Delay_ms(1000);
}
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
speed=Encoder_Get();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //更新中断就是产生一个中断标志位
}
}