我现在想用AVR单片机读取两个旋转编码器,要求是AB相输入的,频率不高4K左右,要考虑速
谢谢!! 顶一顶!! void EncoderDetect(uchar *p, uchar pinsta){
/*************************************************************
_____ ____ ____ ____ ____
A |____| |____| |____I____| |____| |____
I
_______ ____ ____ I ____ ____
B |____| |____| |__I__| |____| |______
I
前进 后退
--------> <---------
*************************************************************/
uchar cnt;
uchar i = *p;
cnt = i & 0x0f;
i = ((i >> 4) & 0x03);
pinsta = pinsta & 0x03;
cnt++;
{
if (cnt == 1) {
if(pinsta != 3) {goto EncoderDetect_LAB0;}
}else if (cnt == 2) {
if(pinsta == 3) {cnt--; goto EncoderDetect_LAB2;}
if(pinsta == 0) {goto EncoderDetect_LAB0;}
i = pinsta;
}else if (cnt == 3) {
if(pinsta == 0) {
if(i == 2) {i |= 0x04; goto EncoderDetect_LAB1;}
else if(i == 1) {goto EncoderDetect_LAB1;}
goto EncoderDetect_LAB0;
}
if(pinsta != 3) {cnt--; goto EncoderDetect_LAB2;}
goto EncoderDetect_LAB0;
EncoderDetect_LAB1:
i = i | 0x08;
}else {
EncoderDetect_LAB0:
cnt = 0;
}
}
EncoderDetect_LAB2:
*p = (i << 4) | cnt;
} 谢谢!!慢慢研究一下!!! 2位为1表示后退(i = i | 0x04;) !
3位为1表示前进(i = i | 0x08;) !
放在主程序检测就行!
*p表示旋转编码器缓冲!
pinsta低两位表示AB状态! 当然查询不能太慢! 采用中断方式完全能满足 还是用个CPLD采集 然后 AVR读取 这样可靠一点 单片接负担小点 楼上的都太复杂了……
直接用两个外中断+两个普通端口:
比如INT0+Pxn1INT1+Pxn2
外中断触发从上升沿和下降沿中任选一个:然后,判断Pxn的电平,高电平计数器增加;低电平计数器减少;
如果想两倍频:那么外中断的触发选择双边沿触发:然后判断Pxn的电平和INTn电平相同的,计数器增加;不相同的计数器减小……
……
用AVR可以轻松应付,不过记得在外中断中开欠套,而且,最好系统跑16M以上频率…… 资源少的时候,如中断少的查询还是比较好!
我用89s52用查询做三个旋转编码器还可以! 最好先用电路把信号处理一下,然后送到单片机,那样比较好点。。。。。 收获了,谢谢各位!!
1、如果硬件处理的话,是不是在其I/O口加上一个103的电容就可以??
2、我也正在看“聪明孩子”你的书,你的书写得很好,看你的书好象看小说,不闷!!
按的书上的做法是,进入外部中断后,判断普通I/O口的电平来确定加数还是减数!!如何提高抗干扰,我的
想法在进入中断后,多次判断I/O的电平来确定是否有效,但是这样就降低速度怕会提脉冲!!你有什么好建议
谢谢!! “聪明孩子”,在吗?? 前几天利用Mega128做了光栅尺的计数器
A+ B+A- B- 接到单片机的外部中断(上升沿触发中断)
另外B+接到单片机的普通IO口
在A+对应的中断程序里判断B+对应的电平状态来判断光栅尺的方向
经过测试发现对于计数没有问题 不会丢失
但是好像对于方向的判断有点问题 我发现光栅尺朝一个方向运动的时候检测到B+的电平不稳定一会高一会低
呵呵现在手头没程序 只能这么说说~~ 另外还发现单片机有发热的状态~~~
不过应该属于正常的范围之内~ 呵呵 没人接棒 接着来说说了啊~~ 用LM3S带正交编码功能的可以非常容易做到,我们以前也有用AVR做的,读两个码盘的数据,占用大量CPU时间,影响CPU干其他事情,还容易出现丢码。
后来尝试使用LM3S,发现正交编码功能非常好用,不丢码也几乎不占用CPU时间。 1.加个74HC14 为什么呢? 因为假如做到4倍频,后面还要加个74HC86,所以是去扰+整形用(RC还是要的).然后再用4个INTX,4个普通GPIO.中断方式.非中断方式,就单独用个核,整个绝对式的也是不错的方式.--指4倍频.
2.如此这般,2个编码器.4倍频的实现就相当简单包括软件上.用M64/128做,不要可惜成本.或者中断扩展,再爬出几个GPIO来,呵呵.
3.最最容易的直接用STM32做,这个片子是ST为工控专门下的蛋.直接支持.(AVR没有什么优势.片上外设太少了).
4.俺的方法超爽.俺点到此,想通了,不用谢俺,谢谢你自己.对楼主加个103,建议有空时一定去看看邱关源的书,俺和他同宗. to 【12楼】 fangmcu 方谭
抗干扰的问题……如果这个系统存在干扰,建议你不要使用中断方式……查询方式最好……
不过说实话……一般用到编码器的场合,都应该使用屏蔽线,并保证信号良好……如果你想降低干扰,可以考虑
在编码器的AB线上增加上拉电阻……或者通过普通光耦(非高速光耦合)隔离的方式来滤掉较高频率的毛刺……
不知道你的应用场合如何,丢脉冲是很正常的,但是可以通过Z信号来校正。我应用的场合干扰算是比较夸张的,
都是继电器打来打去……一般不敢用长的普通导线……线的长度也在20cm以内。降低干扰固然重要,但是对于编码器
来说必要的校正才是王道。
能不能叫我“傻孩子”…… to【17楼】 Qhjh
两个通道用一个M88就可以了……为什么要用M64……4倍频不需要任何额外硬件……只要使用引脚电平变化中断配合INT0和INT1就可以实现…… 用硬件先处理下,如果不处理肯定会丢脉冲的,如果是远距离的接成两路485的,硬件处理可参照以下方法,正向的时候一路输出脉冲另一路输出高电平,反向的时候反过来,这样只要做正向反向计数既可,对照编码器的最高速度调整电路参数,这样可保证在有电工作器件不丢脉冲,当然停电后就不得而知了,这种处理在闸控上最少用了20年了 傻孩子的方法正解
远距离可用非门增强 1.现在做的产品上AVR已经不用了,谢谢指点.假如M88有多个中断的话,的确是个好事情.
2.加个86,软件容易搞,每个边沿都能统一到上(/或统一到下)沿触发.AVR的电平变化中断,用在这个方面,让人耳目一新,好方法. 谢谢“傻孩子”!!能否说一说,用Z相校正的思路!! 为什么要限定avr呢,现在32位arm哪个没有ab相接口。你们考虑问题可能还偏简单,看看伺服锁住时候的编码器信号看看,抖得要命。频率绝对大于4K。到时死都不知道怎么死。
【16楼】 Alexkey 提得就是很好的简易。能硬件做肯定选硬件。方法归方法,但是你会发现做的很累。。。。 台湾的伺服电机的光电编码器用的是CPLD实现的,电子最快的时候3000转
3000/60*1000*2=100k
伺服驱动器还要实现四倍频
楼主所说的4k 那应该是正常运行的时候,如果在抖动的情况下估计不止4k 瞬间的频率可能很高。就有可能会丢脉冲
还有我觉得中断可能还是查询来的快。中断进进出出要开销时钟的。
但是用了查询之后,最好其他事情不要做了。 谢谢"tclandmei 小罗",我不是太看得明白你的程序,能否说一说思路!! 太久没有看和用这个函数了!
有点忘!回去看看明天再说说!
哈哈!都是没有作好注释的祸! /*
* 先说一下思路:
*
* typedef struct {
* ucahr cnt; // cnt == 1~3表示AB的三个状态
* uchar pinstabk; // 记录上次AB
* uchar encoderout; // 解码输出
* }EncoderBuff;
* p 指向的是上面的数据类型。我为了省RAM所以写可能有点不好理解,用一个字节表示了
*
*/
void EncoderDetect(uchar *p, uchar pinsta)
{
/*************************************************************
___1__ ____ ____ ____ ____
A |____| |____| |____I____| |____| |____
I
___1____ ____ ____ I ____ ____
B |____| |____| |__I__| |____| |______
I
前进 后退
--------> <---------
*************************************************************/
uchar cnt;
uchar i = *p;
cnt = i & 0x0f;
i = ((i >> 4) & 0x03);
pinsta = pinsta & 0x03;
cnt++;
{
if (cnt == 1) { // cnt == 1表示要检测到AB == 11作为起始状态才进行后续
if(pinsta != 3) { // 表示状态没有变,cnt = 0,下次继续检测cnt == 1的状态
goto EncoderDetect_LAB0;
}
}else if (cnt == 2) { // cnt == 2表示AB == 10 ,AB == 01, AB == 00
if(pinsta == 3) { // 起始状态AB == 11没有变化
cnt--;
goto EncoderDetect_LAB2;
}
if(pinsta == 0) { // AB == 00, 丢弃本帧
goto EncoderDetect_LAB0;
}
i = pinsta; // 记录AB == 10 ,AB == 01,
}else if (cnt == 3) { // 已经记录了AB == 10 ,AB == 01,
if(pinsta == 0) { // 当AB == 00,则一帧 11 -> (10 或 01) -> 00 被检测
/* 与上一次cnt == 2比较AB,如果相同表示一帧完整解码输出,不同丢弃本帧*/
if(i == 2) {
i |= 0x04; // 输出减
goto EncoderDetect_LAB1;
}else if(i == 1) {
goto EncoderDetect_LAB1;
}
goto EncoderDetect_LAB0;
}
if(pinsta != 3) { // 如果AB没有变为00,则继续等待检测
cnt--;
goto EncoderDetect_LAB2;
}
goto EncoderDetect_LAB0; // AB == 11 ,丢弃本帧
EncoderDetect_LAB1:
i = i | 0x08; // 输出加
}else {
EncoderDetect_LAB0:
cnt = 0;
}
}
EncoderDetect_LAB2:
*p = (i << 4) | cnt;
} 继续学习 mark mark 谢谢,正好用的着 Gorgon_Meducer 发表于 2009-4-20 12:30
楼上的都太复杂了……
直接用两个外中断+两个普通端口:
比如INT0+Pxn1INT1+Pxn2
大侠,如果外中断一直被触发,那么主程序里面的程序(就是非中断的程序)怎么执行呢?谢谢! baikenor 发表于 2016-10-27 15:27
大侠,如果外中断一直被触发,那么主程序里面的程序(就是非中断的程序)怎么执行呢?谢谢! ...
如果一直触发,那么就要看看这种一直触发是否合理了。脱离应用考虑极端情况是意义不大的。
你是否可以描述下具体的应用场景呢? Gorgon_Meducer 发表于 2016-11-3 18:35
如果一直触发,那么就要看看这种一直触发是否合理了。脱离应用考虑极端情况是意义不大的。
你是否可以描 ...
受宠若惊!大侠竟然回复了!我看到大侠的方案是把脉冲接到中断引脚上,如果一直有脉冲,MCU还有时间处理其他的工作吗?谢谢! baikenor 发表于 2016-11-7 16:31
受宠若惊!大侠竟然回复了!我看到大侠的方案是把脉冲接到中断引脚上,如果一直有脉冲,MCU还有时间处 ...
这里就是一个典型的“凭感觉得出结论的例子”——嵌入式开发是可以定量分析的,不能凭感觉。
就这个例子来说,你只说一只有脉冲,这个谁都没有办法回答你的问题——脉冲频率是多少?处理器主频是多少,处理器的指令周期和主频是什么关系(早期的51,指令周期和主频是 12分之一的关系)。有了这些信息,我们才有可能定性的评估你这个问题。如果你只单纯从人类的感官来思考——作为人类,也许1K已经很快了,也许10K已经很快了,但是对于一个跑12M的CPU来说,可能仍然是慢动作。所以针对你的问题,具体看了。 Gorgon_Meducer 发表于 2016-12-2 15:49
这里就是一个典型的“凭感觉得出结论的例子”——嵌入式开发是可以定量分析的,不能凭感觉。
就这个例子 ...
大侠,如果是10khz频率,单片机是在12MHZ下运行的MEGA16,并且MEGA16还有每50ms通过串口以9600波特率发送20个字节的任务,具体的时间消耗应该怎样计算呢,一般单片机程序消耗时间应该怎样计算呢?请大侠给个思路,谢谢!
页:
[1]