C8051 PCA實現紅外遙控接收


 

   這里使用的處理器是C8051F005。紅外接收頭接處理器引腳,中斷方式接收按鍵數據。

 


 

一 PCA介紹

 1.1 PCA  

  可編程計數器陣列(PCA)提供增強的定時器功能,與標准8051計數器/定時器相比,它需要較少的CPU干預。PCA包含一個專用的16位計數器/定時器和5個16位捕捉/比較模塊。每個捕捉/比較模塊有其自己的I/O線(CEXn)。當被允許時,I/O線通過交叉開關連到端口I/O。

  計數器/定時器由一個可配置的時基信號驅動,可以在四個輸入源中選擇時基信號:系統時鍾12分頻、系統時鍾4分頻、定時器0溢出或ECI線上的外部時鍾信號。對PCA的配置和控制是通過系統控制器的特殊功能寄存器來實現的。PCA的基本原理框圖下圖。

   

 1.2 捕捉/比較模塊

  每個模塊都可被配置為獨立工作,有四種工作方式:邊沿觸發捕捉、軟件定時器、高速輸出和脈寬調制器。每個模塊在CIP-51系統控制器中都有屬於自己的特殊功能寄存器(SFR)。這些寄存器用於配置模塊的工作方式和與模塊交換數據。

  PCA0CPMn寄存器用於配置PCA捕捉/比較模塊的工作方式,下表概述了模塊工作在不同方式時該寄存器各位的設置情況。置‘1’ PCA0CPMn寄存器中的ECCFn位將允許模塊的CCFn中斷。

  注意:要使單獨的CCFn中斷得到響應,必須先整體允許PCA0中斷。通過將EA位(IE.7)和EPCA0位(EIE1.3)設置為邏輯1來整體允許PCA0中斷。

    

 1.3 邊沿觸發的捕捉方式

  在該方式,CEXn引腳上出現的有效電平變化導致PCA捕捉PCA計數器/定時器的值並將其裝入到對應模塊的16位捕捉/比較寄存器(PCA0CPLn和PCA0CPHn)。

  PCA0CPMn寄存器中的CAPNn位用於選擇觸發捕捉的電平變化類型:低電平到高電平(正沿)、高電平到低電平(負沿)或任何變化(正沿或負沿)。

  當捕捉發生時,PCA0CN中的捕捉/比較標志(CCFn)被置為邏輯1並產生一個中斷請求(如果CCF中斷被允許)。

  當CPU轉向中斷服務程序時,CCFn位不能被硬件自動清除,必須用軟件清0。

   


 

二、紅外編碼

 2.1數據格式

  數據格式包括了引導碼、用戶碼、數據碼和數據碼反碼,編碼總占32 位。數據反碼是數據碼反相后的編碼,編碼時可用於對數據的糾錯。注意:第二段的用戶碼也可以在遙控應用電路中被設置成第一段用戶碼的反碼。

   

 2.2位定義

  用戶碼或數據碼中的每一個位可以是位‘1’,也可以是位‘0’。區分‘0’和‘1’是利用脈沖的時間間隔來區分,這種編碼方式稱為脈沖位置調制方式,英文簡寫PPM。

   

  這里只介紹了紅外的一些簡單的知識,還有其他重復碼等知識自行學習。

 


 

三、實現

 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            //負沿捕捉功能使能
define

  上面一部分的時間是這樣算出來的,系統采用的時鍾是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位數據。

 

 


免責聲明!

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



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