有在PIC单片机上使用编码开关的程序代码,小白想借鉴下 |
相当简洁的代码。需要时间消化。 |
bhjyqjs 发表于 2022-2-7 10:49 高手啊! |
http://www.51hei.com/bbs/dpj-233399-1.html 这个也是很简洁,又新颖的EC11驱动 |
hewayking 发表于 2024-7-2 17:06 试了,很棒!史上最简洁的代码。 |
个人做法是a下降沿中断 中断后 判断b高低 确定正反转![]() |
之前测试很多代码,效果均不理想,表现为正转、反转有误判,从而导致计数不对。我想到的办法是得到方向数据后(比如正转定义为1,反转定义为0),先修正方向,再结合中断和方向二者,决定是否累加或累减计数值。方案是建立一个数组,包括10个元素,用来存储获得的方向,任何时刻记录的是最近十次获得的方向数据,对数组的10个元素进行累加,和超过5时,强制为正方向,反之为负方向。实测效果有所改善,计数值绝不会忽大忽小、重复出现等情况了。遗憾的是如果你反复正转、反转1下,那计数还是会有问题,即不会保持不变。但这种使用场景很少见吧?真要微调,你多转几下,再反过来多转几下就行。有人会说,实际卡顿感与计数反映会不同步吧?理论上讲是这样,但单片机速度很快,实际感觉不到不同步。 |
要想多快都不丢步(相对哈,快到中断处理都来不及不算哈),必须在中断里来处理。这种中断+轮询判断的方式,依然会丢步的。 |
这东西还是需要用状态机来写,只要描述好正常状态迁移的关系,异常状态处理,硬件上消抖不消抖都是可以处理好的。 |
完美的代码效果应该是转动一下只计数一下,不能多增也不能不增,最重要的是!不论转得多快还是多慢,都如此,那才是好代码!从这个标准来说,我试验了上10款作者自诩为非常不错的代码,均不合格!当然我自己也编不出合格的代码来,一度怀疑是我买的EC11编码器在硬件方面不合格,因为只有上拉电阻。没有消抖电容。但符合这样标准的编码器效果是普遍存在的,比如十几、二十年前的进口功放机,就采用了旋转编码器调整音量,那编码器的使用效果才是我追求的,现在我的一个项目卡在编码器上,怎么都不好用,肯定采用中断来实现,还没找到合适的代码,下一步寄加消抖电容看看谁的代码最理想,再来汇报。 |
楼主的代码很不错,我这边有另一种算法,也很精简EC11编码器基于运算解码的算法(原创),汇编后大小也基本一样,有一个算法甚至更小 |
很好的优化方法,学习了! |
diyage 发表于 2023-11-25 19:55 你说的这种情况,确实存在,也不能旋转过快,且在部分EC11上表现明显,即存在挑EC11现象,,后来我尝试将KB对地接的104电容换成105的就改善了,也不挑EC11了,你可试试。 |
下载学习一下,正准备用这个一定位一脉冲编码器。 |
刘佑红 发表于 2023-9-25 15:48 我跟你用的一样,但是发现转快了丢码,慢很好 ![]() |
unsigned char key=0; static bit nextA; if (KA()!=nextA) {nextA=KA(); if (nextA==1) {if (KB()==1) key=6;else key=5;} else {if (KB()==0) key=6;else key=5;} } return key; |
haokey 发表于 2021-7-7 12:20 你这样是不行的,会重复的加或减 |
以下是我之前采用拿来主义得到的,只对判断后执行部分稍作修改,应用还不错。 /************************参数设置***************************/ void canshu() //EC11旋转编码器一定位一脉冲 { static bit LastA = 0; //EC11旋转编码器的A引脚上一次的状态 static bit LastB = 0; //EC11旋转编码器的B引脚上一次的状态 if(KA != LastA) //判断EC11旋转编码器A引脚是否等于上一次的状态 { if(KA == 0) //EC11旋转编码器旋转后,判断KA是否是低电平状态 { if(KB) //判断KB引脚当前状态,高电平则为正转 {num++;} else {num--;} } LastA = KA; //更新编码器上一个状态暂存变量 LastB = KB; //更新编码器上一个状态暂存变量 } } 现在看来LsaB变量似乎没有用,有空了去掉它试试。对于正反向不同的EC11,我是通过调换num变量的加减方向来解决的。 |
我用一个外中断,使用正常。 |
一般方法:先判断跳变(同时触发抖动计时连续判断),再判断另一个io的高低,![]() |
herui2128 发表于 2023-9-22 15:41 用一个外中断即可
|
谢谢楼主分享,我用的STC15W408AS。用楼主的例程,采用两个外部中断来检测脉冲。能正常检测到正转和反转。但是旋转编码器的旋转速度稍微快点,就容易丢脉冲(脉冲速度快了,连成一片了),导致单片机采不到或者误采到B相。求一下速度快点的解决办法。count1和count2是正转和反转的脉冲计数,以后用于计算角度使用。 void exint0() interrupt 0 //INT0中断入口 { if(!P32 && PinA_O && P33) { count1++; } PinA_O = P32; } //外部中断服务程序1 void exint1() interrupt 2 //INT1中断入口 { if(!P33 && PinB_O && P32) { count2++; } PinB_O = P33; } |
hi等你 发表于 2023-6-28 16:05 能否共享一下 |
微笑的小小 发表于 2022-11-8 17:51 STC15W的引脚默认是准双向口,STC8H的引脚默认是高阻,初始化的时候需要设置为准双向口。 |
EC11不需要用延时,放在中断程序中,占用资源很少,用的很稳定。 |
lkc8210 发表于 2023-6-27 11:30 ![]() 我就是不用定时器和中断,这个资源用在更重要的地方,只需要判断10和11就行,反转判断01和11. 已经成品用了好久了,手感也很好 |
hi等你 发表于 2023-4-17 10:59 看到"延时毫秒"和"中断和定时器都不需要" 就知道你还没弄懂 |
hi等你 发表于 2023-4-17 10:59 [em17 ![]() ![]() |
不用这么复杂,只要判断两个脚是11,然后延时毫秒多少。忘了,再判断是不是10,就说明 它旋转了,如果判断出来是01就是反方向旋转了,中断和定时器都不需要,主程序留在 等待的时候加一丢丢延时再执行就ok了 |
stc8h默认是高阻 |
//00准双向 01推挽输出 10高阻输入 11开漏输出高阻输入 P3M1 = B0000_0000; P3M0 = B1010_0000; 增加这个后就可以了 |
这个代码我在STC15W408AS上调试通过。 为什么在STC8H1K08上不行,就是没有操作EC11旋转编码器,电脑串口 不断收到数据。 |
hewayking 发表于 2022-2-16 14:19 我也认为这种方法更好。 http://www.51hei.com/bbs/dpj-221520-1.html 这是用十速51mcu做的直流电机定位功能,非常可靠准确,用于EC11要加104电容。 一定要用软件消抖,要增加2个全局bit变量用于存储AB引脚之前的状态,但这样增加了不少mcu开销。 |
hewayking 发表于 2022-2-16 14:19 难打别人不都是这样吗? |
个人做法硬件加104电容 一个接外部中断一个接普通IO 中断后读普通IO高低 正转高或低 反转低或高控制++ -- 可靠高效无敌 一般人我不告诉他![]() |
齿轮传动,小齿轮带大齿轮,用大齿轮带动编码器旋转,即可降低转速 |
cn_zhx 发表于 2022-2-8 10:18 什么是加减速器的方法? 可以详细说说吗? |
本帖最后由 cn_zhx 于 2022-2-8 14:43 编辑 其实,这里AB数据线产生的是格雷码,如果我们采集时采用判断AB两线的变化,即,A或B来下降沿时,作出4次判断,可以避免楼上所说的哆嗦,但是,要求采样频率要跟得上,可以采用加减速器的方法, |
lkc8210 发表于 2022-1-28 14:03 为什么我知道是因为我以前就是用类似的算法,后来全部换成更复杂的算法了。 看应用,如果误加减影响不大则可以用,否则需要更鲁棒性的算法 |
bhjyqjs 发表于 2022-2-7 10:49 妙啊~ ![]() ![]() ![]() |