增量式编码器是直接利用光电转换原理输出三组方波脉冲A、B和Z相;A、B两组脉冲相位差90o,从而可方便地判断出旋转方向,而Z相为每转一个脉冲,用于基准点定位。它的优点是原理构造简单,机械平均寿命可在几万小时以上,抗干扰能力强,可靠性高,适合于长距离传输。其缺点是无法输出轴转动的绝对位置信息。增量式编码器是一种测量设备转动的传感器,在电机驱动控制中得到广泛应用。
关键词:SPMC75 增量编码器
1 引言
本文主要是讲解SPMC75F2413A的PDC定时器模块的增量码盘接口功能,用这个接口可以测量增量码盘转轴的角位移,同时还可根据单位时间的角位移计算出增量码盘转轴的角速度,进而得到转轴的转速。本例使用的增量码盘接口模式1,这是四倍频接口模式,适合图2-1中所示类型的波形。
2 系统框图
系统结构如图2-1所示,主要由信源模拟发生模块和速度测量模块组成。两个模块均由SPMC75F2413A构成。信源模拟发生模块产生如中A、B所示的信号波形,A、B信号相差90度,图中只示出了B超前A的情况,信号的频率由电位器调整。
图 2-1 系统结构图
3 增量编码盘接口原理
3.1 设计原理
增量编码盘是一种测量角位移增量的传感器,根据其工作方式的不同可分为光电式、磁电式和纯机械式等几种,光电式和磁电式是现今最常用的方式。其中光电式用得最多是光电透射式,而磁电式主要是利用类式磁带的原理在一个圆周上均布了N、S的磁信号,利用磁敏组件检出信号。
SPMC75F2413A的增量编码盘接口模式1工作原理如图3-1所示:外部输入信号TCLKA、TCLKB频率相同但相位互差90度,其频率与其转速成正比,比例为增量编码的细分数(每转1转所输出的脉冲个数)。而两路信号的相位关系则代表了转向信息。当TCLKA超前TCLKB时为正转,反之当TCLKA滞后TCLKB时为反转。同时,由于这两路信号是互差90度的,为了提高测量的精度,计数器是在两路信号的跳变沿都计数,而计数的方向则由两路信号的相位关系确定。TCLKA超前时计数器增计数,TCLKA滞后时计数器减计数。如此,用户便可以得到从计数器开始计数后增量编码转轴的角位移量(如当增量编码盘的细分数为N时,增量编码盘的每一个脉冲代表的角位移为由于为四倍频计数,因此,当计数器的值为K时,所代表的角位移为)。同时,用户可以通过测量单位时间内的角位移而得到当前转轴的转速。其转速为:
------(式3-1)
式中:为转轴角速度;
为测量时间;
为内的计数器增量;
N为码盘的细分数;
图2-1 相位计数模式1
4 硬件说明
4.1 信号模拟发生电路
这部分电路如图4-1所示,使用SPMC75F2413A的MCP3实现双线增量码盘输出信号的模拟,并根据AD采集的数据设置信号的频率和方向,以满足系统测试的需要。
图4-1信号模拟发生电路
4.2 测量接口电路
电路如图4-2所示,这部分是本例的主体部分,它主要是利用SPMC75F2413A的PDC定时计数器的相位计数(码盘接口)模式1完成位置信号的采集、速度的测量。为了提高测量精度,使用了四倍频技术。
图4-2测量接口电路
5 软件说明
5.1 软件说明
系统的软件部分主要是系统所用到的硬件的初始化,并在硬件中断时进行相应的的处理。同时利用DMC的通信软体库完成与PC的通信,以便对系统状态和结果进行监控。
5.2 软件流程
5.2.1 主程序流程
主程序在完成系统初始化以后,就不断检测有没有来自PC的控制信息,如果有便完成相应的控制功能,没有就继续检测。同时将当前系统测得数据送入DMC接口区,以便系统状态的监示。
图5-1 主程序流程图
5.2.2 中断流程
中断服务主要有三个,一个是系统通信中断服务,主要是在DMC库中完成;一个是PDC定时器的溢出中断服务,在这里主要完成位置计数溢出的处理,以保证位置单元的正确性;最后一个是定时器的周期中断服务,这里主要完成当前位置信息的采集,同时根据位置增量计算当前的转速。
5.3 程序代码
使用SPMC75F2413A的PDC0的相位计数模式(即两线增量码盘接口)实现使用两线增量码盘测量电机转速。
#include "Spmc75_regs.h" #include "mcMACRO.h" #include "Spmc75_dmc_uart_ext.h" #define Samp_Time 8 // 采样定时器 , 单位 ms void Daly_Time(int Time); void PDC0_Init(void); void Time2_Init(void); static int Moto_Speed = 0; // 电机转速 static int Over_flag = 0; // 位置计数器溢出标志 static int Encoder_Data = 256*4; // 编码盘的细分常数 // 电机绝对位置 ( 长整数 , 为了计算方便 , 高低分开定义 ) static unsigned int Position_Count[2] = {0,0}; static unsigned int Old_Position_Count = 0; // 上一次电机位置 ( 低 16 位 ) //===================================================================== // ----Function: main(void); // -Description: 主函数 // -----Returns: None // -------Notes: //===================================================================== main() { PDC0_Init(); Time2_Init(); MC75_DMC_UART_Setup(9600); INT_IRQ(); while(1) { MC75_DMC_UART_Service(); if(SPMC_DMC_Load_SpdCmd(1) > 0) Encoder_Data = SPMC_DMC_Load_SpdCmd(1)*4; SPMC_DMC_Save_SpdNow(1,Moto_Speed); } } //===================================================================== // ----Function: void PDC0_Init(void); // -Description: 定时器初始化 // --Parameters: None // -----Returns: None // -------Notes: //===================================================================== void PDC0_Init(void) { P_IOA_Dir->W &= 0xe7ff; // 设置用到的 IO 口 P_IOA_Attrib->W &= 0xe7ff; P_IOA_Buffer->W |= 0x1800; P_IOA_SPE->W |= 0x1800; P_TMR0_Ctrl->B.SPCK = CB_TMR0_SPCK_FCKdiv1; // 设置采样时钟为主系统时钟 // 设置定时计数器模式为四倍频增量码盘接口 P_TMR0_Ctrl->B.MODE = CB_TMR0_MODE_Mode1; P_TMR0_Ctrl->B.CCLS = CB_TMR0_CCLS_Disabled; // 禁止计数器清除 P_TMR0_Ctrl->B.CKEGS = CB_TMR0_CKEGS_Rising; // 设定计数边沿为上升沿 P_TMR0_Ctrl->B.TMRPS = CB_TMR0_TMRPS_FCKdiv1; // 设置时钟 , 这是必需的 // 使能计数器的上溢下溢中断 P_TMR0_INT->W |= CW_TMR0_TCUIE_Enable + CW_TMR0_TCVIE_Enable; P_TMR_Start->B.TMR0ST = 1; // 启动定时器 } //===================================================================== // ----Function: void Time2_Init(void); // -Description: TMR2_module initialize function // --Parameters: None // -----Returns: None // -------Notes: //===================================================================== void Time2_Init(void) { P_TMR2_Ctrl->B.MODE = CB_TMR2_MODE_Normal; // 工作模式初始化为连续增计数 P_TMR2_Ctrl->B.CCLS = CB_TMR2_CCLS_TPR; // 计数器清零源为周期匹配信号 P_TMR2_Ctrl->B.CKEGS = CB_TMR2_CKEGS_Rising; // 计数边沿为上升沿 P_TMR2_Ctrl->B.TMRPS = CB_TMR2_TMRPS_FCKdiv4;// 计数时钟为主时钟的 1/4 P_TMR2_TPR->W = 6000*Samp_Time; // 定时周期设为 48000---8ms P_TMR2_INT->B.TPRIE = CB_TMR2_TPRIE_Enable; // 使能定时器的周期中断 P_TMR_Start->B.TMR2ST = CB_TMR_TMR2ST_Start; // 启动定时器 } //===================================================================== // Description: IRQ1 interrupt source is XXX,used to XXX // Notes: //===================================================================== void IRQ1(void) __attribute__ ((ISR)); void IRQ1(void) { if(P_TMR0_Status->B.TCUIF) { P_TMR0_Status->B.TCUIF = 1; //Clear TCUIF flag (int)Position_Count[1] --; // 位置计数下溢出 Over_flag = 1; } if(P_TMR0_Status->B.TCVIF) { P_TMR0_Status->B.TCVIF = 1; //Clear TCVIF flag (int)Position_Count[1] ++; // 位置计数上溢出 Over_flag = 1; } } //===================================================================== // Description: IRQ4 interrupt source is XXX,used to XXX // Notes: //===================================================================== void IRQ4(void) __attribute__ ((ISR)); void IRQ4(void) { long Temp; if(P_TMR2_Status->B.TPRIF) { P_TMR2_Status->B.TPRIF = 1; Position_Count[0] = P_TMR0_TCNT->W; if(Position_Count[0] < Old_Position_Count) // 计算位置增量 { if(Over_flag > 0) //1 正转 , 上溢 Temp = (0xffff - Old_Position_Count) + Position_Count[0] + 1; else //0 反转 , 没有溢出 { Temp = Old_Position_Count - Position_Count[0]; Temp = -Temp; } } else { if(Over_flag > 0) // 反转 , 溢出 { Temp = (0xffff - Position_Count[0]) + Old_Position_Count + 1; Temp = - Temp; } else // 正转 , 没有溢出 Temp = Position_Count[0] - Old_Position_Count; } Over_flag = 0; Old_Position_Count = Position_Count[0]; Moto_Speed = (int)((Temp*7500)/Encoder_Data);// 速度计算 } } //===================================================================== // Description: IRQ6 interrupt source is XXX,used to XXX // Notes: //===================================================================== void IRQ6(void) __attribute__ ((ISR)); void IRQ6(void) { if(P_UART_Status->B.RXIF && P_UART_Ctrl->B.RXIE) MC75_DMC_RcvStream(); } |
评论
查看更多