基于STM32和EV1527的无线接收解码程序
一、1527的數據幀結構
無線遙控的編碼,從編碼類型上來說,分為2類,一類是固定碼,也就是編碼芯片的地址是不變的,芯片型號以 EV1527、PT2262 為代表。另一種是滾動碼,芯片的地址碼是變化的,芯片以HS300、HS301為代表。
1 EV1527 數據幀結構
EV1527 是一片由 CMOS 設計制造的可預燒內碼的學習碼編碼IC ,由軟件解碼;內碼共有 20 個位元可預燒 1048576 組內碼組合,降低使用上編碼重復的機率。
EV1527 每幀數據由 24 個數據位組成,前 20 位為地址碼,對于一個芯片來說,地址位的內容是固定的,是出廠前就預制好的,并且理論上每個芯片的地址碼是唯一的。后面 4 位為按鍵碼,對應芯片上的K0-K3 4 根數據線,數據線的狀態不同,按鍵碼就不同。
在數據位之前,還有一個同步脈沖,也就是每幀數據都是從同步
脈沖開始的。數據位的“1”和“0”是由高低電平寬度(脈沖寬度)的比例決定的。如果高電平寬度為低電平寬度的 3 倍,就表示邏輯“1”,反過來如果低電平為高電平寬度的 3 倍,就表示邏輯“0”。同步脈沖高電平和低電平的比例固定為 4:124.
二、中斷方式的解碼
把串行輸入的編碼數據幀,還原成編碼之前的狀態,讀取其中
的地址碼和按鍵碼,稱之為解碼。
數據幀都是由同步頭開始,然后是 24位的數據碼,并且此數據幀在遙控器按鍵的過程中是重復出現的,我們首先要判斷同步碼,判斷出了同步碼,就知道數據碼是從那一位開始了。對于一款量產的無線遙控器來說,他的編碼芯片匹配的電阻是一個固定值,也就是說它發射的數據幀的脈沖寬度是不變的,所以我們可以通過測量高低脈沖寬度的方式來分辨同步碼、邏輯“1”、邏輯“0”。
具體的方法是這樣的,首先啟用定時器,裝入一個初值,打開
定時器中斷,讓其以固定的間隔進入中斷程序。在中斷程序中,我們查詢數據輸入管腳的狀態,如果為高電平,就在高電平狀態累加計數,反之就在低電平狀態計數,當電平發生上升沿變化的時候,判斷接收到的高低電平寬度的值是否符合同步信號的要求,如果符合就進入數據位的接收,以同樣的方式判斷邏輯“1”或邏輯“0”。如果接受過程中出現不符合要求的電平狀態,就退出接收,為了增加可靠性,我們一般要求規定時間內,成功接收到完全相同的 2 幀數據才算有效。
接收完成后,24 個數據位被放入 3 個字節中。下一步我們要對接收到的數據進行處理,判斷編碼的類型,分離地址碼和按鍵碼。
三、程序代碼
/*main.c*/#include "stm32f10x.h" #include "uart.h" #include "led.h" #include "delay.h" #include "sys.h" #include "timer.h"uint8_t rf_data[4]; extern uint8_t decode_ok; //解碼成功標志位 extern uint8_t RF;int main(void) { LED_Init();Uart_Init();delay_init(); //延時初始化一定要加上!!!!!!EV1527_GPIO_Init();TIM6_NVIC_Init();TIM6_Mode_Init();while(1){if(decode_ok == 1) //解碼成功{switch(rf_data[2]){case 0xf8: //解碼為0xf8,點亮LED{LED1 = LED_ON;LED2 = LED_ON;LED3 = LED_ON;break;}case 0xf2: //解碼為0xf2,熄滅LED{LED1 = LED_OFF;LED2 = LED_OFF;LED3 = LED_OFF;break;}}} /***調試用代碼,查看接收到的編碼***/ // printf("\r\n EV1527 \r\n"); // delay_ms(500); // printf("i get %x ",rf_data[0]); // delay_ms(500); // printf("i get %x ",rf_data[1]); // delay_ms(500); // printf("i get %x ",rf_data[2]); // delay_ms(500); // printf("i get %x ",rf_data[3]); // delay_ms(500);} } /************** END OF FILE *****************//*Timer.c*/#include "stm32f10x.h" // Device header#include "timer.h" #include "led.h" #include "uart.h" #include "delay.h"void EV1527_GPIO_Init() //EV1527 IO口初始化 {GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // PB9 輸入端GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStruct); }//中斷函數使用定時器6void TIM6_NVIC_Init() //中斷分組初始化 { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //TIM6中斷 NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //先占優先級2級 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //從優先級0級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //IRQ通道被使能 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器 NVIC_Init(&NVIC_InitStructure); }void TIM6_Mode_Init() { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//使能TIM6時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //初始化定時器6//設定計數器自動重裝值 TIM_TimeBaseStructure.TIM_Period = 100; //時鐘預分頻系數 驅動計數器的時鐘 CK_CNT=CK_INT/(71+1) = 1M//計數器計數1次時間等于1/CK_CNT = 1usTIM_TimeBaseStructure.TIM_Prescaler =71; //設置時鐘分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //TIM向上計數模式TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //根據指定的參數初始化TIMx的時間基數單位TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); //允許更新中斷 TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);TIM_ClearFlag(TIM6,TIM_FLAG_Update);//使能定時器6TIM_Cmd(TIM6,ENABLE ); }uint8_t RF; uint8_t decode_ok; //解碼成功 uint8_t hh_w,ll_w; //高,低電平寬度 uint8_t ma_x; //接收到第幾位編碼了 uint8_t bma1,bma2,bma3,bma4; //用于接收過程存放遙控編碼,編碼比較兩次,這是第一次 uint8_t mma1,mma2,mma3,mma4; uint8_t mmb1,mmb2,mmb3,mmb4; // 用于接收過程存放遙控編碼,第二次 //extern uint8_t mmb1,mmb2,mmb3,mmb4;uint8_t rf_ok1,rf_ok2,rf_ok; //解碼過程中的臨時接收成功標志,接收到一個完整的遙控命令后置1,通知解碼程序可以解碼了 uint8_t old_rc5; //保存上一次查詢到的電平狀態 uint8_t tb_ok; //接收到同步的馬時置1 uint8_t D0,D1,D2,D3 ; uint16_t s ,s1; uint8_t bt_auto; //自動設置遙控接收波特率標志 extern uint8_t rf_data[4]; void TIM6_IRQHandler() {if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET){TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //接收數據的電平 PB9RF = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9); if (!RF) { ll_w++; // 檢測到低電平 低電平時間加1,記錄本 // 次電平狀態old_rc5old_rc5=0; } else // 檢測到高電平{ hh_w++;if (!old_rc5) // 檢測到從低到高的跳變,已檢測// 到一個完整(高-低)電平周期{ //判同步碼 2/5 100/130if (((hh_w>=2)&&(hh_w<=5))&&((ll_w>=100)&&(ll_w<=130))) { tb_ok = 1 ;ma_x = 0;bma1=0; bma2=0; bma3=0; bma4=0; }else if ((tb_ok)&&((ll_w>=8)&&(ll_w<=13))) //8/13{ ma_x++; //已經接收到同步碼,判0if(ma_x>23){if(!rf_ok1) //rf_ok1臨時接收成功{ //將接收到的編碼復制到解碼寄存器中 mma1=bma1;mma2=bma2;mma3=bma3;mma4=bma4; // 通知解碼子程序可以解碼了 rf_ok1=1; tb_ok=0;s=1000; }else{//將接收到的編碼復制到解碼寄存器中 mmb1=bma1;mmb2=bma2;mmb3=bma3;mmb4=bma4; // 通知解碼子程序可以解碼了 rf_ok2=1; tb_ok=0; }}} else if ((tb_ok)&&((ll_w>=2)&&(ll_w<=7))) // 2/7{ switch (ma_x){ case 0 : { bma1=bma1 | 0x80; break; } //遙控編碼第1位case 1 : { bma1=bma1 | 0x40; break; }case 2 : { bma1=bma1 | 0x20; break; }case 3 : { bma1=bma1 | 0x10; break; }case 4 : { bma1=bma1 | 0x08; break; }case 5 : { bma1=bma1 | 0x04; break; }case 6 : { bma1=bma1 | 0x02; break; }case 7 : { bma1=bma1 | 0x01; break; }case 8 : { bma2=bma2 | 0x80; break; }case 9 : { bma2=bma2 | 0x40; break; }case 10: { bma2=bma2 | 0x20; break; }case 11: { bma2=bma2 | 0x10; break; }case 12: { bma2=bma2 | 0x08; break; }case 13: { bma2=bma2 | 0x04; break; }case 14: { bma2=bma2 | 0x02; break; }case 15: { bma2=bma2 | 0x01; break; }case 16: { bma3=bma3 | 0x80; break; }case 17: { bma3=bma3 | 0x40; break; }case 18: { bma3=bma3 | 0x20; break; }case 19: { bma3=bma3 | 0x10; break; }case 20: { bma3=bma3 | 0x08; break; }// 按鍵狀態第1位case 21: { bma3=bma3 | 0x04; break; }case 22: { bma3=bma3 | 0x02; break; }case 23: { bma3=bma3 | 0x01; if(!rf_ok1){mma1=bma1;mma2=bma2;mma3=bma3;// mma4=bma4; // 將接收到的編碼復制到解碼寄存器中 rf_ok1=1; // 通知解碼子程序可以解碼了tb_ok=0; // bt_auto=0;s=1000;break; }else{mmb1=bma1;mmb2=bma2;mmb3=bma3;//mmb4=bma4; // 將再次接收到的編碼復制到解碼寄存器中, rf_ok2=1; // 通知解碼子程序可以解碼了tb_ok=0;break; } }} ma_x++; }else{ma_x=0; tb_ok=0;bt_auto=0;bma1=0;bma2=0; bma3=0; hh_w=1;ll_w=0;} //接收到不符合的高-低電平序列ll_w=0;hh_w=1; } old_rc5=1; // 記錄本次電平狀態}if(rf_ok1) //規定時間內接受到2幀相同的編碼數據才有效{s--;if(!s) rf_ok1=0;if(rf_ok2) {if((mma1==mmb1)&&(mma2==mmb2)&&(mma3==mmb3)){rf_ok=1;rf_ok1=0;rf_ok2=0; }else{rf_ok=0;rf_ok1=0;rf_ok2=0;} } }if((rf_ok)) //判斷是否接收成功{ TIM_ITConfig(TIM6, TIM_IT_Update, DISABLE);rf_ok=0; rf_data[0]=mma1;rf_data[1]=mma2;rf_data[2]=mma3;decode_ok=1;TIM_ITConfig(TIM6 , TIM_IT_Update, ENABLE);}} }總結
以上是生活随笔為你收集整理的基于STM32和EV1527的无线接收解码程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FPGA学习心得分享——交通灯(EGO1
- 下一篇: linux笔记本安装双显卡驱动(inte