找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 13485|回復: 10
打印 上一主題 下一主題
收起左側(cè)

第18章-單片機紅外通信

  [復制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:111078 發(fā)表于 2016-3-28 23:22 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
51單片機輕松入門—基于STC15W4K系列(C語言版)
李友全
編著 詳見:http://www.torrancerestoration.com/bbs/dpj-37954-1.html

第18章 紅外通信
1 電路圖
2 程序移植

紅外遙控普遍運用在家用電器上,在工業(yè)控制中,對于存在高壓、輻射、有毒
氣體、粉塵等場合,可以使用紅外遙控。


1電路圖

1號單片機與紅外接收頭連接電路如圖所示,紅外接收頭一般都可互換使用。




2 程序移植

例18.4 紅外接收數(shù)據(jù),使用一個定時器模擬外中斷方式,并通過串口發(fā)送接收到的用戶碼 與鍵碼,R/C時鐘:22.1184MHz,波特率9600, 要求串口助手按字符格式顯示。 程序優(yōu)點:通用性極強,可使用任意IO口接收紅外數(shù)據(jù),紅外接收部分自適應R/C時鐘頻率
5~35M,模擬串口輸出部分需要根據(jù)R/C時鐘頻率調(diào)整延時函數(shù)參數(shù),此程序移植時只需更
改紅外接收引腳定義與模擬串口發(fā)送引腳即可。

#include "STC15W4K.H"

#define MAIN_Fosc 22.1184 // 定義主時鐘, 紅外接收會自動適應5~36MHZ,

#define User_code 0xFD02 // 定義紅外接收用戶碼 sbit Ir_Pin = P3^6; // 定義紅外接收輸入端口 sbit TXD1 = P3^1; // 定義模擬串口發(fā)送腳 void InitTimer0(void)

{
TMOD = 0x01; // 16位計數(shù)方式. TH0 = Timer0_Reload / 256;
TL0 = Timer0_Reload % 256; ET0 = 1;
TR0 = 1; EA = 1;
}
void main(void)
{
InitTimer0(); // 初始化Timer0
PrintString("定時器0初始化完畢\r\n"); // 上電后串口發(fā)送一條提示信息
while(1)
{
if(IR_OK) // 接收到一幀完整的紅外數(shù)據(jù)
{
PrintString("紅外鍵碼: 0x"); // 提示紅外鍵碼 Tx1Send(HEX2ASCII(IR_code >> 4)); // 鍵碼高半字節(jié) Tx1Send(HEX2ASCII(IR_code)); // 鍵碼低半字節(jié) if(IrUserErr) // 用戶碼錯誤,則發(fā)送用戶碼
{
Tx1Send(' '); // 發(fā)空格 Tx1Send(' '); // 發(fā)空格 PrintString("用戶碼: 0x"); // 提示用戶碼 Tx1Send(HEX2ASCII(IR_UserH >> 4)); // 用戶碼高字節(jié)的高半字節(jié) Tx1Send(HEX2ASCII(IR_UserH)); // 用戶碼高字節(jié)的低半字節(jié) Tx1Send(HEX2ASCII(IR_UserL >> 4)); // 用戶碼低字節(jié)的高半字節(jié) Tx1Send(HEX2ASCII(IR_UserL)); // 用戶碼低字節(jié)的低半字節(jié)
}
Tx1Send(0x0d); // 發(fā)回車 Tx1Send(0x0a); // 發(fā)回車
IR_OK = 0; // 清除IR鍵按下標志
}
}
}

程序運行結(jié)果如下圖所示。

只要單片機能獲取紅外鍵碼,單片機就可根據(jù)不同的鍵碼執(zhí)行不同的控制功能。

程序:
1.1—IR查詢方式解碼:
  1. /****************《51單片機輕松入門-基于STC15W4K系列》配套例程 *************
  2. ★★★★★★★★★★★★★★★★★★★★★★★★
  3. 《51單片機輕松入門-基于STC15W4K系列》 一書已經(jīng)由北航出版社正式出版發(fā)行。
  4.   作者親手創(chuàng)作的與教材配套的51雙核實驗板(2個MCU)對程序下載、調(diào)試、仿真方便,不需要外部
  5.   仿真器與編程器,這種設(shè)計方式徹底解決了系統(tǒng)中多個最高優(yōu)先級誰也不能讓誰的中斷競爭問題。
  6.   QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
  7.         驗證信息:STC15單片機
  8.   郵箱:xgliyouquan@126.com
  9.   ★★★★★★★★★★★★★★★★★★★★★★★★*/

  10. ////////////////////////////////////////////////////////////
  11. //   紅外接收數(shù)據(jù),查詢方式,并通過串口發(fā)送輸出  
  12. //   晶振:22.1184MHz         ,波特率:9600
  13. ////////////////////////////////////////////////////////////
  14. #include "STC15W4K.H"
  15. sbit Ir_Pin = P3^6;             // 紅外接收頭信號輸出腳
  16. unsigned char Ir_Buf[4]; // 用于保存解碼結(jié)果(Ir_Buf[0]--用戶碼L,Ir_Buf[3] --鍵反碼)

  17. // 獲取低電平時間 (其實是16位計數(shù)器的計數(shù)值,STC15系列定時器默認為16位自動重裝方式)
  18. unsigned int Ir_Get_Low()
  19. {
  20.         TL0 = 0;                 // 清空16位計數(shù)器0
  21.         TH0 = 0;                 // 清空16位計數(shù)器0
  22.         TR0 = 1;                 // 計數(shù)器0開始運行
  23.         while (!Ir_Pin && (TH0<0x80));          // 信號引腳變成高或低電平時間>17ms退出(只要>12ms即可)
  24.                                       // 0x8000=32768,  32768*0.54253uS=17777.62 uS            
  25.         TR0 = 0;                          // 這里 ! 優(yōu)先級大于&&     
  26.         return (TH0 * 256 + TL0);                  // 返回16位計數(shù)器的計數(shù)值。
  27. }

  28. // 獲取高電平時間(其實是16位計數(shù)器的計數(shù)值,STC15系列定時器默認為16位自動重裝方式)
  29. unsigned int Ir_Get_High()
  30. {
  31.         TL0 = 0;                    // 清空16位計數(shù)器0
  32.         TH0 = 0;                    // 清空16位計數(shù)器0
  33.         TR0 = 1;
  34.         while (Ir_Pin && (TH0<0x40));           // 信號引腳變成低電平或高電平時間>17ms退出
  35.         TR0 = 0;
  36.         return (TH0 * 256 + TL0);
  37. }  

  38. void UART_init(void)                      // 9600@22.1184MHz
  39. {                  
  40.         //下面代碼設(shè)置定時器1
  41.         TMOD = 0x20;           // 0010 0000 定時器1工作于方式2(8位自動重裝方式)
  42.         TH1  = 0xFA;           // 波特率:57600 /22.1184MHZ
  43.         TL1  = 0xFA;           // 波特率:57600 /22.1184MHZ
  44.         TR1  = 1;
  45.         //下面代碼設(shè)置定串口
  46.         AUXR = 0x00;             // 很關(guān)鍵,使用定時器1作為波特率發(fā)生器,S1ST2=0
  47.         SCON = 0x50;         // 0101 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允許接收)
  48. }        

  49. //  UART發(fā)送一字節(jié)        
  50. void UART_Send_Byte(unsigned char dat)
  51. {
  52.         SBUF = dat;
  53.         while (TI == 0);
  54.         TI = 0;             // 此句可以不要,不影響后面數(shù)據(jù)的發(fā)送,只供代碼查詢數(shù)據(jù)是否發(fā)送完成
  55. }

  56. void main()
  57. {
  58.         unsigned int time;
  59.         unsigned char i,j;
  60.         UART_init();
  61.         UART_Send_Byte(0X55);                // 測試串口工作是否正常
  62.         while (1)
  63.         {
  64. start:
  65.                 ///////////// 接收同步信號 ///////////
  66.                 while (Ir_Pin);                    // 等待低電平出現(xiàn)
  67.                 time = Ir_Get_Low();        // 低電平區(qū)間16位計數(shù)器的計數(shù)值
  68.                 if ((time < 15667) || (time > 17510))   goto start;        
  69.                                                         // 引導脈沖低電平8500~9500us,T=12/22.1184=0.54253uS
  70.                                                         // 8500/0.54253uS=15667.3    9500/0.54253uS=17510.5
  71.                 time = Ir_Get_High();
  72.                 if ((time < 7372) || (time > 9216))  goto start;   // 引導脈沖高電平4000-5000us
  73.                                                                                      // 4000/0.54253uS=7372.8    5000/0.54253uS=9216
  74.                 ////////// 接收后續(xù)的4 字節(jié)數(shù)據(jù)        ////////
  75.                 for (i=0; i<4; i++)                  // 4個字節(jié)
  76.                 {
  77.                         for (j=0; j<8; j++)              // 每個字節(jié)8位
  78.                         {
  79.                                 time = Ir_Get_Low();                 // 接收每位560us 低電平
  80.                                 if ((time < 626) || (time > 1438))   goto start;                 // 340-780us
  81.                                                                                  // 340/0.54253uS=626.7    780/0.54253uS=1437.7
  82.                                 time = Ir_Get_High();                    // 接收每位560us或1690us高電平時間
  83.                                 if ((time>626) && (time<1438))  // 時間范圍為340-780us(中心值560us),
  84.                     {
  85.                          Ir_Buf[i] >>= 1;                // 因低位在先,所以數(shù)據(jù)右移,移入的最高位為0
  86.                                 }
  87.                     else if ((time>2728) && (time<3502))
  88.                 {                           // 時間判定范圍為1480~1900us(中心值1690us)
  89.                                                                             // 1480/0.54253uS=2727.9   1900/0.54253uS=3502.1
  90.                                         Ir_Buf[i] >>= 1;                // 因低位在先,所以數(shù)據(jù)右移,移入的最高位為0
  91.                                         Ir_Buf[i] |= 0x80;          // 最高位置1
  92.                                 }
  93.                     else                            // 不在上述范圍內(nèi)則說明為誤碼,直接退出
  94.                                 {
  95.                                         goto start;        
  96.                                 }
  97.                         }
  98.                 }
  99.                 UART_Send_Byte(Ir_Buf[0]);                // 用戶碼低字節(jié)
  100.                 UART_Send_Byte(Ir_Buf[1]);                // 用戶碼高字節(jié)
  101.                 UART_Send_Byte(Ir_Buf[2]);                // 鍵碼
  102.                 UART_Send_Byte(Ir_Buf[3]);                // 鍵反碼
  103.         }
  104. }  
復制代碼

2.3—IR-中斷方式(復雜的)
  1. /****************《51單片機輕松入門-基于STC15W4K系列》配套例程 *************
  2. ★★★★★★★★★★★★★★★★★★★★★★★★
  3. 《51單片機輕松入門-基于STC15W4K系列》 一書已經(jīng)由北航出版社正式出版發(fā)行。
  4.   作者親手創(chuàng)作的與教材配套的51雙核實驗板(2個MCU)對程序下載、調(diào)試、仿真方便,不需要外部
  5.   仿真器與編程器,這種設(shè)計方式徹底解決了系統(tǒng)中多個最高優(yōu)先級誰也不能讓誰的中斷競爭問題。
  6.   QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
  7.         驗證信息:STC15單片機
  8.   郵箱:xgliyouquan@126.com
  9.   ★★★★★★★★★★★★★★★★★★★★★★★★*/

  10. ////////////////////////////   main.c  ////////////////////////////////////////
  11. // 紅外接收數(shù)據(jù),中斷方式,并通過串口發(fā)送接收到的4字節(jié),晶振:22.118400 MHz
  12. // 接收頭信號引腳P3.6,串口波特率9600
  13. ///////////////////////////////////////////////////////////////////////////
  14. #include "STC15W4K.H"
  15. sbit Ir_Pin = P3^6;                 // 紅外接收頭信號輸出腳

  16. unsigned char irtime;                 // 紅外時間
  17. unsigned char irdata[33];         // 1位引導碼+32位數(shù)據(jù)=33
  18. unsigned char bitnum;                 // 32位數(shù)據(jù)中第幾位
  19. unsigned char startflag;         // 開始接收標志,長時間空閑狀態(tài)出現(xiàn)第1個下降沿就置1
  20. unsigned char irok;                         // 一楨數(shù)據(jù)接收完成標志,完成時值為1,否則為0
  21. unsigned char Ir_Buf[4];         // 存放接收到的4字節(jié)碼(用戶碼L + 用戶碼H + 鍵碼 + 鍵反碼),Ir_Buf[0]是用戶碼L
  22. unsigned char disnum[8];           //

  23. void UART_init(void)                      // 9600@22.1184MHz
  24. {                  
  25.         //下面代碼設(shè)置定時器1
  26.         TMOD&= 0x0F;
  27.         TMOD |= 0x20;           // 0010 0000 定時器1工作于方式2(8位自動重裝方式)
  28.         TH1  = 0xFA;           // 波特率:9600 /22.1184MHZ
  29.         TL1  = 0xFA;           // 波特率:9600 /22.1184MHZ
  30.         TR1  = 1;
  31.         //下面代碼設(shè)置定串口
  32.         AUXR = 0x00;             // 很關(guān)鍵,使用定時器1作為波特率發(fā)生器,S1ST2=0
  33.         SCON = 0x50;         // 0101 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允許接收)
  34. }        

  35. //  UART發(fā)送一字節(jié)        
  36. void UART_Send_Byte(unsigned char dat)
  37. {
  38.         SBUF = dat;
  39.         while (TI == 0);
  40.         TI = 0;             // 此句可以不要,不影響后面數(shù)據(jù)的發(fā)送,只供代碼查詢數(shù)據(jù)是否發(fā)送完成
  41. }

  42. // 定時器0初始化
  43. void Timer0_init(void)           
  44. {
  45.         TMOD&=0xF0;
  46.         TMOD|=0x02;               // 8位自動重裝方式
  47.          TH0=0x00;                   // T=12/22.1184=0.54253uS,256*0.54253 =        138.88768 uS
  48.          TL0=0x00;
  49.         ET0=1;             // 開中斷
  50.         EA=1;                           // 開總中斷
  51.         TR0=1;
  52. }

  53. // 外部中斷2初始化
  54. void Int2_init()      // P3.6引腳即為外部中斷2
  55. {
  56.         INT_CLKO|=0x10;          // 開啟外中斷2

  57.         EA = 1;                          // 總開關(guān)
  58. }  

  59. void irpros(void)         // 33位紅外數(shù)據(jù)轉(zhuǎn)4字節(jié)碼值
  60. {
  61.         unsigned char mun,k,i,j;
  62.         k=1;                              // k=0存放的引導碼,這里不管
  63.         for(j=0;j<4;j++)
  64.         {
  65.                 for(i=0;i<8;i++)
  66.                 {
  67.                         mun=mun>>1;                  // 右移7次,發(fā)送端輸出的原始二進制數(shù)據(jù)的每個字節(jié)都是低位在前,高位在后。
  68.                         if(irdata[k]>12)  // 數(shù)值0對應irtime值位1.12/0.138=8.12   
  69.                         {                                  // 數(shù)值1對應irtime值位2.25/0.138=16.3 ,取中值12區(qū)分
  70.                                 mun=mun | 0x80;
  71.                         }
  72.                         k++;
  73.                 }
  74.                 Ir_Buf[j]=mun;
  75.         }                                                  // 33位數(shù)據(jù)轉(zhuǎn)4字節(jié)完成                                    
  76. }

  77. void irwork(void)                  // 4字節(jié)紅外數(shù)據(jù)發(fā)串口輸出
  78. {
  79.         UART_Send_Byte(Ir_Buf[0]);           // 用戶碼低字節(jié)
  80.         UART_Send_Byte(Ir_Buf[1]);           // 用戶碼高字節(jié)
  81.         UART_Send_Byte(Ir_Buf[2]);           // 鍵碼
  82.         UART_Send_Byte(Ir_Buf[3]);           // 鍵反碼                                                               
  83. }

  84. void main()
  85. {
  86.         UART_init();
  87.         Timer0_init();                          // 讓定時器0開始自由計數(shù)
  88.         Int2_init();                          // 外中斷 2 初始化(紅外接收引腳)
  89.         while(1)
  90.         {
  91.                 if(irok==1)                          // 一楨數(shù)據(jù)接收完成標志,完成此值為1,否則為0
  92.                 {
  93.                         irpros();                  // 33位紅外數(shù)據(jù)轉(zhuǎn)4字節(jié)紅外碼值
  94.                         irwork();                  // 若用數(shù)碼管顯示,需要將2進制轉(zhuǎn)換成16進制
  95.                         irok=0;
  96.                 }
  97.         }                        
  98. }

  99. void timer0 () interrupt 1
  100. {
  101.         irtime++;           // 0--255自由循環(huán)計數(shù) ,//T=12/11.0592=1.08506uS
  102. }                                   // 自動重裝計數(shù)初值255,irtime里面的1代表256* 1.08506uS=277.77uS
  103.                                    // 最大計數(shù)時間 256*        277.77=71109.12uS= 71mS         

  104. //中斷函數(shù)功能:利用信號下降沿觸發(fā)對脈沖周期計時,最多計33個脈沖
  105. void int2_isr() interrupt 10      // 外部中斷2中斷函數(shù)
  106. {
  107.         P35=!P35;
  108.         if(startflag)
  109.         {
  110.                 if(irtime>90&&irtime<104)  // 12.5-14.5ms引導碼        (8500+4000)--(9500+5000)=12.5--14.5mS
  111.                 {                                                  // 12500/138.89=90        14500/138.89=104
  112.                         bitnum=0;
  113.                 }
  114.                 irdata[bitnum]=irtime;          // 第一次引導碼時間存入irdata[0]
  115.                 irtime=0;                                  // 清零下次備用
  116.                 TL0=0;
  117.                 bitnum++;
  118.                 if(bitnum==33)                          // 數(shù)組范圍0--32
  119.                 {
  120.                         bitnum=0;
  121.                         irok=1;                                  // 一楨數(shù)據(jù)接收完成標志
  122.                 }
  123.         }
  124.         else
  125.         {
  126.                 irtime=0;                 // 長時間空閑狀態(tài)中出現(xiàn)第1個下降沿,清空計數(shù)器不確定的計數(shù)值
  127.                 TL0=0;           // TH0在初始化時設(shè)置的0,可以不作處理,定時器0雖為8位自動重裝方式,
  128.                 startflag=1;         // 但這里的運用不是在定時器溢出時處理數(shù)據(jù),所以需要手動清零操作。
  129.         }
  130. }
復制代碼
IR中斷方式(簡單版)的單片機紅外解碼程序:http://www.torrancerestoration.com/bbs/dpj-47283-1.html
只用一個單片機定時器的紅外接收解碼程序:http://www.torrancerestoration.com/bbs/dpj-47284-1.html

全部完整的4個源碼請下載附件: 第18章 紅外通信.rar (84.33 KB, 下載次數(shù): 169)

評分

參與人數(shù) 1黑幣 +8 收起 理由
xiou + 8 很給力!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏9 分享淘帖 頂2 踩

相關(guān)帖子

回復

使用道具 舉報

沙發(fā)
ID:138443 發(fā)表于 2016-10-4 23:16 | 只看該作者
太好了,謝謝
回復

使用道具 舉報

板凳
ID:277420 發(fā)表于 2018-7-10 15:25 | 只看該作者
路過學習學習。。。。。。。。。。
回復

使用道具 舉報

地板
ID:69115 發(fā)表于 2018-10-20 10:16 | 只看該作者
不錯,很好的應用實例
回復

使用道具 舉報

5#
ID:332997 發(fā)表于 2018-11-1 09:13 | 只看該作者
很給力
回復

使用道具 舉報

6#
ID:420172 發(fā)表于 2018-11-3 18:01 | 只看該作者
很實用,謝謝
回復

使用道具 舉報

7#
ID:71297 發(fā)表于 2019-1-24 22:59 | 只看該作者
剛好,需要用到,謝謝了
回復

使用道具 舉報

8#
ID:621994 發(fā)表于 2019-11-30 21:52 | 只看該作者
你好我是小白 請問一下:我用IR中斷的形式寫的串口顯示按鍵碼的程序 ,內(nèi)容上面大致和您的大致相同,可是在按下同一個按鍵兩次后就顯示其他的數(shù)碼(不是正常的00 ff 開頭的數(shù)碼) 我開始以為是程序的問題 但是第二次的顯示還是正確的第三次錯誤,我就想不出來是什么原因了,您能指導指導嗎? 必要的話可以叫我貼出程序出來 謝謝! 各位看到的朋友如果可以的話也請幫幫忙,。感謝。
回復

使用道具 舉報

9#
ID:398219 發(fā)表于 2020-2-17 13:19 | 只看該作者
路過,學習大神的編程思路
回復

使用道具 舉報

10#
ID:725238 發(fā)表于 2020-4-24 15:06 來自手機 | 只看該作者
jpg阿福 發(fā)表于 2019-11-30 21:52
你好我是小白 請問一下:我用IR中斷的形式寫的串口顯示按鍵碼的程序 ,內(nèi)容上面大致和您的大致相同,可是在 ...

我比你白,是不是按鍵按下時連續(xù)發(fā)射信號?該搞個松開按鍵才發(fā)射的程序;蚴悄隳莻變量發(fā)射后沒復位?發(fā)射完復位
回復

使用道具 舉報

11#
ID:965189 發(fā)表于 2021-11-16 11:57 | 只看該作者
沒看見連續(xù)鍵的解碼部份。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表