久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 13409|回復: 10
打印 上一主題 下一主題
收起左側

第18章-單片機紅外通信

  [復制鏈接]
跳轉到指定樓層
樓主
51單片機輕松入門—基于STC15W4K系列(C語言版)
李友全
編著 詳見:http://www.zg4o1577.cn/bbs/dpj-37954-1.html

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

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


1電路圖

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




2 程序移植

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

#include "STC15W4K.H"

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

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

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

程序運行結果如下圖所示。

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

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

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

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

  28. // 獲取高電平時間(其實是16位計數器的計數值,STC15系列定時器默認為16位自動重裝方式)
  29. unsigned int Ir_Get_High()
  30. {
  31.         TL0 = 0;                    // 清空16位計數器0
  32.         TH0 = 0;                    // 清空16位計數器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.         //下面代碼設置定時器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.         //下面代碼設置定串口
  46.         AUXR = 0x00;             // 很關鍵,使用定時器1作為波特率發生器,S1ST2=0
  47.         SCON = 0x50;         // 0101 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允許接收)
  48. }        

  49. //  UART發送一字節        
  50. void UART_Send_Byte(unsigned char dat)
  51. {
  52.         SBUF = dat;
  53.         while (TI == 0);
  54.         TI = 0;             // 此句可以不要,不影響后面數據的發送,只供代碼查詢數據是否發送完成
  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);                    // 等待低電平出現
  67.                 time = Ir_Get_Low();        // 低電平區間16位計數器的計數值
  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.                 ////////// 接收后續的4 字節數據        ////////
  75.                 for (i=0; i<4; i++)                  // 4個字節
  76.                 {
  77.                         for (j=0; j<8; j++)              // 每個字節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;                // 因低位在先,所以數據右移,移入的最高位為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;                // 因低位在先,所以數據右移,移入的最高位為0
  91.                                         Ir_Buf[i] |= 0x80;          // 最高位置1
  92.                                 }
  93.                     else                            // 不在上述范圍內則說明為誤碼,直接退出
  94.                                 {
  95.                                         goto start;        
  96.                                 }
  97.                         }
  98.                 }
  99.                 UART_Send_Byte(Ir_Buf[0]);                // 用戶碼低字節
  100.                 UART_Send_Byte(Ir_Buf[1]);                // 用戶碼高字節
  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系列》 一書已經由北航出版社正式出版發行。
  4.   作者親手創作的與教材配套的51雙核實驗板(2個MCU)對程序下載、調試、仿真方便,不需要外部
  5.   仿真器與編程器,這種設計方式徹底解決了系統中多個最高優先級誰也不能讓誰的中斷競爭問題。
  6.   QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
  7.         驗證信息:STC15單片機
  8.   郵箱:xgliyouquan@126.com
  9.   ★★★★★★★★★★★★★★★★★★★★★★★★*/

  10. ////////////////////////////   main.c  ////////////////////////////////////////
  11. // 紅外接收數據,中斷方式,并通過串口發送接收到的4字節,晶振: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位數據=33
  18. unsigned char bitnum;                 // 32位數據中第幾位
  19. unsigned char startflag;         // 開始接收標志,長時間空閑狀態出現第1個下降沿就置1
  20. unsigned char irok;                         // 一楨數據接收完成標志,完成時值為1,否則為0
  21. unsigned char Ir_Buf[4];         // 存放接收到的4字節碼(用戶碼L + 用戶碼H + 鍵碼 + 鍵反碼),Ir_Buf[0]是用戶碼L
  22. unsigned char disnum[8];           //

  23. void UART_init(void)                      // 9600@22.1184MHz
  24. {                  
  25.         //下面代碼設置定時器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.         //下面代碼設置定串口
  32.         AUXR = 0x00;             // 很關鍵,使用定時器1作為波特率發生器,S1ST2=0
  33.         SCON = 0x50;         // 0101 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允許接收)
  34. }        

  35. //  UART發送一字節        
  36. void UART_Send_Byte(unsigned char dat)
  37. {
  38.         SBUF = dat;
  39.         while (TI == 0);
  40.         TI = 0;             // 此句可以不要,不影響后面數據的發送,只供代碼查詢數據是否發送完成
  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;                          // 總開關
  58. }  

  59. void irpros(void)         // 33位紅外數據轉4字節碼值
  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次,發送端輸出的原始二進制數據的每個字節都是低位在前,高位在后。
  68.                         if(irdata[k]>12)  // 數值0對應irtime值位1.12/0.138=8.12   
  69.                         {                                  // 數值1對應irtime值位2.25/0.138=16.3 ,取中值12區分
  70.                                 mun=mun | 0x80;
  71.                         }
  72.                         k++;
  73.                 }
  74.                 Ir_Buf[j]=mun;
  75.         }                                                  // 33位數據轉4字節完成                                    
  76. }

  77. void irwork(void)                  // 4字節紅外數據發串口輸出
  78. {
  79.         UART_Send_Byte(Ir_Buf[0]);           // 用戶碼低字節
  80.         UART_Send_Byte(Ir_Buf[1]);           // 用戶碼高字節
  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開始自由計數
  88.         Int2_init();                          // 外中斷 2 初始化(紅外接收引腳)
  89.         while(1)
  90.         {
  91.                 if(irok==1)                          // 一楨數據接收完成標志,完成此值為1,否則為0
  92.                 {
  93.                         irpros();                  // 33位紅外數據轉4字節紅外碼值
  94.                         irwork();                  // 若用數碼管顯示,需要將2進制轉換成16進制
  95.                         irok=0;
  96.                 }
  97.         }                        
  98. }

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

  104. //中斷函數功能:利用信號下降沿觸發對脈沖周期計時,最多計33個脈沖
  105. void int2_isr() interrupt 10      // 外部中斷2中斷函數
  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)                          // 數組范圍0--32
  119.                 {
  120.                         bitnum=0;
  121.                         irok=1;                                  // 一楨數據接收完成標志
  122.                 }
  123.         }
  124.         else
  125.         {
  126.                 irtime=0;                 // 長時間空閑狀態中出現第1個下降沿,清空計數器不確定的計數值
  127.                 TL0=0;           // TH0在初始化時設置的0,可以不作處理,定時器0雖為8位自動重裝方式,
  128.                 startflag=1;         // 但這里的運用不是在定時器溢出時處理數據,所以需要手動清零操作。
  129.         }
  130. }
復制代碼
IR中斷方式(簡單版)的單片機紅外解碼程序:http://www.zg4o1577.cn/bbs/dpj-47283-1.html
只用一個單片機定時器的紅外接收解碼程序:http://www.zg4o1577.cn/bbs/dpj-47284-1.html

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

評分

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

查看全部評分

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

我比你白,是不是按鍵按下時連續發射信號?該搞個松開按鍵才發射的程序。或是你那個變量發射后沒復位?發射完復位
回復

使用道具 舉報

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

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 玖玖精品视频 | 美女天堂| 毛片av免费在线观看 | 青青草这里只有精品 | www.久久 | 一区二区三区四区在线 | 亚洲精品色 | 亚洲一区二区精品视频在线观看 | 欧美8一10sex性hd | 成人精品一区 | 中文在线一区二区 | 亚洲狠狠| 久久爱综合 | 欧美日韩精品在线免费观看 | av黄色在线| 午夜在线| 国产精品视频一区二区三区 | 国产成人免费 | 在线免费观看欧美 | 一区二区av | 日韩中文一区二区三区 | 亚洲精品国产成人 | 日韩爱爱网站 | 欧美综合久久 | 看毛片网站 | 99热在线免费 | 鲁一鲁资源影视 | 福利视频网 | 99re视频在线观看 | 欧美一级二级在线观看 | 91精品国产一区二区三区香蕉 | 老头搡老女人毛片视频在线看 | 正在播放国产精品 | 久久国产一区二区 | 午夜视频一区二区三区 | 日韩三级视频 | 日本中文字幕一区 | 永久免费av | 青青久在线视频 | 午夜小视频在线播放 | 亚洲精品一区二三区不卡 |