本帖最后由 hubaba 于 2016-3-28 23:31 編輯
1電路圖
1號單片機與紅外接收頭連接電路如圖所示,紅外接收頭一般都可互換使用。
程序預覽: - /****************《51單片機輕松入門-基于STC15W4K系列》配套例程 *************
- ★★★★★★★★★★★★★★★★★★★★★★★★
- 《51單片機輕松入門-基于STC15W4K系列》 一書已經由北航出版社正式出版發行。
- 作者親手創作的與教材配套的51雙核實驗板(2個MCU)對程序下載、調試、仿真方便,不需要外部
- 仿真器與編程器,這種設計方式徹底解決了系統中多個最高優先級誰也不能讓誰的中斷競爭問題。
- QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
- 驗證信息:STC15單片機
- 郵箱:xgliyouquan@126.com
- ★★★★★★★★★★★★★★★★★★★★★★★★*/
- ///************* 功能說明 **************
- //紅外接收程序。適用于市場上用量最大的HT6121/6122及其兼容IC的編碼。
- //當遙控器用戶碼與程序定義的用戶碼不同時,程序會將遙控器的用戶碼一起從串口輸出。
- //使用模擬串口發送用戶碼與鍵碼,波特率9600,接收端要求使用字符格式顯示。
- /******************************************/
- #include "STC15W4K.H"
- #define MAIN_Fosc 22.1184 // 定義主時鐘, 紅外接收會自動適應,5~36MHZ,但模擬串口輸出部分不能自動適應。
- #define User_code 0xFD02 // 定義紅外接收用戶碼
- sbit Ir_Pin = P3^6; // 定義紅外接收輸入端口
- sbit TXD1 = P3^1; // 定義模擬串口發送腳
- /************* 用戶系統配置 **************/
- #define TIME 125 // 選擇定時器時間125us, 紅外接收要求在60us~250us之間
- /************* 以下宏定義用戶請勿修改 **************/
- #define Timer0_Reload (unsigned int)(65536 - (TIME * MAIN_Fosc /12.0)) // 定時器初值
-
- /************* 本地變量聲明 **************/
- unsigned char IR_SampleCnt; // 采樣次數計數器,通用定時器對紅外口檢測次數累加記錄
- unsigned char IR_BitCnt; // 記錄位數
- unsigned char IR_UserH; // 用戶碼(地址)高字節
- unsigned char IR_UserL; // 用戶碼(地址)低字節
- unsigned char IR_data; // 鍵原碼
- unsigned char IR_DataShit; // 鍵反碼
- unsigned char IR_code; // 紅外鍵碼
- bit Ir_Pin_temp; // 記錄紅外引腳電平的臨時變量
- bit IR_Sync; // 同步標志(1——已收到同步信號,0——沒收到)
- bit IrUserErr; // 用戶碼錯誤標志
- bit IR_OK; // 完成一幀紅外數據接收的標志(0,未收到,1,收到一幀完整數據)
- /******************** 紅外采樣時間宏定義, 用戶不要隨意修改 *******************/
- //數據格式: Synchro,AddressH,AddressL,data,/data, (total 32 bit).
- #if ((TIME <= 250) && (TIME >= 60)) // TIME決定測量誤差,TIME太大防錯能力降低,TIME太小會干擾其它中斷函數執行。
- #define IR_sample TIME // 定義采樣時間,在60us~250us之間,
- #endif
- #define IR_SYNC_MAX (15000/IR_sample) // 同步信號SYNC 最大時間 15ms(標準值9+4.5=13.5ms)
- #define IR_SYNC_MIN (9700 /IR_sample) // 同步信號SYNC 最小時間 9.5ms,(連發信號標準值9+2.25=11.25ms)
- #define IR_SYNC_DIVIDE (12375/IR_sample) // 區分13.5ms同步信號與11.25ms連發信號,11.25+(13.5-11.25)/2=12.375ms
- #define IR_DATA_MAX (3000 /IR_sample) // 數據最大時間3ms (標準值2.25 ms)
- #define IR_DATA_MIN (600 /IR_sample) // 數據最小時,0.6ms (標準值1.12 ms)
- #define IR_DATA_DIVIDE (1687 /IR_sample) // 區分數據 0與1,1.12+ (2.25-1.12)/2 =1.685ms
- #define IR_BIT_NUMBER 32 // 32位數據
- //**************************** 紅外接收模塊 ********************************************
- // 信號第1個下降沿時刻清零計數器并讓計數器從0開始計數,第2個下降沿時刻計算計數器運行時間
- // 因此檢測的是每個信號從低電平開始到高電平結束這段時間,也就是脈沖周期。
- void IR_RX_HT6121(void)
- {
- unsigned char SampleTime; // 信號周期
- IR_SampleCnt++; // 定時器對紅外口檢測次數
- F0 = Ir_Pin_temp; // 保存前一次此程序掃描到的紅外端口電平
- Ir_Pin_temp = Ir_Pin; // 讀取當前紅外接收輸入端口電平
- if(F0 && !Ir_Pin_temp) // 前一次采樣高電平并且當前采樣低電平,說明出現了下降沿
- {
- SampleTime = IR_SampleCnt; // 脈沖周期
- IR_SampleCnt = 0; // 出現了下降沿則清零計數器
- //******************* 接收同步信號 **********************************
- if(SampleTime > IR_SYNC_MAX) IR_Sync = 0; // 超出最大同步時間, 錯誤信息。
- else if(SampleTime >= IR_SYNC_MIN) // SYNC
- {
- if(SampleTime >= IR_SYNC_DIVIDE) // 區分13.5ms同步信號與11.25ms連發信號
- {
- IR_Sync = 1; // 收到同步信號 SYNC
- IR_BitCnt = IR_BIT_NUMBER; // 賦值32(32位有用信號)
- }
- }
- //********************************************************************
- else if(IR_Sync) // 已收到同步信號 SYNC
- {
- if((SampleTime < IR_DATA_MIN)|(SampleTime > IR_DATA_MAX)) IR_Sync=0; // 數據周期過短或過長,錯誤
- else
- {
- IR_DataShit >>= 1; // 鍵反碼右移1位(發送端是低位在前,高位在后的格式)
- if(SampleTime >= IR_DATA_DIVIDE) IR_DataShit |= 0x80; // 區別是數據 0還是1
- //*********************** 32位數據接收完畢 ****************************************
- if(--IR_BitCnt == 0)
- {
- IR_Sync = 0; // 清除同步信號標志
- if(~IR_DataShit == IR_data) // 判斷數據正反碼
- {
- if((IR_UserH == (User_code / 256)) && IR_UserL == (User_code % 256))
- {
- IrUserErr = 0; // 用戶碼正確
- }
- else IrUserErr = 1; // 用戶碼錯誤
-
- IR_code = IR_data; // 鍵碼值
- IR_OK = 1; // 數據有效
- }
- }
- // 格式: 用戶碼L —— 用戶碼H —— 鍵碼 —— 鍵反碼
- // 功能: 將 “用戶碼L —— 用戶碼H —— 鍵碼”通過3次接收交換后存入對應字節,
- // 這樣寫代碼可以節省內存RAM占用,但是不如用數組保存好理解。
- // 鍵反碼前面部分代碼已保存好了 :IR_DataShit |= 0x80;
- //**************************** 將接收的************************************************
- else if((IR_BitCnt & 7)== 0) // 1個字節接收完成
- {
- IR_UserL = IR_UserH; // 保存用戶碼高字節
- IR_UserH = IR_data; // 保存用戶碼低字節
- IR_data = IR_DataShit; // 保存當前紅外字節
- }
- }
- }
- }
- }
- /**************** Timer0初始化函數 ******************************/
- void InitTimer0(void)
- {
- TMOD = 0x01; // 16位計數方式.
- TH0 = Timer0_Reload / 256;
- TL0 = Timer0_Reload % 256;
- ET0 = 1;
- TR0 = 1;
- EA = 1;
- }
- /********************** Timer0中斷函數************************/
- void timer0 (void) interrupt 1
- {
- IR_RX_HT6121();
- TH0 = Timer0_Reload / 256; // 重裝定時器初值
- TL0 = Timer0_Reload % 256; // 重裝定時器初值
- }
- /********************** 模擬串口相關函數************************/
- void delay104us(void)
- {
- unsigned char i,j,k;
- for(i=1;i>0;i--) // 注意后面沒分號
- for(j=3;j>0;j--) // 注意后面沒分號
- for(k=189;k>0;k--); // 注意后面有分號 101
- }
- //模擬串口發送
- void Tx1Send(unsigned char dat) //9600,N,8,1 發送一個字節
- {
- unsigned char i;
- EA = 0;
- TXD1 = 0;
- delay104us();
- for(i=0; i<8; i++)
- {
- if(dat & 1) TXD1 = 1;
- else TXD1 = 0;
- dat >>= 1;
- delay104us();
- }
- TXD1 = 1;
- EA = 1;
- delay104us();
- delay104us();
- }
- void PrintString(unsigned char code *puts) // 發送一串字符串
- {
- for (; *puts != 0; puts++) Tx1Send(*puts); // 遇到停止符0結束
- }
- /********************* 十六進制轉ASCII函數 *************************/
- unsigned char HEX2ASCII(unsigned char dat)
- {
- dat &= 0x0f;
- if(dat <= 9) return (dat + '0'); //數字0~9
- return (dat - 10 + 'A'); //字母A~F
- }
- /********************* 主函數 *************************/
- 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鍵按下標志
- }
- }
- }
復制代碼
|