基于STM32的正交编码器接口应用含源程序
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于STM32的正交编码器接口应用
本设计应用了ST公司的最新单片机STM32完成。STM32应用的是ARM 32位的
Cortex™-M3 CPU,最高72MHz工作频率,单周期乘法和硬件除法,高速的运行速度,可以保证编码器高转速条件下的高速脉冲依旧能够被准确的计数。多达7个定时器,3个16位定时器,每个定时器有多达4个用于输入捕获/输出比较/PWM或脉冲计数的通道和增量编码器输入。因此只要对MCU进行配置之后,MCU只需要少量的中断程序,就可以方便的完成对编码器的方向和角速度的运算。
STM32单片机工作在3.3V下。拥有内部8M晶振,可以通过锁相环倍频到48M(内部晶振由于稳定度不够,只能倍频到48M)
。
采用标准的JATGE接口进行程序的烧录和调试。
采用一块lm1117-3.3V作为芯片的稳压电源。LM1117为一块LDO(低压差线性稳压器),输入最低为3.3+0.7=4v
用一块LCD5110手机屏作为显示设备,可以显示输出电压以及当前状态。液晶屏参数为72*48,点阵式,使用一个驱动库作为支持,方便开发,工作在3.3V电压下,与单片机相适应。耗电极低,小于1MA,背光耗电为20MA。
采用USB接口与编码器连接,线序定义为V+,A相,B相,GND,正好将USB的所有连线用完,可以同时完成给编码器提供电力以及返回信号的功能。同时MINIUSB接口良好的物理连接特性也保证了应用的稳定性。
由于编码器为NPN集电极输出,所以需要在信号线上提供一定的上拉电阻。
所使用的编码器为远征牌,200线(转一圈输入200个脉冲),AB 两相,最大转速200rad/s,输入电压可以为5到18V(编码器内部带有稳压芯片)。
正交编码器接口详述的所有通用定时器
及高级定时器都集成了正交编码器接口。定时器的两个输入和直接与增量式正交编码器接口。当定时器设为正交编码器模式时,这两个信号的边沿作
为计数器的时钟。而正交编码器的第三个输出(机械零位),可连接外部中断口来触发定时器的计数器复位。
定时器正交编码器接口框图
图:定时器正交编码器接口
功能描述
选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置
TIM1_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;
如果计数器同时在TI1和TI2边沿计数,则置SMS=011。
通过设置TIM1_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性;如果需要,还可以对输入滤波器编程。
两个输入TI1和TI2被用来作为增量编码器的接口。参看表1,假定计数器已经启动(TIM1_CR1寄存器中的CEN=1),则TI1FP1或TI2FP2上的有效跳变作为计数器的时钟信号。TI1FP1和TI2FP2是TI1和TI2在通过输入滤波器和极性控制后的信号;如果没有滤波和变相,则TI1FP1=TI1,TI2FP2=TI2。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号的跳变顺序,计数器向上或向下计数,因此TIM1_CR1寄存器的DIR位由硬件进行相应的设置。不管计数器是对TI1计数、对TI2计数或者同时对TI1和TI2计数。在任一输入(TI1或者TI2)跳变时都会重新计算DIR位。
应用笔记正交编码器接口
编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到TIM1_ARR寄存器中自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计数)。所以在开始计数之前必须配置
TIM1_ARR;同样,捕获器、比较器、预分频器、周期计数器、触发输出特性等仍工作如常。编码模式和外部时钟模式2不兼容,因此不能同时操作。
在这个模式下,计数器依照增量编码器的速度和方向被自动的修改,因此,它的内容始终指示着编码器的位置。计数方向与相连的传感器旋转的方向对应。
表1列出了所有可能的可能的组合,假设TI1和TI2不同时变换。
表1:计数方向与编码器信号的关系
一个外部的增量编码器直接和MCU连接不需要外部接口逻辑。但是,一般使用比较器将编码器的差动输出转换到数字信号,这大大增加了抗噪声干扰能力。编码器输出的第三个信号表示机械零点,可以连接到一个外部中断输入,触发一个计数器复位。
//***************************************************************************** ***********************
//编码器库函数
//操作环境:MDK
//***************************************************************************** ***********************
#include "enconder.h"
//#include "LCD.h"
//***************************************************************************** ***********************
//正交编码器接口的初始化
//***************************************************************************** ***********************
void ENC_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APBPeriph_ENCODER_TIMER, ENABLE);//TIM4 // ENCODER_TIMER时钟初始化
RCC_APB2PeriphClockCmd(RCC_APBPeriph_ENCODER_GPIO, ENABLE); // ENCODER_GPIO 时钟初始化
GPIO_StructInit(&GPIO_InitStructure); //TI1 TI2初始化GPIO_InitStructure.GPIO_Pin = ENCODER_TI1 | ENCODER_TI2; //PB6,PB7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输出GPIO_Init(ENCODER_GPIO, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIMER_IRQChannel;//TIM4_IRQn //设置ENCODER_TIMER的优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIMx_PRE_EMPTION_PRIORITY; NVIC_InitStructure.NVIC_IRQChannelSubPriority = TIMx_SUB_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Timer configuration in Encoder mode */ //设置ENCODER_TIMER为编码器模式
TIM_DeInit(ENCODER_TIMER); //ENCODER_TIMER复位TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 无分频
TIM_TimeBaseStructure.TIM_Period = (4*ENCODER_PPR)-1; //计数器重载值4*200-1
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(ENCODER_TIMER, &TIM_TimeBaseStructure); //TIM4
//TIM4
TIM_EncoderInterfaceConfig(ENCODER_TIMER,
TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //编码器接口初始化TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER; //6
TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);
// Clear all pending interrupts
TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);