论坛风格切换切换到宽版
  • 10180阅读
  • 27回复

51单片机检测光电旋转编码器每周实际脉冲数 [复制链接]

上一主题 下一主题
离线BG4UVR
 
发帖
11288
只看楼主 倒序阅读 0楼 发表于: 2006-10-04
由于工作需要,写了这个程序来实际使用,感觉效果还可以。特记录在此,供有相同或相似需要的朋友查看。


程序代码

/******************************************************************
** 文件名: main.c
** 创建人: 飘扬
** 日 期: 2006.10.04
** 修改人:
** 日 期:
** 描 述: 本程序使用伟纳300a型实验板,来检测光电旋转编码器的实际每周
**       输出脉冲数。程序中,定时器0用于8位数码管动态扫描定时,时间
**       为1ms(12mhz晶振)。定时器1工作于模式1,计数器方式,直接测量
**       接在t1脚的脉冲个数。外部中断0,工作于边沿触发方式,接在旋转
**       编码器的z信号输出上,用于检测编码器完整旋转一周。8位数码管,
**       接成动态扫描,接在p0和p2口。左4位,用来显示上一周的实际脉冲
**       数,右4位,用来显示当前周的脉冲数。
**
**       实际使用,感觉效果还可以。程序准确的测量出某牌光电旋转编码
**       器(400脉冲),实际工作时,双路信号输出脉冲数量不等,及脉冲
**       数与标称值的误差情况。
**
**       本程序的显示部分,直接修改于伟纳提供的数码管显示1-8例程。
**----------------------------------------------------------------*/

#include <reg51.h>
#include <intrins.h>

unsigned char data dis_digit;
unsigned char code dis_code[11]={0xc0,0xf9,0xa4,0xb0,   // 0, 1, 2, 3
          0x99,0x92,0x82,0xf8,0x80,0x90, 0xff};// 4, 5, 6, 7, 8, 9, off
unsigned char data dis_buf[8];
unsigned char data dis_index;

unsigned int counter1,counter2;     //左右计数器数值

void main()
{
  p0 = 0xff;
  p2 = 0xff;
  tmod = 0x51;   //定时器0工作在模式1定时器方式,定时器1工作在模式1计数器方式
  th0 = 0xfc;
  tl0 = 0x17;
  th1 = 0;
  tl1 = 0;
  ie = 0x83;     //开定时器0中断和外部中断0
  it0 = 1;     //外部中断0为边沿触发方式
//显示初始化
  counter1=0;     //右测显示的本周当前脉冲数
  counter2=0;     //左测显示的上一周脉冲数

  dis_digit = 0xfe;
  dis_index = 0;

  tr0 = 1;
//主程序
  tr1 = 1;
  while(1){
    counter1=(th1*0xff)+tl1;
    dis_buf[0] = dis_code[0x0a];
    dis_buf[1] = dis_code[counter2/100];
    dis_buf[2] = dis_code[(counter2%100)/10];
    dis_buf[3] = dis_code[counter2%10];
    dis_buf[4] = dis_code[0x0a];
    dis_buf[5] = dis_code[counter1/100];
    dis_buf[6] = dis_code[(counter1%100)/10];
    dis_buf[7] = dis_code[counter1%10];    
  }
}

//外部中断0
void int0() interrupt 0
{
  tl1=0;
  th1=0;
  counter2=counter1;
}

void timer0() interrupt 1
// 定时器0中断服务程序, 用于数码管的动态扫描
// dis_index --- 显示索引, 用于标识当前显示的数码管和缓冲区的偏移量
// dis_digit --- 位选通值, 传送到p2口用于选通当前数码管的数值, 如等于0xfe时,
//           选通p2.0口数码管
// dis_buf   --- 显于缓冲区基地址  
{
  th0 = 0xfc;
  tl0 = 0x17;
 
  p2 = 0xff;                   // 先关闭所有数码管
  p0 = dis_buf[dis_index];         // 显示代码传送到p0口
  p2 = dis_digit;                 //

  dis_digit = _crol_(dis_digit,1);   // 位选通值左移, 下次中断时选通下一位数码管
  dis_index++;                 //
           
  dis_index &= 0x07;         // 8个数码管全部扫描完一遍之后,再回到第一个开始下一次扫描
}
离线BG4XCR
发帖
33381
只看该作者 1楼 发表于: 2006-10-04
收藏了!!1
离线BG4ABM
发帖
1139
只看该作者 2楼 发表于: 2006-10-04
能改成汇编的发上来吗?我最近也在搞一个用旋转编码器的计数电路,但还看不懂用c编写的程序。
离线BG4UVR
发帖
11288
只看该作者 3楼 发表于: 2006-10-04
'
能改成汇编的发上来吗?我最近也在搞一个用旋转编码器的计数电路,但还看不懂用c编写的程序。
'

这两天搞这个编码器,头痛死我了

至于汇编,只是在初学51时用过一段时间,现在指令基本都忘得差不多了。劝您花点时间,学一下c,真的好很用,不骗你。而且也不是很难学,以我高中都没毕业的水平,花些时间都可以简单使用了,相信您也一定能学会

另外,这个编码器的检测问题,我过几天有时间,还会上一个新的程序。新程序不再是检测脉冲数了,而是检测a、b两路脉冲的相位准确性。理由是,近两天研究发现,廉价的编码器,并不是输出脉冲数量不可靠,更严重的问题在于,它两路输出脉冲的相位准确性可能不太好(这个结论有待于用新程序验证)。

先忙去了
离线BG4ABM
发帖
1139
只看该作者 4楼 发表于: 2006-10-04
很受鼓舞,一定抓紧时间学c。其实以前学校里都学过,只是从没用过,都忘了。

我买的是一个400多元的旋转编码器,买来时,用示波器看过,正转、反转时a、b两路相位都没问题,就是不知道转的圈数多了以后,相位会不会出现偏差。

期待你的相位检测程序。
离线BG4XCR
发帖
33381
只看该作者 5楼 发表于: 2006-10-04
'
很受鼓舞,一定抓紧时间学c。其实以前学校里都学过,只是从没用过,都忘了。
我买的是一个400多元的旋转编码器,买来时,用示波器看过,正转、反转时a、b两路相位都没问题,就是不知道转的圈数多了以后,相位会不会出现偏差。
期待你的相位检测程序。
'
哈哈,一圈不出偏差那多少圈都不会出偏差。一般编码器都有abz三相。z可以用来清零。结合z相使用不会有积累误差。两相的话可以用硬件实现鉴相。ab两相用逻辑电路互锁。正传屏蔽a。反转屏蔽b。

我常用的是测频率。也就是周期。
离线红猪
发帖
4980
只看该作者 6楼 发表于: 2006-10-04
多谢分享!!
离线BG4ABM
发帖
1139
只看该作者 7楼 发表于: 2006-10-04
'
哈哈,一圈不出偏差那多少圈都不会出偏差。一般编码器都有abz三相。z可以用来清零。结合z相使用不会有积累误差。两相的话可以用硬件实现鉴相。ab两相用逻辑电路互锁。正传屏蔽a。反转屏蔽b。
我常用的是测频率。也就是周期。
'
这位朋友,能否把这一点详细说一说,就是:“z可以用来清零。结合z相使用不会有积累误差。”
我买的那个就是带z相的,但就是不知道z相究竟有什么用,我做的那个东西对测量精度有一定要求的,迫切需要了解如何消除累计误差。
离线BG4UVR
发帖
11288
只看该作者 8楼 发表于: 2006-10-04
顶楼的程序已经发现有些问题了。就是编码器旋转速度越高,检测到的每周脉冲值越小。怀疑是执行中断程序时,影响了计数器计数。不过中断执行时,硬件计数器是否会停止计数,我没有找到相关资料,还请其他同学指点。

我写了一个通过脉冲边沿触发中断来进行双向旋转检测的版本,计数值很就准确了。不过这个程序也有个缺点,就是编码器在1/4个脉冲周期以内范围晃动时,如果正巧一个信号的状态有改变,会误向一个方向计数(原因是中断只能在下降沿触发,不能设置成上下沿都触发)。后来改进了算法后,这个问题是解决了,但新问题又出来了。就是改进过的程序效率太低了,只能以很低的速率进行检测。唉…… 仍然有待改进…… 学习学习再学习……
离线BG4XCR
发帖
33381
只看该作者 9楼 发表于: 2006-10-04
'
这位朋友,能否把这一点详细说一说,就是:“z可以用来清零。结合z相使用不会有积累误差。”
我买的那个就是带z相的,但就是不知道z相究竟有什么用,我做的那个东西对测量精度有一定要求的,迫切需要了解如何消除累计误差。
'
简单说,假设你的编码器是1200线的。也就是每圈1200个脉冲。两个输出ab,a和b相差1/4个周期。因此可以通过ab的相位先后来判断转向。z是零位脉冲。简单说就是每转一圈就输出一个脉冲。因此在多圈计数的时候可以作为整数。也就是即便受到1190个ab脉冲,但收到一个z相脉冲时就把1190个当作1200个有10个误差的。比如你要计长。需要编码器转30.5圈,你不要计ab之间的30.5x1200=36600个脉冲,有可能漏掉就不准了。最好的办法是计z相30个ab相600个,也就是你只要数630个脉冲就达到目标。相比之下出错的可能性就很小了。
离线BG4XCR
发帖
33381
只看该作者 10楼 发表于: 2006-10-04
'
顶楼的程序已经发现有些问题了。就是编码器旋转速度越高,检测到的每周脉冲值越小。怀疑是执行中断程序时,影响了计数器计数。不过中断执行时,硬件计数器是否会停止计数,我没有找到相关资料,还请其他同学指点。
我写了一个通过脉冲边沿触发中断来进行双向旋转检测的版本,计数值很就准确了。不过这个程序也有个缺点,就是编码器在1/4个脉冲周期以内范围晃动时,如果正巧一个信号的状态有改变,会误向一个方向计数(原因是中断只能在下降沿触发,不能设置成上下沿都触发)。后来改进了算法后,这个问题是解决了,但新问题又出来了。就是改进过的程序效率太低了,只能以很低的速率进行检测。唉…… 仍然有待改进…… 学习学习再学习……
'
鉴相最好用硬件!软件可以很省。而且很可靠。硬件电路也很简单。
离线BG4VEO
发帖
68
只看该作者 11楼 发表于: 2006-10-05
ssi接口的?
离线BG4XCR
发帖
33381
只看该作者 12楼 发表于: 2006-10-05
'
ssi接口的?
'
你说的诗绝对型编码器。那个太贵。普通用用不起的。abz三相的是增量型的。
离线BG4ABM
发帖
1139
只看该作者 13楼 发表于: 2006-10-05
'

简单说,假设你的编码器是1200线的。也就是每圈1200个脉冲。两个输出ab,a和b相差1/4个周期。因此可以通过ab的相位先后来判断转向。z是零位脉冲。简单说就是每转一圈就输出一个脉冲。因此在多圈计数的时候可以作为整数。也就是即便受到1190个ab脉冲,但收到一个z相脉冲时就把1190个当作1200个有10个误差的。比如你要计长。需要编码器转30.5圈,你不要计ab之间的30.5x1200=36600个脉冲,有可能漏掉就不准了。最好的办法是计z相30个ab相600个,也就是你只要数630个脉冲就达到目标。相比之下出错的可能性就很小了。
'
看明白了,不过我分析还是在高速和长距离的情况下z比较有用,如果是短距离和低速,只要旋转编码器质量过关,应该可以不用z
离线BG4ABM
发帖
1139
只看该作者 14楼 发表于: 2006-10-05
'
顶楼的程序已经发现有些问题了。就是编码器旋转速度越高,检测到的每周脉冲值越小。怀疑是执行中断程序时,影响了计数器计数。不过中断执行时,硬件计数器是否会停止计数,我没有找到相关资料,还请其他同学指点。
'
我估计这种情况就是在中断没有退出时,又有新的中断产生而发生漏计数了。我前一阵也写了一个计数的程序,每满1厘米就产生一个中断,开始觉得还可以,后来在中断里加了一段蜂鸣器程序,并用了较长的延时,结果发现快速旋转时会漏计数。再后来,我用keil进行了软件仿真,发现:当一个中断正在执行时,后面不管产生了多少中断,当前中断执行完后,单片机只再执行1次中断。
离线BG4XCR
发帖
33381
只看该作者 15楼 发表于: 2006-10-05
'
看明白了,不过我分析还是在高速和长距离的情况下z比较有用,如果是短距离和低速,只要旋转编码器质量过关,应该可以不用z
'
理论上讲超过一圈就应该用z。
离线BG4UVR
发帖
11288
只看该作者 16楼 发表于: 2006-10-05
'
我估计这种情况就是在中断没有退出时,又有新的中断产生而发生漏计数了。我前一阵也写了一个计数的程序,每满1厘米就产生一个中断,开始觉得还可以,后来在中断里加了一段蜂鸣器程序,并用了较长的延时,结果发现快速旋转时会漏计数。再后来,我用keil进行了软件仿真,发现:当一个中断正在执行时,后面不管产生了多少中断,当前中断执行完后,单片机只再执行1次中断。
'

应该不会是这个原因。顶楼的程序只用了2个中断,一个定时器中断,1ms一次,中断中的程序在1ms以内足可以完成,就算完不成,也只影响显示。另一个是z信号中断,这个中断每秒才产生几次,完全不至于没完成就又产生了新中断。

而且,把顶楼的程序2个中断修改成外部中断0高优先级,定时器中断低优先级,结果没有任何改善。

至于在中断中,硬件计数器是否仍然可以工作,我仍然是没找到相关说法
离线BG4ABM
发帖
1139
只看该作者 17楼 发表于: 2006-10-05
'

至于在中断中,硬件计数器是否仍然可以工作,我仍然是没找到相关说法 [表情]
'
你所说的硬件计数器是指单片机外面的电路,还是指单片机内的电路?如果是指单片机内的电路用keil仿真一下不就可以知道了吗?
离线BG4VEO
发帖
68
只看该作者 18楼 发表于: 2006-10-05
'
你说的诗绝对型编码器。那个太贵。普通用用不起的。abz三相的是增量型的。
'
绝对码和增量码好象都有ssi接口,不知道楼主怎么解决掉电之后的数据保存?
离线BG4XCR
发帖
33381
只看该作者 19楼 发表于: 2006-10-06
没见过ssi接口增量型/