本人現在在使用MSP430做系統,現在做了一個按鍵紅外發送數組程序,和一個接收紅外信息之后,正確識別數組,并將數組發送到串口助手以比較發送和接收的數據是否有誤差。這已經通過硬件下載調試了,沒有誤碼,可以直接使用。本人使用的紅外芯片是美國安捷倫公司的HSDL-3201,最大支持115.2Kb/S的紅外發送。由于程序只是在功能上實現了,還沒有進一步優化。 1、按鍵之后紅外發送一個數組
#include<msp430x417.h> #include"led.c" #include"lcd_modle.c" //將其他的函數模塊包涵在一個文件中 #define uchar unsigned char #define uint unsigned int #define TIME 6000 //延時時間常數,延時時間為183ms,其實延時時間常數完全可以設置得小一些,但是由于按鍵抖動得厲害,所以設這么大
//在IAR EW430 編譯器軟件中如何實現高精度軟件延時,利用IAR EW430 內部延時子程序即可方便地實現 #define CPU_F ((double)1048576) //這里是你當前MSP430 CPU的主頻頻率,即CPU的MCLK,單位為HZ #define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) //************************************************************************
//要發送的數據,用關鍵字"const" 聲明,不放在RAM區 const uchar a[6]={0x66,0x83,0x08,0x00,0xE8,0x84}; //加號 const uchar b[6]={0x66,0x83,0x20,0x00,0xF6,0x84}; // 減號 const uchar c[6]={0x66,0x83,0x10,0x00,0xE2,0x84}; //左箭頭 const uchar d[6]={0x66,0x83,0x18,0x00,0xE5,0x44}; //右箭頭 const uchar e[6]={0x66,0x83,0x28,0x00,0xF1,0x44}; //OK const uchar f[6]={0x66,0x83,0x30,0x00,0xFB,0x44}; //C/II const uchar g[6]={0x66,0x83,0x38,0x00,0xFC,0x84}; //開閥 const uchar h[6]={0x66,0x83,0x40,0x00,0xDE,0x84}; //關閥 const uchar i[6]={0x66,0x83,0x48,0x00,0xD9,0x44}; //左右箭頭同時按下
extern void lcd_modle(); //利用函數原型(函數聲明)擴展函數的作用域, void led(); //利用函數原型(函數聲明)擴展函數的作用域, extern可以省略
uchar keybuf=0x00; //鍵值,全局變量的初始化 uchar keytime=0x06; //判斷連鍵時,定時中斷的次數,初始化為6,即連鍵時間間隔設置 //************************************************************************ void settime(long uint ti) //設置定時時間 { CCR0=ti; //定時時間 }
void gostopA(uchar a) //打開或是關閉定時器,其中a為判斷標志 { if(a==1) { TACTL=TASSEL0+TACLR+MC0; //清TAR(消除定時器的方向記憶特性),設置定時器工作在增計數模式,記得選擇ASCLK作為定時時鐘 settime(TIME); } else if(a==0) { TACTL&=~MC0; //定時器暫停計數,TACTL=MC_0;但是并不發生復位,當定時器重新計數時,計數器從暫停時的值開始 } }
//************************************************************************ void timerainit() //定時器A的初始化 { TACTL=TASSEL0+TACLR; //選ASCLK,清TAR, 剛開始并沒有計數 CCTL0=CCIE; //先開允許比較中斷 settime(TIME); //設置時間放在允許中斷的后面 }
//************************************************************************ void gostopkey(uchar sw) //打開或者關閉按鍵中斷 { if(sw==0) P1IE&=0X00; //關閉按鍵中斷 else if (sw==1) P1IE|=0XFF; //打開按鍵中斷允許 }
//************************************************************************ uchar conkey() //連續按鍵的判斷和處理,此模塊放在定時中斷程序中,不知是否需要清定時中斷標志(CCIFG0=0;),不需要消除,它會自動消除,跳出定時中斷 { uchar x=0x00; if((P1IN&0XFF)==0X00) //單獨按鍵,或者是連續按鍵松開之后 { //沒有鍵按下 gostopA(0); //關閉定時器 gostopkey(1); //打開按鍵中斷 } else //連續按鍵的情況 { if(keytime==0) //連續按鍵的時間到 { keytime=0x06; //重新置值 if((P1IN&0XFF)==0X80) { x=1; //給全局變量鍵值賦值 } else if((P1IN&0XFF)==0X40) { x=2; } else if((P1IN&0XFF)==0X20) { x=3; } else if((P1IN&0XFF)==0X10) { x=6; } else if((P1IN&0XFF)==0X08) { x=4; } else if((P1IN&0XFF)==0X04) { x=7; } else if((P1IN&0XFF)==0X02) { x=5; } else if((P1IN&0XFF)==0X01) { x=8; } else if((P1IN&0XFF)==0X18) //組合鍵,4、6組合鍵,組合鍵有效的時間為:按鍵之后:183ms*6,即時間間隔為連鍵時間間隔 { x=9; } else //其他情況 { x=0x00; gostopA(0); //關閉定時器 gostopkey(1); //打開按鍵中斷 }
} else //連續按鍵的時間沒有到 keytime--; } return(x); }
//************************************************************************ #pragma vector=TIMERA0_VECTOR //CCRO中斷,為單源中斷,自動消除中斷標志 __interrupt void Timer_A0(void) //定時器中斷 { keybuf=conkey(); //獲取連續按鍵值,0x00代表沒有連續按鍵 }
//************************************************************************ void keyinit() //按鍵初始化 { P1DIR&=0X00; //P1口接8個按鍵,全部設為輸入 P1IES&=0X00; //設為上升沿中斷 P1IE|=0XFF; //全部允許中斷 P1IFG&=0X00; //清中斷標 }
//************************************************************************ uchar keycode() //判斷單個的鍵值 { uchar y, q0=0; if((P1IN&0XFF)==0X80)//不使用中斷標志查詢中斷源,在按鍵中斷中不識別組合鍵 { y=1; q0=1; } else if((P1IN&0XFF)==0X40) { y=2; q0=1; } else if((P1IN&0XFF)==0X20) { y=3; q0=1; } else if((P1IN&0XFF)==0X10) { y=6; q0=1; } else if((P1IN&0XFF)==0X08) { y=4; q0=1; } else if((P1IN&0XFF)==0X04) { y=7; q0=1; } else if((P1IN&0XFF)==0X02) { y=5; q0=1; } else if((P1IN&0XFF)==0X01) { y=8; q0=1; } else y=0x00; //沒有按鍵按下,或者是其他情況 if(q0==1) //有按鍵按下的情況,為判斷是否按鍵連續做準備 { gostopA(1); //開啟定時中斷 gostopkey(0); //關閉按鍵中斷 } return(y); }
//************************************************************************ #pragma vector=PORT1_VECTOR __interrupt void port1_vector(void) { keybuf=keycode(); P1IFG=0X00;//消除中斷標志,跳出按鍵中斷 }
//************************************************************************ void zijiesend(uchar m) //以19200bit/S紅外發送一個字節, { uchar n; P5OUT&=0xdf;P5OUT|=0X20;delay(4);_NOP();_NOP();_NOP();//發送起始位,設置波特率 for(n=1;n<=8;n++) //8個數據位,發8次 { if((m&0x01)==0){P5OUT&=0Xdf;P5OUT|=0X20;delay(4);_NOP();} //先發最低位(即最右邊那位) else {P5OUT|=0X20;delay(6);} m=m>>0x01; //將要發送的數據右移一位 } P5OUT|=0x20; //發送停止位 delay(7);_NOP();_NOP();_NOP();_NOP();//延時1個停止位 }
//************************************************************************ void shuzusend(const uchar *c) //使用指針調用數組 { uchar i,*p; //i為數組元素個數 p=(uchar *)c; //指針類型轉換 keybuf=0x00; //清零 for(i=1;i<=6;i++) //數組有6個元素,發送6次 { zijiesend(*p); //發送數組元素 p++; //移到下一個元素 delay_us(500); //發送完一個字節等待500微秒 } delay_ms(10); //發送完一個數組等待10毫秒 }
//************************************************************************ main() //連續去抖動,按鍵機械扛抖動能力很差,加入了組合鍵(注意組合鍵識別的有效時鍵) { WDTCTL=WDTPW+WDTHOLD;//關看門狗 P2DIR|=0X04; P2OUT|=0X04; //在P2.2口輸出高電位,開啟紅外部分電源 keyinit(); //按鍵初始化 timerainit(); //定時器初始化 P5DIR|=0X20; //設置P5.5為輸出端 delay_ms(150); //進入循環前延時,等待低速時鐘穩定 _EINT(); //開總中斷 while(1) { switch(keybuf) //使用keybuf作為判斷標志 { case 0x00 : break; case 1 : shuzusend(a); break; case 2 : shuzusend(b); break; case 3 : shuzusend(c); break; case 4 : shuzusend(d); break; case 5 : shuzusend(e); break; case 6 : shuzusend(f); break; case 7 : shuzusend(g); break; case 8 : shuzusend(h); break; case 9 : shuzusend(i); break; //4、6組合鍵 default : break; } } }
//定時器延時時間常數本來可以設得比較小的,但設置得小的時候,由于抖動厲害,會發兩次數據;若是需要修改連鍵識別時間間隔,直接更改"keytime"的值就可以了 //低速時鐘需要上百毫秒的建立時間才能穩定下來。
2、紅外接收數組,并將接收到的數組以19200b/S的速率,經485發送PC串口,并在串口調試助手上顯示出來:
#include<msp430x417.h> #include"delay.c" #define uchar unsigned char #define uint unsigned int
//在IAR EW430 編譯器軟件中如何實現高精度軟件延時,利用IAR EW430 內部延時子程序即
可方便地實現 #define CPU_F ((double)1048576) //這里是你當前MSP430 CPU的主頻
頻率,即CPU的MCLK,單位為HZ #define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) #define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) //************************************************************************
uchar a[6]={0}; //定義數組a來存放紅外接收到的數據,并初始化為0,
uchar zijiereceive()//用關系統總中斷,查詢中斷標志的方案實現 { uchar s,t=0x00; for(;;) //沒有字節發送則一直等待 if((P2IFG&0X01)==0X01) { P2IFG&=0XFE; //先將中斷標志清零 break; }
delay(10); //從檢測到起始位(下降沿)到第一個采樣點的延時 if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else {s=0x01;P2IFG&=0XFE;} t+=s; delay(7); if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else {s=0x01;P2IFG&=0XFE;} s<<=1; t+=s; delay(7); if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else{s=0x01;P2IFG&=0XFE;} s<<=2; t+=s; delay(4); if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else {s=0x01;P2IFG&=0XFE;} s<<=3; t+=s; delay(4); if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else {s=0x01;P2IFG&=0XFE;} s<<=4; t+=s; delay(3); if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else {s=0x01;P2IFG&=0XFE;} s<<=5; t+=s; delay(3); if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else {s=0x01;P2IFG&=0XFE;} s<<=6; t+=s; delay(6); if((P2IFG&0X01)==0X01){s=0x00;P2IFG&=0XFE;} else {s=0x01;P2IFG&=0XFE;} s<<=7; t+=s; return(t); }
//************************************************************************ void shuzureceive( uchar *a) //使用指針完成一個數組的接收,并將他們按順序存入
已定義的數組。 { uchar i,*p; //定義循環常數和指針變量 p=a; //將數組首地址賦給指針p P2IES|=0X01; //P2.0設為下降沿中斷觸發 P2IFG&=0XFE; //將中斷標志清零,初始化 for(i=1;i<=6;i++) { *p=zijiereceive(); //存入一個字節 p++; //更新存儲單元 } }
//************************************************************************ void transmit(uchar m) //485以19200bit/S發送一個字節, { uchar n; P5OUT&=0xdf; //發送起始位 delay(6); //設置波特率 for(n=1;n<=8;n++) //8個數據位,發8次 { if((m&0x01)==0)P5OUT&=0Xdf;//先發最低位(即最右邊那位) else P5OUT|=0X20; delay(6); m=m>>0x01; //將要發送的數據右移一位 } P5OUT|=0x20; //發送停止位 delay(8);_NOP(); //延時1個停止位 }
//************************************************************************ void send( uchar *c) //使用指針調用數組,485發送一個數組 { uchar i,*p; //i為數組元素個數 p=c; //指針類型轉換 for(i=1;i<=6;i++) //數組有6個元素,發送6次 { transmit(*p); //發送數組元素 p++; //移到下一個元素 } }
//************************************************************************ main() { WDTCTL=WDTPW+WDTHOLD;//關看門狗 _DINT();//關總中斷
P2DIR|=0X04; P2OUT|=0X04; //輸出高電平,開啟紅外部分電源,這也是用的P2口 P5DIR|=0X20; //設置P5.5為輸出端 delay_ms(20); // 等待低速時鐘穩定
while(1) { shuzureceive(a); //紅外接收一個數組 send(a); //485發送接到的數據 }
} //不允許中斷,但中斷標志仍然存在,須用軟件清零
實驗結果(串口助手上顯示的數據): 00 66 83 38 00 FC 84 00 66 83 18 00 E5 44 66 83 18 00 E5 44 66 83 18 00 E5 44 66 83 18 00 E5 44 00 66 83 18 00 E5 44 66 83 18 00 E5 44 66 83 18 00 E5 44 00 66 83 38 00 FC 84 66 83 38 00 FC 84 00 66 83 30 00 FB 44 66 83 30 00 FB 44 00 00 00 00 00 66 83 08 00 E8 84 66 83 08 00 E8 84 66 83 08 00 E8 84 66 83 08 00 E8 84 00 66 83 20 00 F6 84 66 83 20 00 F6 84 66 83 20 00 F6 84 66 83 20 00 F6 84
|