標題: 51單片機旋轉(zhuǎn)編碼器模塊測試代碼 [打印本頁]

作者: pengxxx    時間: 2020-5-5 15:28
標題: 51單片機旋轉(zhuǎn)編碼器模塊測試代碼
模塊圖片
測試平臺:STC89C516單片機 晶振:12MHz
其他單片機(STC12單片機)或晶振,請在程序的LCD1602.crotary_encoder.c文件中修改延時函數(shù)


連線如圖(連線的接口在程序的port.h文件里)




測試代碼功能:
將程序下載到開發(fā)板,LCD顯示0FF,顯示數(shù)字000.
按下旋轉(zhuǎn)編碼器的按鍵,OFF變?yōu)?/font>ON,轉(zhuǎn)動旋轉(zhuǎn)編碼器就可以在LCD1602中看到數(shù)字變化.
再次按下旋轉(zhuǎn)按鍵,ON變?yōu)?/font>OFF,此時轉(zhuǎn)動旋轉(zhuǎn)編碼器不可以在LCD1602中看到數(shù)字變化.

結(jié)尾:
    測試程序的注釋也比較詳細,自我感覺這個程序?qū)^慢的轉(zhuǎn)速和正常的轉(zhuǎn)速的兼容性都比較好,只有極少數(shù)情況出現(xiàn)丟步,已經(jīng)實現(xiàn)較好的實現(xiàn)了旋轉(zhuǎn)編碼器的功能了.

本帖測試程序參考過以下帖子
http://www.torrancerestoration.com/bbs/dpj-93972-1.html

單片機源程序如下:
  1. #include <intrins.h>
  2. #include "public.h"
  3. #include "rotary_encoder.h"
  4. #include "LCD1602.h"
  5. #include "port.h"

  6. void rotary_encoder_delay50us()//12.000MHz
  7. {
  8.         u8 i;
  9.         _nop_();
  10.         i=22;
  11.         while(--i);
  12. }

  13. void rotary_encoder_delay10ms()        //12.000MHz
  14. {
  15.         u8 i,j;

  16.         i=20;
  17.         j=113;
  18.         do
  19.         {
  20.                 while (--j);
  21.         }while (--i);
  22. }

  23. //旋轉(zhuǎn)編碼器初始化
  24. void rotary_encoder_init()
  25. {
  26.         ROTARY_ENCODER_CLK=1;
  27.         ROTARY_ENCODER_DT=1;
  28.         ROTARY_ENCODER_SW=1;
  29.        
  30.         IT0=1;
  31.         EX0=1;
  32.         EA=1;
  33.        
  34.         LCD1602_print_char(0,0,'O');
  35.         LCD1602_print_char(0,1,'F');
  36.         LCD1602_print_char(0,2,'F');
  37.        
  38.         LCD1602_print_char(1,0,'0'+0);
  39.         LCD1602_print_char(1,1,'0'+0);
  40.         LCD1602_print_char(1,2,'0'+0);
  41. }

  42. //掃描旋轉(zhuǎn)編碼器,返回值為1代表正轉(zhuǎn),返回值為0代表反轉(zhuǎn),返回值為0xFF代表未旋轉(zhuǎn)或旋轉(zhuǎn)錯誤
  43. u8 scan_rotary_encoder()
  44. {
  45.         u8 rotary_encoder_state;//旋轉(zhuǎn)編碼器狀態(tài)
  46.         u16 forced_out;//強制退出
  47.        
  48.         //旋轉(zhuǎn)編碼器狀態(tài)
  49.         //如果在剛開始ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT都為1,則狀態(tài)為1
  50.         //如果在剛開始ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT都為0,則狀態(tài)為0
  51.         if((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT)) rotary_encoder_state=1;
  52.         else if((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)) rotary_encoder_state=0;
  53.        
  54.         //ROTARY_ENCODER_CLK和ROTARY_ENCODER_DT為同一電平時檢測
  55.         if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  56.         {
  57.                 //用最多150ms時間來等待ROTARY_ENCODER_CLK電平或ROTARY_ENCODER_DT電平變化(此時AB為11或00)
  58.                 forced_out=3000;
  59.                 while(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  60.                 {
  61.                         --forced_out;
  62.                         rotary_encoder_delay50us();
  63.                         if(!forced_out) return 0xFF;//超時則強制退出,返回錯誤碼
  64.                 }
  65.                
  66.                 //每次電平變化必定旋轉(zhuǎn)了編碼器,電平變化后要消抖
  67.                 rotary_encoder_delay10ms();
  68.                
  69.                 //當ROTARY_ENCODER_CLK為低電平,ROTARY_ENCODER_DT為高電平時
  70.                 if((!ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))
  71.                 {
  72.                         //用150ms時間來等待ROTARY_ENCODER_DT電平變化(此時AB為01)
  73.                         forced_out=3000;
  74.                         while((!ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))
  75.                         {
  76.                                 --forced_out;
  77.                                 rotary_encoder_delay50us();
  78.                                 if(!forced_out) return 0xFF;//超時則強制退出,返回錯誤碼
  79.                         }
  80.                        
  81.                         //每次電平變化必定旋轉(zhuǎn)了編碼器,電平變化后要消抖
  82.                         rotary_encoder_delay10ms();
  83.                        
  84.                         //當ROTARY_ENCODER_CLK為低電平,而且ROTARY_ENCODER_DT也為低電平
  85.                         //或ROTARY_ENCODER_CLK為高電平,而且ROTARY_ENCODER_DT也為高電平(AB為11或00)
  86.                         //此時  AB從11到01到00  或  AB從00到01到11
  87.                         if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  88.                         {
  89.                                 //如果旋轉(zhuǎn)編碼器的狀態(tài)為1則返回1,代表正轉(zhuǎn)一下
  90.                                 if(rotary_encoder_state) return 1;
  91.                                 //如果旋轉(zhuǎn)編碼器的狀態(tài)為0則返回0,代表反轉(zhuǎn)一下
  92.                                 else return 0;
  93.                         }
  94.                         //若AB不為11或不為00則返回旋轉(zhuǎn)編碼器錯誤碼
  95.                         else return ROTARY_ENCODER_ERROR;
  96.                 }
  97.                 //當ROTARY_ENCODER_CLK為高電平,ROTARY_ENCODER_DT為低電平時
  98.                 else
  99.                 {
  100.                         //當ROTARY_ENCODER_CLK為高電平,ROTARY_ENCODER_DT為低電平時
  101.                         if((ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT))
  102.                         {
  103.                                 //用150ms時間來等待ROTARY_ENCODER_CLK電平變化(此時AB為10)
  104.                                 forced_out=3000;
  105.                                 while((ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT))
  106.                                 {
  107.                                         --forced_out;
  108.                                         rotary_encoder_delay50us();
  109.                                         if(!forced_out) return 0xFF;//超時則強制退出,返回錯誤碼
  110.                                 }
  111.                                
  112.                                 //每次電平變化必定旋轉(zhuǎn)了編碼器,電平變化后要消抖
  113.                                 rotary_encoder_delay10ms();
  114.                                
  115.                                 //當ROTARY_ENCODER_CLK為低電平,而且ROTARY_ENCODER_DT也為低電平
  116.                                 //或ROTARY_ENCODER_CLK為高電平,而且ROTARY_ENCODER_DT也為高電平(AB為11或00)
  117.                                 //此時  AB從11到10到00  或  AB從00到10到11
  118.                                 if(((ROTARY_ENCODER_CLK)&&(ROTARY_ENCODER_DT))||((!ROTARY_ENCODER_CLK)&&(!ROTARY_ENCODER_DT)))
  119.                                 {
  120.                                         //如果旋轉(zhuǎn)編碼器的狀態(tài)為0則返回1,代表正轉(zhuǎn)一下
  121.                                         if(!rotary_encoder_state) return 1;
  122.                                         //如果旋轉(zhuǎn)編碼器的狀態(tài)為1則返回0,代表反轉(zhuǎn)一下
  123.                                         else return 0;
  124.                                 }
  125.                                 //若AB不為11或不為00則返回旋轉(zhuǎn)編碼器錯誤碼
  126.                                 else return ROTARY_ENCODER_ERROR;
  127.                         }
  128.                 }
  129.         }
  130.         //未響應返回旋轉(zhuǎn)編碼器錯誤碼
  131.         return 0xFF;
  132. }

  133. //旋轉(zhuǎn)編碼器中斷
  134. void rotary_encoder_interrupt() interrupt 0
  135. {
  136.         static u8 dat=0;
  137.         u8 temp=0xFF;//臨時變量先賦旋轉(zhuǎn)編碼器錯誤碼的值
  138.         if(!ROTARY_ENCODER_SW)//檢查按鍵是否按下
  139.         {
  140.                 rotary_encoder_delay10ms();//若按鍵按下,則消抖
  141.                 if(!ROTARY_ENCODER_SW)//再次檢查按鍵是否按下
  142.                 {
  143.                         while(!ROTARY_ENCODER_SW);//按鍵按住則程序卡死在這里
  144.                         rotary_encoder_delay10ms();//松手消抖
  145.                        
  146.                         LCD1602_print_char(0,0,'O');
  147.                         LCD1602_print_char(0,1,'N');
  148.                         LCD1602_print_char(0,2,' ');
  149.                        
  150.                         while(ROTARY_ENCODER_SW)//現(xiàn)在掃描旋轉(zhuǎn)編碼器
  151.                         {       
  152.                                 //掃描旋轉(zhuǎn)編碼器,返回值為1代表正轉(zhuǎn),返回值為0代表反轉(zhuǎn),返回值為0xFF代表未旋轉(zhuǎn)或旋轉(zhuǎn)錯誤
  153.                                 temp=scan_rotary_encoder();
  154.                                
  155.                                 if(temp!=0xFF)//去除旋轉(zhuǎn)編碼器錯誤碼
  156.                                 {
  157.                                         //利用 unsigned char 特性
  158.                                         //當temp為255時,再加1則溢出,變?yōu)?
  159.                                         //同理,當temp為0時,再減1則變?yōu)?55
  160.                                         if(temp==0x01) ++dat;
  161.                                         if(temp==0x00) --dat;
  162.                                        
  163.                                         //LCD1602打印字符(行,列,字符)
  164.                                         LCD1602_print_char(1,0,'0'+(dat/100%10));
  165.                                         LCD1602_print_char(1,1,'0'+(dat/10%10));
  166.                                         LCD1602_print_char(1,2,'0'+(dat/1%10));
  167.                                 }
  168.                         }
  169.                         rotary_encoder_delay10ms();//按鍵按下,則消抖
  170.                        
  171.                         while(!ROTARY_ENCODER_SW);//按鍵按住則程序卡死在這里
  172.                         rotary_encoder_delay10ms();//松手消抖
  173.                        
  174.                         LCD1602_print_char(0,0,'O');
  175.                         LCD1602_print_char(0,1,'F');
  176.                         LCD1602_print_char(0,2,'F');
  177.                 }
  178.         }
  179. }
復制代碼

鏈接:
全部資料51hei下載地址:

旋轉(zhuǎn)編碼器測試代碼.rar (1.44 MB, 下載次數(shù): 138)

作者: 深海咸魚    時間: 2020-5-10 17:21
謝謝分享,我試了下在仿真里數(shù)值似乎沒有變化啊
作者: pengxxx    時間: 2020-5-11 08:12
深海咸魚 發(fā)表于 2020-5-10 17:21
謝謝分享,我試了下在仿真里數(shù)值似乎沒有變化啊

這段代碼我沒有用仿真測試過,都是用實物測試的,下面的GIF是實物測試



作者: wjianing    時間: 2020-7-9 11:43
這不是正交信號嗎,怎么你編碼器的絲印都是串行輸出的
作者: pengxxx    時間: 2020-7-21 21:32
我實在找不到編輯按鈕在哪了,直接發(fā)吧

旋轉(zhuǎn)編碼器V1.1版
測試平臺:STC89C516單片機        12MHz晶振
其他平臺可能要在RotaryEncoder.c文件中修改延時函數(shù)
接口定義在port.h文件中

版本特性:

1.旋轉(zhuǎn)編碼器程序加入旋轉(zhuǎn)編碼器按鍵的單擊雙擊以及長按
2.精簡旋轉(zhuǎn)編碼器代碼
旋轉(zhuǎn)編碼器V1.1.rar (35.09 KB, 下載次數(shù): 47)
鏈接:https://pan.baidu.com/s/1DDse2uiioNi6ByMBjVnB2Q
提取碼:peng




作者: lzzasd    時間: 2020-7-22 08:30
樓主用的中斷方式   占用1個中斷     代碼中的11   00這兩個狀態(tài)很關(guān)鍵      配合01 10就能很準確的判斷方向
作者: 滄海一粒    時間: 2020-7-22 09:28
我贊同樓上的意見,根據(jù)狀態(tài) 判斷出   旋轉(zhuǎn)方向,是正轉(zhuǎn)還是反轉(zhuǎn)
作者: scorpioxz    時間: 2020-10-26 16:44
樓主e6b2cwz6c編碼器用過嗎?這種三相的脈沖輸出應該怎么做

作者: hefq    時間: 2021-2-27 15:15

用103做了一個,用按鈕模擬是對的,我沒有編碼器,用壞鼠標里的滾輪接上,竟然亂跑,一會加一會減,難道是滾輪壞了

作者: hefq    時間: 2021-2-27 15:28

拆開后是這個樣子了,看來要打磨一下

作者: tyrl800    時間: 2021-3-2 09:10
太復雜了,看了頭通,可以優(yōu)化吧
作者: 985524550    時間: 2021-6-12 08:14
樓主,你好,我需要增加2個LED燈,正轉(zhuǎn)=LED1;反正=LED2;來測試編碼器方向,如何增加,求大家指點下
作者: zhycong    時間: 2021-12-25 15:28
好東西!給無私奉獻點個贊!
作者: xiexugang    時間: 2021-12-26 00:41
這個旋轉(zhuǎn)編碼器程序程序,寫的太復雜了.應該幾行C代碼就可以實現(xiàn).
當A相在剛導通的瞬間,同時檢測B相是否也接通,若沒有接通,說明A相先接通是正轉(zhuǎn)
若B相已經(jīng)接通,說明B相已經(jīng)先接通了,是反轉(zhuǎn)




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1