文档库 最新最全的文档下载
当前位置:文档库 › 基于STM32的正交编码器接口应用含源程序

基于STM32的正交编码器接口应用含源程序

基于STM32的正交编码器接口应用含源程序
基于STM32的正交编码器接口应用含源程序

基于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);

TIM_ITConfig(ENCODER_TIMER, TIM_IT_Update, ENABLE);

//Reset counter

TIM2->CNT = COUNTER_RESET; //0

TIM_Cmd(ENCODER_TIMER, ENABLE);

}

//***************************************************************************** ***********************

// 计算马达转子相对于初始位置的角度-180至+180

//***************************************************************************** ***********************

void ENC_Get_Electrical_Angle(uint16_t *degree)

{

int32_t temp;

int16_t tim_count;

tim_count=TIM_GetCounter(ENCODER_TIMER); //获取ENCODER_TIMER TIM4的值if(tim_count>=400) //如果超过180度,角度为负数

{

degree[0]='-';

degree[1]=(800-tim_count)*180/(4*ENCODER_PPR/2); //整数部分

temp = (int32_t)(800-tim_count) *

(int32_t)(1000000/(4*ENCODER_PPR/2))*360-degree[1]*1000000;

degree[2]=(unsigned char)temp; //小数部分

}

else //如果未超过180度,角度为正数

{

degree[0]='+';

degree[1]=tim_count*180/(4*ENCODER_PPR/2);//整数部分

temp = (int32_t)tim_count *

(int32_t)(1000000/(4*ENCODER_PPR/2))*180-degree[1]*1000000;

degree[2]=(unsigned char)temp; //小数部分

}

}

相关文档