51單片機學習筆記(清翔版)(23)——紅外通訊


DS18B20課后題:

負數以補碼形式存在的。

如果是負數,那么S全為1,前面那些不看,我們只看最后一個S,當它為1時,那么就是0x08,所以只要高8位大於等於0x08,就是負數。

其中s=0x40這里

上面打錯了,如果不是負數,則s=0,則不顯示負號,如果是負數,就執行else的語句。

溫度達不到零下怎么顯示呢?模擬

這里是錯的,所以中文手冊會出錯,要參照英文手冊。

錯的是16進制,應該是FE6F


開始紅外通訊

紅外遙控廣泛用於家庭中,體積小,抗干擾強,功能強,功耗低,成本低

開發板帶有紅外接收和紅外發射功能

自學習型萬能遙控器源代碼,下載到開發板運行后,拿電視機遙控器對着開發板按下開關機鍵,開發板就能把開關機鍵代碼解碼,同時按下矩陣鍵盤某個按鍵,這個按鍵就有了電視機遙控器開關機鍵的功能,並且斷電后學習到的數據不會丟失,因為程序把解碼的程序儲存到EEPROM中,只要是NEC協議的紅外遙控器,開發板都可以解碼,復制到開發板按鍵上。這就是萬能遙控器。

 紅外發射電路用的紅外發射二極管,發紅外光,特殊顏色的普通光,可見光譜之下,即眼看不到它發光。

解碼芯片用單片機解碼。應用電路就隨機了,例如遙控器按下后,流水燈亮,流水燈就是應用電路。

上圖右側為一體化紅外接收頭。就是U6這個器件。

1腳將接收到的紅外信號放大解調后輸出,我們把數據送給了P32,便於我們編寫程序解碼。

可參考那個電路,也可參考芯片手冊的電路:

紅外通訊沒有射頻模塊做的好用,紅外光會被東西擋到。

紅外通訊流程:

紅外發射裝置:鍵盤編碼調制,送給紅外發射管,然后發射出去。例如我按下了CH-,右邊是對應的鍵值碼,即45,16進制,然后編碼芯片就會對它進行編碼、調制,然后送給發射管,在發射出去。

紅外接收裝置:接收到信號后,放大、解調,然后輸出給解碼芯片解碼。

我們輸出給P32,由單片機解碼。

信號的調制和解調是紅外通訊的基本原理。

將我們要發送的數據,也就是我們說的基帶二進制信號,調制為38.41kHz的載波信號,然后發射出去。

紅外接收設備接收到信號后要還原為我們發射的數據,也就是解調。目前大部分紅外接收設備都是用的一體化紅外接收頭進行解調。

調制主要是像我們看的那個自學習型萬能遙控器程序,編碼和調制都需要通過單片機進行。

接下來看看編碼和解碼:

以我們目前這紅外遙控系統為例,紅外發射就不用考慮了,遙控器就是一個完整的紅外發射器件,任意按下某個按鍵,遙控器就會把這按鍵的值進行編碼調制發射。

接收端我們用了一體化接收頭,接收到信號后,把這個信號放大解調,輸出給單片機,我們寫程序解碼。要解碼我們首先要知道是如何編碼的,我們遙控器使用的NEC編碼協議,要解碼這個發出的數據,我們要先了解這個NEC協議。如果不知道遙控器(紅外發射器件)是NEC協議的該怎么知道呢?我們可以用示波器或邏輯分析儀,把紅外信號通過一體化接收頭解調后的信號,把編碼抓出來,之后分析是哪種協議。這是用邏輯分析儀分析的。

之前說了調制是為了信號更好的傳輸,那么為什么要編碼呢?如果不編碼,會出現這種情況,抽屜里有空調和電視機,我用空調的遙控器按下開機鍵,想打開空調,結果都打開了,這就是為了區分不同機器類型,才將信號按照一定規律進行編碼傳輸。現在不論是業余還是專業制作,都是用的編碼芯片。不同的編碼芯片編碼協議不同。NEC是最廣泛的。日本人定的。

空調遙控器的紅外通訊,紅外編碼通常是用遙控器內單片機特定的編碼,編碼協議是自己定制的,不同廠家編碼協議不一樣。不過編碼調制后基本都在38kHz頻率上發射的。

所以我們也可以通過一體化接收頭,把它解調出來,要想知道如何解碼,就要用邏輯分析儀或示波器抓出來,分析編碼規律。

NEC的編碼完成后,所要發送的基帶二進制編碼通常有30多位。空調編碼完后有100多位。

NEC

開始會有一段引導碼,是有規定的,高電平9000微秒左右,低電平4500微秒。

只有兩個8位的用戶碼。也是為了區分不同器件,例如兩台電視機,不同品牌,都使用的NEC協議,為了不串用,廠家用戶碼做的就不一樣。

在之后就是8位數據碼和數據反碼,數據碼就是鍵值碼,反碼是為了校驗前面8位是否正確的。

數據是一位一位發送的。

為了更形象化,我們把遙控器所發送的鍵值,通過開發板一體化接收頭解調出來后,把基帶二進制碼通過示波器抓出來。開發板和邏輯分析儀接好。

發送和接收那端,起始碼高電平在8~10ms就可以。

所有的起始碼,用戶碼,數據碼和數據反碼都能分析出來。

程序根據波形建立起一個思路,紅外接收頭的輸出端,解調后輸出給P32,有第二功能外部中斷0,可以配置在跳邊沿觸發,來一個低電平觸發一次,觸發時我們就啟動定時器,在它下次再次觸發時,定時器在這期間走的數,我們取出來,就能知道脈沖有多寬。

比如從這到這,看到有多長就能知道這是起始碼。之后是判斷0還是1,0約是1.125ms寬,1約是2.25ms寬。通過這種方法讓單片機充當解碼芯片,把紅外遙控器鍵值解碼出來。

這里起始碼后只有32位數據,空調遙控器就長了,有100多位。

  

如果有告訴是某品牌的編碼規律是怎么樣的,還簡單一點,否則只能一點一點分析找出規律。

解碼后也可以用單片機把鍵值碼學習下來,按照這個規律重新編碼,編碼完成后用定時器調制到38k這頻率通過紅外發射頭發射,就可以遙控空調。


 編程,接收到紅外信號后,把數據通過NEC協議規定解碼,之后讓串口以9600波特率發出,用計算機串口助手顯示。

 寫之前在梳理下思路:

一體化紅外接收頭輸出端接到了P32,第二功能是外部中斷0,可以設置外部中斷為跳邊沿模式,來一個低電平觸發一次,觸發外部中斷時讓定時器開始計數,當下次再觸發時,就可以讀取計時器所計的數值,就可以計算出上一次脈寬的持續時間,根據時間確認是引導碼(13.5ms左右)、數據0(1.125ms左右)或者數據1(2.25ms左右)。

為了更形象,我們通過邏輯分析儀先把紅外數據的波形抓出來,通過波形一邊寫程序一邊講解。

先是起始碼,從1這里觸發外部中斷,開啟定時器,2這里再次觸發,就把定時器走的數讀取出來,計算出持續時間,並且把定時器走數的值清0,再開始加,定時器一直不關,到下一次觸發外部中斷,再一次計算持續時間。

  1 #include <reg52.h>
  2 
  3 #define uchar unsigned char
  4 #define uint  unsigned int
  5 sbit P10=P1^0;
  6 uchar IRtime;    //儲存檢測紅外高低電平持續時間
  7 uchar IRcord[4]; //儲存解碼后的4個字節數據
  8 uchar IRdata[33];//包含起始碼在內的33位數據
  9 bit IRpro_ok;    //解碼后4個字節數據接收完成標志位
 10 bit IRok;        //33位數據接收完成標志位
 11 
 12 void init()
 13 {
 14     TMOD|=0x02;//設置定時器0工作模式2,8位自動重裝
 15     TL0=TH0=0;//初始化定時器0寄存器,定時器0溢出一次時間為256個機器周期
 16     EA=1;
 17     ET0=1;
 18     TR0=1;
 19     
 20     IT0=1;//設置外部中斷0跳邊沿觸發方式
 21     EX0=1;
 22     
 23     TMOD|=0x20;//設置定時器1工作模式2,8位自動重裝
 24     TL1=TH1=0xfd;//比特率9600
 25     SM1=1;SM0=0;//設置串口工作模式1,10位異步收發
 26     TR1=1;
 27 }
 28 
 29 //定時器中斷,每中斷一次需要256*1.085us=277.76us(256個機器周期,晶振頻率位11.0592Mhz,機器周期=12*晶振周期)
 30 void time0() interrupt 1
 31 {
 32     IRtime++;//277.76us
 33 }
 34 
 35 //外部中斷0存入33次脈寬
 36 void int0() interrupt 0
 37 {
 38     static uchar i;//靜態變量用於存入33次數據計數
 39     static bit startflag;//開始儲存脈寬標志位
 40     if(startflag)//標志被置1則開始存儲33次脈沖寬度,一位一位存
 41     {
 42         if((IRtime<53)&&(IRtime>=32))i=0;//判斷引導碼,如果是引導碼則從起始碼開始存
 43         IRdata[i]=IRtime;//以T0溢出的次數來計算脈寬把這個時間存放在數組
 44         IRtime=0;//計數清零
 45         i++;//計數脈寬存入次數自加
 46         if(i==33)//i=33就表示已經存入了33次脈寬
 47         {
 48             IRok=1;//脈寬檢查完成
 49             i=0;//把脈寬計數清零准備下次存入
 50         }
 51     }
 52     else
 53     {
 54         IRtime=0;//定時器0計數清零,因為初始化時就啟動了,即使沒有收到紅外數據也再加
 55         startflag=1;//開始處理標志位置1
 56     }
 57 }
 58 
 59 //把提取的33次脈寬解碼 NEC協議
 60 void IRcordpro()
 61 {
 62     uchar i;//計數處理4個字節
 63     uchar j;//用於處理1個字節的8位數據
 64     uchar k;//用於計數處理33次脈寬
 65     k=1;//從第一位脈寬開始處理,丟掉起始碼
 66     for(i=0;i<4;i++)
 67     {
 68         for(j=0;j<8;j++)
 69         {
 70             if(IRdata[k]>5)    IRcord[i]|=0x80;//如果脈寬大於數據0標准的1125us那么就判斷為數據1
 71             
 72             if(j<7)    IRcord[i]>>=1;//只能移動7次,防止最后一位移出
 73             k++;//處理下一次脈寬
 74         }
 75     }
 76     IRpro_ok=1;//解碼完成
 77 }
 78 
 79 void main()
 80 {
 81     uchar i;//計數串口發送字節數
 82     init();
 83     while(1)
 84     {
 85         if(IRok)//判斷33次脈寬是否提取完成
 86         {
 87             IRcordpro();//根據脈寬解碼出4個字節數據
 88             IRok=0;//清零脈寬檢查完成標志位等待下一次脈寬檢查
 89             if(IRpro_ok)//判斷是否解碼完成
 90             {
 91                 if(IRcord[2]==0x45)P10=!P10;//若是CH-按鍵則亮第一個燈
 92                 for(i=0;i<4;i++)//串口發送4個字節數據
 93                 {
 94                     SBUF=IRcord[i];//發送數據
 95                     while(!TI);//等待發送完成標志
 96                     TI=0;//清零發送完成標志位
 97                 }
 98                 IRpro_ok=0;//清零解碼完成標志位
 99             }
100         }
101     }
102     
103 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM