這裏使用的處理器是C8051F005。紅外接收頭接處理器引腳,中斷方式接收按鍵數據。編程
一 PCA介紹eclipse
1.1 PCA ide
可編程計數器陣列(PCA)提供加強的定時器功能,與標準8051計數器/定時器相比,它須要較少的CPU干預。PCA包含一個專用的16位計數器/定時器和5個16位捕捉/比較模塊。每一個捕捉/比較模塊有其本身的I/O線(CEXn)。當被容許時,I/O線經過交叉開關連到端口I/O。學習
計數器/定時器由一個可配置的時基信號驅動,能夠在四個輸入源中選擇時基信號:系統時鐘12分頻、系統時鐘4分頻、定時器0溢出或ECI線上的外部時鐘信號。對PCA的配置和控制是經過系統控制器的特殊功能寄存器來實現的。PCA的基本原理框圖下圖。編碼
1.2 捕捉/比較模塊spa
每一個模塊均可被配置爲獨立工做,有四種工做方式:邊沿觸發捕捉、軟件定時器、高速輸出和脈寬調製器。每一個模塊在CIP-51系統控制器中都有屬於本身的特殊功能寄存器(SFR)。這些寄存器用於配置模塊的工做方式和與模塊交換數據。code
PCA0CPMn寄存器用於配置PCA捕捉/比較模塊的工做方式,下表概述了模塊工做在不一樣方式時該寄存器各位的設置狀況。置‘1’ PCA0CPMn寄存器中的ECCFn位將容許模塊的CCFn中斷。blog
注意:要使單獨的CCFn中斷獲得響應,必須先總體容許PCA0中斷。經過將EA位(IE.7)和EPCA0位(EIE1.3)設置爲邏輯1來總體容許PCA0中斷。ip
1.3 邊沿觸發的捕捉方式it
在該方式,CEXn引腳上出現的有效電平變化致使PCA捕捉PCA計數器/定時器的值並將其裝入到對應模塊的16位捕捉/比較寄存器(PCA0CPLn和PCA0CPHn)。
PCA0CPMn寄存器中的CAPNn位用於選擇觸發捕捉的電平變化類型:低電平到高電平(正沿)、高電平到低電平(負沿)或任何變化(正沿或負沿)。
當捕捉髮生時,PCA0CN中的捕捉/比較標誌(CCFn)被置爲邏輯1併產生一箇中斷請求(若是CCF中斷被容許)。
當CPU轉向中斷服務程序時,CCFn位不能被硬件自動清除,必須用軟件清0。
2、紅外編碼
2.1數據格式
數據格式包括了引導碼、用戶碼、數據碼和數據碼反碼,編碼總佔32 位。數據反碼是數據碼反相後的編碼,編碼時可用於對數據的糾錯。注意:第二段的用戶碼也能夠在遙控應用電路中被設置成第一段用戶碼的反碼。
2.2位定義
用戶碼或數據碼中的每個位能夠是位‘1’,也能夠是位‘0’。區分‘0’和‘1’是利用脈衝的時間間隔來區分,這種編碼方式稱爲脈衝位置調製方式,英文簡寫PPM。
這裏只介紹了紅外的一些簡單的知識,還有其餘重複碼等知識自行學習。
3、實現
3.1 準備
因爲項目中的紅外遙控器是定製的,首先用示波器觀測下某一按鍵的波形圖。
從圖中可知,去除掉起始碼,咱們能夠定義高電平短的是邏輯0,,高電平長點的是邏輯1。這樣讀到的32位數據爲0111 0100 1000 1011 1000 1000 0111 0111
數據的分析:兩兩一組,一共四組。第一組是第二組的反碼;第三組是第四組的反碼。
3.2 軟件實現
1 #define _9ms_val 0x40CC //9ms 2 #define _9ms_min 0x3900 //8.5ms 3 #define _9ms_max 0x4466 //9.5ms 4 #define _45ms_val 0x2066 //4.5ms 5 #define _45ms_min 0x1CCC //4ms 6 #define _45ms_max 0x2400 //5ms 7 #define _56ms_val 0x408 //0.56ms 8 #define _56ms_min 0x34F //0.46ms 9 #define _56ms_max 0x4C0 //0.66ms 10 #define _169ms_val 0xC2B //1.69ms 11 #define _169ms_min 0xACC //1.5ms 12 #define _169ms_max 0xC87 //1.74ms 13 #define _225ms_val 0x1033 //2.25ms 14 #define _225ms_min 0xE66 //2ms 15 #define _225ms_max 0x1200 //2.5ms 16 #define posedge 0x21 //正沿捕捉功能使能 17 #define engedge 0x11 //負沿捕捉功能使能
上面一部分的時間是這樣算出來的,系統採用的時鐘是22.1184MHz。在下面的初始化中,PCA使用的是系統時鐘的十二分之一,便是1.8432MHz。拿9ms做說明,
得出 x=16588.8 ,轉換成16進制數就是 0x40CC。
最後兩個宏參照圖2得來,捕捉上升沿仍是降低沿。
1 void init_pca(void) { 2 EIE1 |= 0x08; //容許PCA0的中斷請求 3 PCA0MD = 0x1; //系統時鐘的12分頻 CF 中斷 4 PCA0CN = 0x0; 5 PCA0CPM0 = 0x0; 6 PCA0CPM0 = engedge; 7 PCA0L = 0x0; 8 PCA0H = 0x0; 9 conut = 0x0; 10 state = 0x0; 11 rep_fg = 0; 12 }
初始化完成對變量的初始化,以及首先捕獲降低沿。
1 #ifdef eclipse 2 void PCA0_ISR(void) /* 可編程計數器陣列0 */ 3 #else 4 void PCA0_ISR (void) interrupt EPCA0_VECTOR /* 可編程計數器陣列0 */ 5 #endif 6 { 7 EA = 0; 8 switch (state) { 9 case 0x0: //開始第一個降低沿 10 PCA0L = PCA0H = 0x0; 11 CR = 1; //容許PCA計數器 12 PCA0CPM0 = posedge; //設置捕獲高電平 13 conut = 0x0; 14 state = 0x1; 15 break; 16 /*----------------------------------------------------------------------------*/ 17 case 0x1: //低電平寬度 9ms 18 CR = 0; 19 TIM_L_VAL.c[1] = PCA0CPL0; 20 TIM_L_VAL.c[0] = PCA0CPH0; 21 PCA0L = PCA0H = 0x0; 22 PCA0CPM0 = engedge; //設置捕獲低電平 23 if ((TIM_L_VAL.i > _9ms_min) && (TIM_L_VAL.i < _9ms_max)) { //9ms比較 24 CR = 1; 25 state = 0x2; 26 } else 27 state = 0x0; //不是9ms脈衝 28 break; 29 /*----------------------------------------------------------------------------*/ 30 case 0x2: //高電平寬度 4.5ms 2.25 31 TIM_H_VAL.c[1] = PCA0CPL0; 32 TIM_H_VAL.c[0] = PCA0CPH0; 33 CR = 0; 34 PCA0L = PCA0H = 0x0; 35 conut = 0x0; 36 if ((TIM_H_VAL.i > _45ms_min) && (TIM_H_VAL.i < _45ms_max)) //4.5ms比較 37 { 38 PCA0CPM0 = posedge; //設置捕獲高電平 39 CR = 1; 40 state = 0x3; 41 } else { 42 if ((TIM_H_VAL.i > _225ms_min) && (TIM_H_VAL.i < _225ms_max)) //2.25ms比較 43 { 44 PCA0CPM0 = posedge; //設置捕獲高電平 45 CR = 1; 46 rep_fg = 1; //重發標誌 47 state = 0x3; 48 } else //干擾信號,從新開始 49 { 50 PCA0CPM0 = engedge; //設置捕獲低電平 51 state = 0x0; 52 } 53 } 54 break; 55 /*----------------------------------------------------------------------------*/ 56 case 0x3: //低電平寬度 0.56ms 57 TIM_L_VAL.c[1] = PCA0CPL0; 58 TIM_L_VAL.c[0] = PCA0CPH0; 59 CR = 0; 60 PCA0L = PCA0H = 0x0; 61 PCA0CPM0 = engedge; 62 if (conut == 32) { 63 if ((key.c[0] == ~key.c[1]) && (key.c[2] == ~key.c[3]) 64 && (key.c[3] == use_code)) { 65 key_code = key.c[1]; 66 key_bit = 1; 67 isr_send_signal(DIS_Handle); 68 } 69 conut = 0x0; 70 state = 0x0; 71 } else { 72 if ((TIM_L_VAL.i > _56ms_min) && (TIM_L_VAL.i < _56ms_max)) //0.56ms比較 73 { 74 if (rep_fg) { 75 state = 0x0; //重發碼 76 rep_fg = 0; 77 //isr_send_signal(DIS_Handle); 78 } else { 79 CR = 1; 80 state = 0x4; 81 } 82 } else 83 state = 0x0; 84 } 85 break; 86 /*----------------------------------------------------------------------------*/ 87 case 0x4: //高電平寬度 88 TIM_H_VAL.c[1] = PCA0CPL0; 89 TIM_H_VAL.c[0] = PCA0CPH0; 90 CR = 0; 91 PCA0L = PCA0H = 0x0; 92 key.l = key.l >> 1; 93 if ((TIM_H_VAL.i > _169ms_min) && (TIM_H_VAL.i < _169ms_max))//1.69ms比較 94 key.l |= 0x80000000; 95 if ((TIM_H_VAL.i > _56ms_min) && (TIM_H_VAL.i < _56ms_max)) //0.56ms比較 96 key.l &= ~0x80000000; 97 CR = 1; 98 PCA0CPM0 = posedge; //設置捕獲高電平 99 state = 0x3; 100 conut++; 101 break; 102 /*----------------------------------------------------------------------------*/ 103 default: 104 CR = 0; 105 PCA0L = PCA0H = 0x0; 106 PCA0CPM0 = engedge; 107 state = 0x0; 108 break; 109 /*----------------------------------------------------------------------------*/ 110 } 111 CCF0 = 0; 112 EA = 1; 113 }
狀態0產生後,開始計數,並設置捕獲上升沿。捕獲到上升沿,進入到狀態1,分析是不是9ms。
狀態3和狀態4是核心部分,接收32位有效數據,而且判斷是否有效。當爲有效按鍵時,會發送一個信號,顯示任務會等待這個信號。
代碼的第92行到第96行,接收位的處理,先接收到的位存儲在字節的最低位。
總的來講,根據波形合理的設置捕獲方式,判斷起始碼,接收32位數據。