提起编码器,可能大家并不陌生,因为这东西真的很常用,现在的主流编码器一般精度都是比较高的,基本上都是基于光栅的。毕竟用硬件用电刷做到512精度以上是很困难的,而且成本也是很高的,这里我就不多说什么了。
编码器一般共有三个主通道,每个主通道有分为两个分支;一个VCC,一个GND,一条屏蔽线。前两个通道一般是比较精确的脉冲信号,且之间有四分之一左右的相位差用来判断正反转的,第三通道基本上是旋转一周才会有一个脉冲信号的那种。
提到步进电机,就一定要有一个合适的电机驱动,个人是比较喜欢用L298n这款芯片的,因为它价格低,操作比较简单。
对于这个系统,我是用128的外部中断的下降沿触发方式来捕捉编码器的脉冲的,硬件连接方面电机驱动和主控芯片一定要注意地线的连接。
下面是程序的完整代码下载地址: http://www.51hei.com/f/bmma.rar
这里是delay.h ==================================================================== //根据CPU时钟频率选择 #ifndef F_CPU //#define F_CPU 7372800 //#define F_CPU 8000000 //#define F_CPU 11059200 //#define F_CPU 12000000 #define F_CPU 16000000 #endif //------------------------------------------------------------------------------ //1、2、3、5和10us的精确延时,用于需要精确时间的场合,比如DS18B20 //------------------------------------------------------------------------------ #if F_CPU == 7372800 #define DELAY_1US NOP();NOP();NOP();NOP();NOP();NOP();NOP() #define DELAY_2US DELAY_1US;DELAY_1US #define DELAY_3US DELAY_1US;DELAY_1US;DELAY_1US #define DELAY_5US DELAY_2US;DELAY_3US #define DELAY_10US DELAY_5US;DELAY_5US #elif F_CPU == 8000000 #define DELAY_1US NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP() #define DELAY_2US DELAY_1US;DELAY_1US #define DELAY_3US DELAY_1US;DELAY_1US;DELAY_1US #define DELAY_5US DELAY_2US;DELAY_3US #define DELAY_10US DELAY_5US;DELAY_5US #elif F_CPU == 11059200 #define DELAY_1US NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP() #define DELAY_2US DELAY_1US;DELAY_1US #define DELAY_3US DELAY_1US;DELAY_1US;DELAY_1US #define DELAY_5US DELAY_2US;DELAY_3US #define DELAY_10US DELAY_5US;DELAY_5US #elif F_CPU == 12000000 #define DELAY_1US NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP() #define DELAY_2US DELAY_1US;DELAY_1US #define DELAY_3US DELAY_1US;DELAY_1US;DELAY_1US #define DELAY_5US DELAY_2US;DELAY_3US #define DELAY_10US DELAY_5US;DELAY_5US #elif F_CPU == 16000000 #define DELAY_1US NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP() #define DELAY_2US DELAY_1US;DELAY_1US #define DELAY_3US DELAY_1US;DELAY_1US;DELAY_1US #define DELAY_5US DELAY_2US;DELAY_3US #define DELAY_10US DELAY_5US;DELAY_5US #endif //------------------------------------------------------------------------------ //函数声明 //------------------------------------------------------------------------------ void delay_nus(unsigned int);//<10us时误差较大,用于无须精确延时的场合 void delay_nms(unsigned int); #endif//__DELAY_H ==================================================================== 这里是delay.c ==================================================================== //|文件名称|delay.c //|--------|-------------------------------------------------------------------- //|描 述|延时文件 //|--------|-------------------------------------------------------------------- //|说 明|delay_us(unsigned int time)用于不需精确定时的场合,<10us时误差较大 //| |若要精确定时用delay.h里的宏 //|--------|-------------------------------------------------------------------- //|调用文件|delay.h //|--------|-------------------------------------------------------------------- //|作 者| //|--------|-------------------------------------------------------------------- //|版 本| //|--------|-------------------------------------------------------------------- //|时 间| //|--------|-------------------------------------------------------------------- //|E-mail | //|--------|-------------------------------------------------------------------- //|开发环境|ICCAVR6.31 //============================================================================== #include "delay.h" #if F_CPU == 7372800 void delay_nus(unsigned int time) { unsigned int i; for(i=0;i<time;i++) { NOP(); } } void delay_nms(unsigned int time) { unsigned int i,j; for(i=0;i<time;i++) { for(j=0;j<1045;j++); } } #elif F_CPU == 8000000 void delay_nus(unsigned int time) { unsigned int i; for(i=0;i<time;i++) { NOP();NOP(); } } void delay_nms(unsigned int time) { unsigned int i,j; for(i=0;i<time;i++) { for(j=0;j<1178;j++); } } #elif F_CPU == 11059200 void delay_nus(unsigned int time) { unsigned int i; for(i=0;i<time;i++) { NOP();NOP();NOP();NOP();NOP(); } } void delay_nms(unsigned int time) { unsigned int i,j; for(i=0;i<time;i++) { for(j=0;j<1578;j++); } } #elif F_CPU == 12000000 void delay_nus(unsigned int time) { unsigned int i; for(i=0;i<time;i++) { NOP();NOP();NOP();NOP();NOP(); } } void delay_nms(unsigned int time) { unsigned int i,j; for(i=0;i<time;i++) { for(j=0;j<1713;j++); } } #elif F_CPU == 16000000 void delay_us(unsigned int time) { unsigned int i; for(i=0;i<time;i++) { NOP();NOP();NOP();NOP();NOP();NOP(); NOP();NOP();NOP();NOP(); } } void delay_ms(unsigned int time) { unsigned int i,j; for(i=0;i<time;i++) { for(j=0;j<2288;j++); } } #endif ==================================================================== 这里是dianji.h ==================================================================== #ifndef __DIANJI_H #define __DIANJI_H #define EN_1 PORTC|=(1<<0) #define EN_0 PORTC&=~(1<<0) void one_circle(void); void circle(unsigned int xcircle); #endif ==================================================================== 这里是dianji.c ==================================================================== #include"dianji.h" #include"delay.h" #include<iom128v.h> /*步进电机旋转一周子函数*/ void one_circle(void) { unsigned int i; for(i=0;i<3200;i++) { EN_1; delay_us(100); EN_0; delay_us(100); } } /*步进电机根据编码器计算的数值旋转任意角度子函数*/ void circle(unsigned int xcircle) { unsigned int i,j; for(j=0;j<xcircle;j++) { for(i=0;i<3;i++) { EN_1; delay_us(100); EN_0; delay_us(100); } } } ==================================================================== 这里是caiji.h ==================================================================== #ifndef __CAIJI_H #define __CAIJI_H //宏定义595 #define SCK_0 PORTB&=~(1<<PB4) #define SCK_1 PORTB|=(1<<PB4) #define LCK_0 PORTB&=~(1<<PB5) #define LCK_1 PORTB|=(1<<PB5) #define SDI_0 PORTB&=~(1<<PB6) #define SDI_1 PORTB|=(1<<PB6) #define DIR_0 PORTC&=~(1<<1) #define DIR_1 PORTC|=(1<<1) void init_xianshi(void); void send_595(unsigned char dat); void jiaoduzhuanhuan(void); #endif ==================================================================== 这里是caiji.c ==================================================================== #include"caiji.h" #include"dianji.h" #include<iom128v.h> #include<macros.h> #include<math.h> //一些变量的定义 int k=0; unsigned int x=1,d=0,c=0,cir=0; unsigned int a,aa,q,angle=0,p=0; //595(数码管)显示数组 unsigned char led[]= { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F, // 9 }; //外部中断0~3向量号码 #pragma interrupt_handler Zhongduan_0:2 #pragma interrupt_handler Zhongduan_1:3 #pragma interrupt_handler Zhongduan_2:4 //端口输入输出初始化 void init_xianshi(void) { DDRA=0XFF; DDRB=0XFF;//595控制口 DDRC=0XFF;//正反转提示LED PORTC=0XFF;//LED初始化(暗) } //595串入一字节并处发送一字节子函数 void send_595(unsigned char dat) { unsigned char i; LCK_0; SDI_1; SCK_0; //上面的三条语句为了初始化端口状态 for(i=0;i<8;i++) { LCK_0;//时钟线拉低 if(dat&0x80) SDI_1; else SDI_0; dat=dat<<1; delay_us(100); LCK_1; //时钟线拉高将数据读入595的移位寄存器 delay_us(100); } SCK_1; //发送数据到并行端口 SCK_0; } void jiaoduzhuanhuan(void) { init_xianshi(); EIMSK=0X0F; EICRA=0XAA; while(1) { if(a!=aa) /*如果有角度变化就执行下面的程序*/ { angle++; if(!(PING&0X04)) cir++; while(cir) { if(!k) { delay_ms(800); if(d<=3) one_circle(); d++; } } if(!(PING&0X02)) { while(PING&0X01) { DIR_0; circle(1); p++; while(p==angle); } while(PING&0X01); if(q=-1)//正转 DIR_1; circle(1); if(q==1) //反转 DIR_1; } aa=a; if(!x) { PORTC=0X00; } } /*下面为数码管显示编码器当前计数的数值*/ PORTA=0X08; send_595(0x00); send_595(led[abs(k)%10]); PORTA=0X01; send_595(0x00); send_595(led[(abs(k)%100)/10]); PORTA=0X02; send_595(0x00); send_595(led[(abs(k)%1000)/100]); PORTA=0X04; send_595(0x00); send_595(led[abs(k)/1000]); SEI(); /*使能中断*/ } } void Zhongduan_0(void) { CLI(); x=0; ////////////////// if(PIND&0X02) q=-1; if(!(PIND&0X02)) q=1; //////////////// k=k+q; SEI(); } void Zhongduan_1(void) { CLI(); if(PIND&0X01) q=1; k=k+q; if(abs(k)==10000) { k=0; } a=k; //EIMSK=0X0E; SEI(); } void Zhongduan_2(void) { CLI(); k=0; SEI(); } ==================================================================== 这里是main.c ==================================================================== #include<iom128v.h> #include<macros.h> #include"delay.h" #include"caiji.h" #include"dianji.h" void init(void) { DDRC=0X03; PORTC=0X00; } void main(void) { init(); //初始化子函数 jiaoduzhuanhuan(); //主程序的实现 } ==================================================================== 程序中涉及到了一些嵌套,如果不明白的话可以给我留言哦!^_^