zigbee 万能遥控器 裸机发送和协议栈发送
生活随笔
收集整理的這篇文章主要介紹了
zigbee 万能遥控器 裸机发送和协议栈发送
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
HX1010
http://www.sbprojects.com/knowledge/ir/index.php
遙控編碼
http://www.sbprojects.com/knowledge/ir/rc5.php
http://www.sbprojects.com/knowledge/ir/nec.php
發送方:波形圖上的高電平對應發相同時間長度的38KHZ方波;波形圖上的低電平對應停止發送對應時間長度的方波(即保持低或高電平即可)
比如在發送方發送引導碼時,先發送9ms的38KHZ防波,然后停止發送4.5ms。接著發送數據。
發送數據0時,先發送0.56ms的38KHZ方波,然后停止發送0.56ms.接著發送下一位。發送數據1時,先發送0.56ms的38KHZ方波,然后停止發送1.68ms.接著發送下一位。全部數據發送完成之后,就停止發送。
接收方:IRM3638,平時沒接收到38KHZ方波時,輸出高電平;接收到38KHZ方波時,持續輸出低電平,直到方波消失。
比如在接收到波形圖上的高電平時(即接收發送者發送的方波時),持續輸出低電平,直到法波消失。
http://www.100y.com.tw/pdf_file/FM-6038LM-5A.pdf
裸機發送:
#include <ioCC2530.h> #define IROUT P1_1 //紅外發射腳 #define RLED P1_0 //紅外接收 #define uchar unsigned char #define uint unsigned int/***************************************** //定義全局變量 *****************************************///接收模式 unsigned int irtime;//紅外用全局變量 unsigned char irok;//=1,表示一組連續的紅外代碼已經成功接收完畢 unsigned char irpro_ok;//=1,表示紅外代碼已經解析完畢 unsigned char IRCode[4]; //處理后的紅外碼,分別是 客戶碼,客戶碼,數據碼,數據碼反碼 unsigned short __xdata IRSourceData[160]; //33個高低電平的時間數據unsigned char __xdata IRSourceData2[14]= {0x65,0x4b,0x00,0x00,0x02,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xba };//haier kogntiao kaiji 29static char ifg=0;//每次按下遙控器時,會觸發多次紅外中斷,只需在第一次紅外中斷時開啟定時器,ifg=0表示初次紅外中斷//發射模式 uint counter = 0; uchar LEDFlag = 0; uchar ucIs38KHZ=0; uint uiCurrentCount=0; uint uiTotalCount=0;void Delay(uint n) {uint i;for(i = 0;i<n;i++);for(i = 0;i<n;i++);for(i = 0;i<n;i++);for(i = 0;i<n;i++);for(i = 0;i<n;i++); }extern void SendIRdata2(char cData); //接收模式的函數 void Ircordpro(void)//紅外碼值處理函數 { unsigned char i, j, k;unsigned int cord,value;k=1;for(i=0;i<4;i++) //處理4個字節{for(j=1;j<=8;j++) //處理1個字節8位{cord=IRSourceData[k];if(cord>67*2)//大于某值為1,這個和晶振有絕對關系,這里使用12M計算,此值可以有一定誤差value=value|0x80;else value=value;if(j<8)value=value>>1;k++;}IRCode[i]=value;value=0; } irpro_ok=1;}//紅外接收中斷處理 #pragma vector = P1INT_VECTOR__interrupt void P1_ISR(void){if(P1IFG & 0x01) //紅外中斷{//需要在前面清理中斷標志P1IFG &= 0; P1IF=0;static unsigned int iIndex=0; //每次按下遙控器時,會觸發多次紅外中斷,只需在第一次紅外中斷時開啟定時器,ifg=0表示初次紅外中斷if(ifg==0){T4CTL |= 0x10; //啟動定時器T4ifg=1;irtime=0;iIndex=0;//重新開始for(int i=0;i<160;i++)//初始化數組為0IRSourceData[i]=0;return ;//第一個下降沿測得的irtime不要,因為=0}//if(irtime<605*2&&irtime>=317*2)//引導碼 TC9012的頭碼,9ms+4.5ms// i=0;IRSourceData[iIndex]=irtime;irtime=0;iIndex++; } if(P1IFG & 0x04) //按鍵中斷{Delay(5);if(P1IFG & 0x04) { //需要在前面清理中斷標志P1IFG &= 0; //清中斷標志P1IF=0;Delay(5);SendIRdata2(68);P1_4=0;//表示發送完畢,進行下一個接收}}}//接收定時器,產生38KHZ方波 #pragma vector = T4_VECTOR __interrupt void T4_ISR(void) {if(TIMIF &= 0x18) //Timer4溢出? {irtime++;//判斷對方的一組連續的代碼是否發送完畢//如果長時間(>6000)未接收到相鄰的一個下降沿,判定此組紅外代碼完畢//此時就停掉定時器,并且//置ifg標志為0,為下一組代碼做初始化的準備//置irok標志為1,表示此組紅外代碼已經接收完畢,后續處理使用此標志if(irtime>6000){T4CTL &= ~0x10; // 停止定時器T4ifg=0;irok=1;}//需要在最后清理中斷標志TIMIF &= ~0x18; //清除Timer4溢出中斷標記IRCON &= ~0x10; //清除Timer4中斷標記}}//初始化紅外接收 //p1.0是紅外接收腳,需配置為中斷,下降沿觸發。核心板的第14腳。也是LED1. void InitReceiveIR(void) {EA=0;P1INP |= 0x01; //上拉 P1IEN |= 0X01; //P10設置為中斷方式PICTL |= 0X02; //下降沿觸發IEN2 |= 0x10; // P1 使能中斷;P1IFG |= 0x00; //初始化中斷標志位//EA = 1; }//初始化定時器4 void InitT4(void) {EA=0;T4CTL = 0x07; //不分頻,Up-Down Mode(0x00->T1CC0->0x00)T4CC0 = 0x30; //設定初值TIMIF &= ~0x18; //清除Timer4溢出中斷標記 T4CTL |= 0x08; //設定Timer4溢出中斷使能IRCON &= ~0x10; //清除Timer4中斷標記IEN1 |= 0x10; //設定Timer中斷使能//EA = 1; }//接收模式的函數//發送模式的函數void StartAndSendIRData(uint TotalCoun,uchar Is38KHZ) { #if 1ucIs38KHZ=Is38KHZ;uiCurrentCount=0;do{}while(uiCurrentCount<TotalCoun);ucIs38KHZ=0;//發送完成之后停止發射載波 #endif }void SendIRdata(char cData) {if(IRSourceData[0]==0)return;//開啟定時器T4T4CTL |= 0x10; int i,j;unsigned short irdata=0;//發送引導碼irdata=IRSourceData[0];//先發送0.56ms的38KHZ紅外波(即編碼中0.56ms的高電平)StartAndSendIRData(irdata/2,1);//停止發送紅外信號(即編碼中的低電平)StartAndSendIRData(irdata/2,0); //1為寬的低電平//StartAndSendIRData(irdata,0);//0為窄的低電平irdata=IRSourceData[1];//先發送0.56ms的38KHZ紅外波(即編碼中0.56ms的高電平)StartAndSendIRData(irdata/2,1);//停止發送紅外信號(即編碼中的低電平)StartAndSendIRData(irdata/2,0); //1為寬的低電平//StartAndSendIRData(irdata,0);//0為窄的低電平//發送數據碼j=2;while(IRSourceData[j]!=0){irdata=IRSourceData[j];if(irdata>120){StartAndSendIRData(irdata/2,1); StartAndSendIRData(irdata/2,0); }else {StartAndSendIRData(irdata/4,1); StartAndSendIRData(irdata*3/4,0);}j++;}// 再發送一位,以便使得接收端產生一個中斷,確定上一位的持續時間irdata=0x1;for(i=0;i<1;i++){//先發送0.56ms的38KHZ紅外波(即編碼中0.56ms的高電平)StartAndSendIRData(22,1);//停止發送紅外信號(即編碼中的高電平)if(irdata & 1)StartAndSendIRData(65,0); //1為寬的低電平elseStartAndSendIRData(22,0);//0為窄的低電平irdata=irdata>>1;}//發送完畢時關閉定時器T4T4CTL &= ~0x10; }void SendIRdata2(char cData) {int i;unsigned char irdata;T3CTL |= 0x10; #if 0//發送9ms的38KHZ起始碼StartAndSendIRData(346,1);//停止發送4.5ms,屬于起始碼StartAndSendIRData(173,0); #endif //發送9ms的38KHZ起始碼StartAndSendIRData(346*48/100,1);//停止發送4.5ms,屬于起始碼StartAndSendIRData(173*48/100,0);//發送9ms的38KHZ起始碼StartAndSendIRData(346*60/98,1);//停止發送4.5ms,屬于起始碼StartAndSendIRData(173*60/98,0);for(int j=0;j<14;j++){irdata=IRSourceData2[j];for(i=0;i<8;i++){//先發送0.56ms的38KHZ紅外波(即編碼中0.56ms的高電平)StartAndSendIRData(22,1);//停止發送紅外信號(即編碼中的低電平)if(irdata & 1)StartAndSendIRData(65,0); //1為寬的低電平elseStartAndSendIRData(22,0);//0為窄的低電平irdata=irdata>>1;}}// 再發送一位,以便使得接收端產生一個中斷,確定上一位的持續時間irdata=0x1;for(i=0;i<1;i++){//先發送0.56ms的38KHZ紅外波(即編碼中0.56ms的高電平)StartAndSendIRData(22,1);//停止發送紅外信號(即編碼中的高電平)if(irdata & 1)StartAndSendIRData(65,0); //1為寬的低電平elseStartAndSendIRData(22,0);//0為窄的低電平irdata=irdata>>1;}T3CTL &= ~0x10;}//發送定時器,產生38KHZ方波 #pragma vector = T3_VECTOR __interrupt void T3_ISR(void) {if(TIMIF &= 0x01) //Timer4溢出? {uiCurrentCount++;if(ucIs38KHZ==1)IROUT = !IROUT;//載波發射elseIROUT =0;//不發射,保持0或者1均可//需要在最后清理中斷標志TIMIF &= ~0x01; //清除Timer4溢出中斷標記,cpu自動也會清除}IRCON &= ~0x08; //清除Timer4中斷標記,,cpu自動也會清除}//初始化紅外發送 //p1.1是紅外發送腳,需配置為輸出。核心板的第13腳。也是LED2. void InitSendIR(void) {P1SEL &= ~0x02; //設定P1_1為通用I/OP1DIR |= 0x02; IROUT = 1; }//初始化定時器3,用于產生發送方波,38KhZ void InitT3(void) {EA=0;T3CTL = 0x07; //不分頻,Up-Down Mode(0x00->T1CC0->0x00)T3CC0 = 0x30; //設定初值TIMIF &= ~0x01; //清除Timer4溢出中斷標記 T3CTL |= 0x08; //設定Timer4溢出中斷使能IRCON &= ~0x08; //清除Timer4中斷標記IEN1 |= 0x08; //設定Timer中斷使能//EA = 1; }//發送模式的函數//設置發送鍵P1_2即中斷 void InitKey(void) {//P1SEL &= ~0x04; //設定P1_2為通用I/O//P1DIR &= ~0x04; //P1INP &= ~0x04;EA=0;P1INP |= 0x04; //上拉 P1IEN |= 0X04; //P12設置為中斷方式PICTL |= 0X02; //下降沿觸發IEN2 |= 0x10; // P1 使能中斷;P1IFG |= 0x04; //初始化中斷標志位 }//設置學習成功指示燈P1_4即S2為通用,輸出 void InitLED(void) {P1SEL &= ~0x10; //設定P1_4為通用I/OP1DIR |= 0x10; P1INP &= ~0x10;P1_4=0;}main() { InitLED();InitT4();InitReceiveIR(); InitKey();InitT3();InitSendIR();EA = 1;while(1)//主循環{ #if 1if(irok) //如果接收好了進行紅外處理{//Ircordpro();irok=0;P1_4=1;//表示接受完畢。可以發送}if(irpro_ok) //如果處理好后進行工作處理,如按對應的按鍵后顯示對應的數字等{// Ir_work();}#endif }}
協議棧 接收
2013-5-29 18:01:45
使用兩個外部中斷,上升沿和下降沿觸發,可以識別所有紅外協議
/** bysong 2013-3-11 8:19:28 process receiving the ir signal */#include "OSAL.h" #include "ZGlobals.h" #include "AF.h" #include "aps_groups.h" #include "ZDApp.h" #include "OnBoard.h"/* HAL */ #include "hal_lcd.h" #include "hal_led.h" #include "hal_key.h" #include "sapi.h" #include "smt_ir_rec.h"//#include "zcl_general.h"//中斷數目 #define MAX_IRDATA_NUM 230 #define MAX_IRHEAD_NUM 10 #define MAX_IRTAIL_NUM 10#define MAX_IR_BYTE_NUM ((MAX_IRHEAD_NUM+MAX_IRTAIL_NUM+MAX_IRDATA_NUM)*2)static uint16 *m_pu16IRSourceData=NULL; //MAX_DATALEN個高低電平的時間數據//static uint16 __xdata m_pu16IRSourceData3[MAX_IRDATA_NUM]; //MAX_DATALEN個高低電平的時間數據 //static uint16 __xdata m_szu16IRSourceDataR[MAX_DATALEN]; //MAX_DATALEN個高低電平的時間數據 static uint16 m_u16SourceDataTotalNum;//實際接收到的有效位個數,包括data,head和tail static uint32 m_u32IRtime;//紅外用全局變量 static bool m_bIRok=0;//紅外位數據已經接收到 static uint8 m_u8Ifg=0;//每次按下遙控器時,會觸發多次紅外中斷,只需在第一次紅外中斷時開啟定時器,m_u8Ifg=0表示本次中斷是初次紅外中斷//初始化紅外接收 //由于p1.0-led1-irin已經作為led顯示使用,協議棧中很多地方都使用led1作為指示使用,所以選用了p1.3-botton2, //此時需要隔斷紅外芯片的1腳,直接連到p1.3,即p16的37腳, //由于紅外1腳在有載波信號時輸出0,所以p1.3最好要上拉, void smt_ir_rec_InitReceiveIR(void) {if ( m_pu16IRSourceData== NULL)m_pu16IRSourceData=(uint16 *)osal_mem_alloc(MAX_IR_BYTE_NUM);if ( m_pu16IRSourceData== NULL)SystemReset();osal_memset(m_pu16IRSourceData,0,MAX_IR_BYTE_NUM);//return;EA=0; #if 1// 使用p1.3,button2P1INP |= 1<<3; //上拉 P1IEN |= 1<<3; //P13中斷使能PICTL |= (1<<1); //下降沿觸發 #endif#if 1// 使用p1.7P1INP |= 1<<7; //上拉 P1IEN |= 1<<7; //P17中斷使能PICTL &= ~(1<<2); //上升沿觸發 #endifP1IFG |= 0x00; //初始化中斷標志位IEN2 |= 1<<4; // P1 使能中斷;EA = 1; }void smt_ir_rec_StopReceiveIR(void) {// 使用p1.3,button2//P1INP |= 0x01; //上拉 if(m_pu16IRSourceData!=NULL){osal_mem_free(m_pu16IRSourceData);m_pu16IRSourceData=NULL;}//return;//P1IEN &= ~0x08; P1IEN &= ~(1<<3); P1IEN &= ~(1<<7); IEN2 &= ~(1<<4); // EA = 0; }//紅外接收中斷處理 /* #pragma vector = P1INT_VECTOR__interrupt void smt_ir_rec_P1_ISR(void) #pragma vector = P1INT_VECTOR__interrupt void smt_ir_rec_P1_ISR(void) */ #if 1HAL_ISR_FUNCTION( smt_ir_rec_P1_ISR, P1INT_VECTOR ){static uint16 u16_Index=0;if(P1IFG & 0x08) //紅外中斷,p1.3,下降沿中斷中記錄的是上次高電平電平持續的時間{P1IFG = 0;P1IF=0;//if(P1IFG==0) //紅外中斷{ //每次按下遙控器時,會觸發多次紅外中斷,只需在第一次紅外中斷時開啟定時器,m_u8Ifg=0表示初次紅外中斷if(m_u8Ifg==0){smt_ir_rec_InitT4();//啟動定時器T4。如果直接使用T4CTL |= 0x10去啟動,有時候會啟動失敗m_u8Ifg=1;m_u32IRtime=0;u16_Index=0;//重新開始m_u16SourceDataTotalNum=0;osal_memset( m_pu16IRSourceData, 0, MAX_IR_BYTE_NUM );// osal_memset( m_szu16IRSourceDataR, 0, sizeof(m_szu16IRSourceDataR) );return ;//第一個下降沿測得的irtime不要,因為=0}if( m_u16SourceDataTotalNum < MAX_IR_BYTE_NUM/2){m_pu16IRSourceData[u16_Index++]=m_u32IRtime;//t4中斷次數存儲起來m_u16SourceDataTotalNum=u16_Index;m_u32IRtime=0;//清零,為下一次中斷準備}} } #if 1if(P1IFG & 0x80) //紅外中斷,p1.7,上升沿中斷中記錄的是上次低電平持續的時間{P1IF = 0;P1IFG = 0;//if(P1IFG==0) //紅外中斷{ if( m_u16SourceDataTotalNum < MAX_IR_BYTE_NUM/2){m_pu16IRSourceData[u16_Index++]=m_u32IRtime;//t4中斷次數存儲起來m_u16SourceDataTotalNum=u16_Index;m_u32IRtime=0;//清零,為下一次中斷準備}}}P1IF = 0;P1IFG = 0;/*if(P1IFG!=0){P1IF = 0;P1IFG = 0;}*/ #endif}#endif/* 定時器t4在hal_timer.c中已經定義了中斷處理函數,所以先要在hal_timer.c中注釋掉,如下HAL_ISR_FUNCTION( halTimer4Isr, T4_VECTOR ) {halProcessTimer4 (); }否則中斷發生時會進入hal_timer.c中的中斷處理函數中執行 *//*#pragma vector = T4_VECTOR __interrupt void smt_ir_rec_T4_ISR(void)#pragma vector = T4_VECTOR __interrupt void smt_ir_rec_T4_ISR(void) */ #if 1 HAL_ISR_FUNCTION( smt_ir_rec_T4_ISR, T4_VECTOR ) {// if(TIMIF &= 0x18) //Timer4溢出? {m_u32IRtime++; //判斷對方的一組連續的代碼是否發送完畢 //如果長時間(>16000)未接收到相鄰的一個下降沿,判定此組紅外代碼完畢 //此時就停掉定時器,并且 //置ifg標志為0,為下一組代碼做初始化的準備 //置irok標志為1,表示此組紅外代碼已經接收完畢,后續處理使用此標志 if(m_u32IRtime>16000){T4CTL &= ~0x10; // 停止定時器T4m_u8Ifg=0;if(m_pu16IRSourceData[0]<6|| m_pu16IRSourceData[1]<6|| m_pu16IRSourceData[2]<6 || m_pu16IRSourceData[3]<6 || m_pu16IRSourceData[4]<6 || m_pu16IRSourceData[5]<6 || m_pu16IRSourceData[6]<6 || m_pu16IRSourceData[7]<6 )//在自己發射時,雖然禁止了接受,但也會檢測到全是0的ir碼,需排除此種情況m_bIRok=0;elsem_bIRok=1;}//TIMIF &= ~0x18; //清除Timer4溢出中斷標記IRCON &= ~0x10; //清除Timer4中斷標記} } #endif//初始化定時器4 void smt_ir_rec_InitT4(void) {T4CTL = 0x07; //不分頻,Up-Down Mode(0x00->T1CC0->0x00)T4CC0 = 210; //設定初值TIMIF &= ~0x18; //清除Timer4溢出中斷標記 T4CTL |= 0x08; //設定Timer4溢出中斷使能IRCON &= ~0x10; //清除Timer4中斷標記IEN1 |= 0x10; //設定Timer中斷使能EA = 1;T4CTL |= 0x10; //啟動定時器T4 }//m_u16SourceDataTotalNum是中斷個數,每個占用2個字節 //為了節約資源,傳輸時,前面10個中斷數每個占2個字節,后面10個每個中斷數每個占2個字節,中間每個占1個字節 uint16 smt_ir_rec_GetIRSourceData(uint8 * pu8IRSourceData) {//return 20;if(m_bIRok==1){m_bIRok=0;uint16 byteNum =0;byteNum= Uint162Ir(m_pu16IRSourceData,m_u16SourceDataTotalNum<<1,pu8IRSourceData);osal_memset( m_pu16IRSourceData, 0, MAX_IR_BYTE_NUM );// byteNum=200;return byteNum;}elsereturn 0; }/*** 返回轉化為1字節的數目的字節總數目 */ uint16 Uint162Ir(uint16 *pSrc,uint16 srcByteCnt,uint8 *pDst) {uint16 ret=0;if(srcByteCnt<=0)return 0;if(srcByteCnt>(MAX_IRHEAD_NUM+MAX_IRHEAD_NUM+MAX_IRDATA_NUM)*2 )return 0;if(srcByteCnt <= (MAX_IRHEAD_NUM+MAX_IRHEAD_NUM)*2){osal_memcpy(pDst,pSrc,srcByteCnt);ret=srcByteCnt;}else if(srcByteCnt > (MAX_IRHEAD_NUM+MAX_IRHEAD_NUM)*2){uint16 dataByteCnt=( srcByteCnt- ((MAX_IRHEAD_NUM+MAX_IRHEAD_NUM) *2 ) );osal_memcpy(pDst,pSrc,MAX_IRHEAD_NUM*2);osal_memcpy(&pDst[MAX_IRHEAD_NUM*2+dataByteCnt/2],&pSrc[MAX_IRHEAD_NUM+dataByteCnt/2],MAX_IRTAIL_NUM*2); //process data //2字節數據--》1字節數據for(uint16 i=0;i<dataByteCnt/2;i++){//pDst是單字節類型//pSrc是雙字節類型pDst[MAX_IRHEAD_NUM*2+i]=pSrc[MAX_IRHEAD_NUM+i];}ret=(dataByteCnt>>1) + ((MAX_IRHEAD_NUM+MAX_IRHEAD_NUM)<<1);}return ret; }/*** 返回轉化為2字節的數目的字節總數目*/ uint16 Ir2Uint16(uint8 *pSrc,uint16 srcByteCnt,uint16 *pDst) {uint16 ret=0;if(srcByteCnt <= (MAX_IRHEAD_NUM+MAX_IRHEAD_NUM)*2){osal_memcpy(pDst,pSrc,srcByteCnt);ret=srcByteCnt;}else if(srcByteCnt > (MAX_IRHEAD_NUM+MAX_IRHEAD_NUM)*2){uint16 dataNum=srcByteCnt-(MAX_IRHEAD_NUM+MAX_IRHEAD_NUM)*2;//cout<<"srcByteCnt "<<srcByteCnt<<endl;//cout<<"dataNum "<<dataNum<<endl;osal_memcpy(pDst,pSrc,MAX_IRHEAD_NUM*2);osal_memcpy(&pDst[MAX_IRHEAD_NUM+dataNum],&pSrc[MAX_IRHEAD_NUM*2+dataNum],MAX_IRTAIL_NUM*2); //process data //1字節數據--》2字節數據for(uint16 i=0;i<dataNum;i++){//pSrc 是單字節類型//pDst是雙字節類型pDst[MAX_IRHEAD_NUM+i]=pSrc[MAX_IRHEAD_NUM*2+i];}ret=(dataNum+MAX_IRHEAD_NUM+MAX_IRHEAD_NUM)*2;}return ret; } /* 本文件內函數調用順序smt_ir_rec_InitReceiveIR(); 即直接在外部函數中調用此函數就可以接收紅外信號了 定時器在接收到紅外中斷信號的時候啟動smt_ir_rec_GetIRCmd(); */
轉載于:https://www.cnblogs.com/-song/archive/2013/02/06/3331829.html
總結
以上是生活随笔為你收集整理的zigbee 万能遥控器 裸机发送和协议栈发送的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Content Provider之一大菊
- 下一篇: android中string.xml文件