![]() |
有在PIC單片機上使用編碼開關的程序代碼,小白想借鑒下 |
相當簡潔的代碼。需要時間消化。 |
bhjyqjs 發表于 2022-2-7 10:49 高手啊! |
http://www.zg4o1577.cn/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.zg4o1577.cn/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 妙啊~ ![]() ![]() ![]() |