/*預處理命令*/
#include<reg52.h> //包含單片機寄存器的頭文件 #include<intrins.h> //包含_nop_()函數定義的頭文件 #define uchar unsigned char #define uint unsigned int #define delayNOP(); {_nop_();_nop_();_nop_();_nop_();}; sbit IRIN=P3^2; //紅外接收器數據線 sbit LCD_RS = P0^7; sbit LCD_RW = P0^6; sbit LCD_EN = P0^5; uchar begin[]={"My car!"}; uchar cdis1[]={"jiansu!"}; uchar cdis2[]={"qianjin!"}; uchar cdis3[]={"jiasu!"}; uchar cdis4[]={"zuozhuang!"}; uchar cdis5[]={"STOP!"}; uchar cdis6[]={"youzhuan!"}; uchar cdis8[]={"daoche!"}; sbit M1 = P1^0; sbit M2 = P1^1; sbit M3 = P1^2; sbit M4 = P1^3; sbit EN12 = P1^4; sbit EN34 = P1^5; uchar IRCOM[7]; uchar m,n; uchar t=2; uchar g; uchar code digit[]={"0123456789"}; uint v; uchar count; bit flag; void delayxms(uchar t); void delay(unsigned char x) ; void delay1(int ms); void motor(); void lcd_display(); /* 檢查LCD忙狀態 lcd_busy為1時,忙,等待。lcd-busy為0時,閑,可寫指令與數據 */ bit lcd_busy() { bit result; LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; delayNOP(); result = (bit)(P0&0x80); LCD_EN = 0; return(result); } /* 寫指令數據到LCD RS=L,RW=L,E=高脈沖,D0-D7=指令碼 */ void lcd_wcmd(uchar cmd) { while(lcd_busy()); LCD_RS = 0; LCD_RW = 0; LCD_EN = 0; _nop_(); _nop_(); P2 = cmd; delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0; } /* 寫顯示數據到LCD RS=H,RW=L,E=高脈沖,D0-D7=數據 */ void lcd_wdat(uchar dat) { while(lcd_busy()); LCD_RS = 1; LCD_RW = 0; LCD_EN = 0; P2 = dat; delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0; } /* LCD初始化設定 */ void lcd_init() { delay1(15); lcd_wcmd(0x38); //16*2顯示,5*7點陣,8位數據 delay1(5); lcd_wcmd(0x38); delay1(5); lcd_wcmd(0x38); delay1(5); lcd_wcmd(0x0c); //顯示開,關光標 delay1(5); lcd_wcmd(0x06); //移動光標 delay1(5); lcd_wcmd(0x01); //清除LCD的顯示內容 delay1(5); } /* 設定顯示位置 */ void lcd_pos(uchar pos) { lcd_wcmd(pos | 0x80); //數據指針=80+地址變量 } /*x顯示速度提示符*/ void display_sym(void) { lcd_pos(0x00); lcd_wdat('v'); lcd_wdat('='); } /*顯示速度數值*/ void display_vel(uint x) { uchar i,j,k,l; i=x/1000; //取千位 j=(x%1000)/100; //取百位 k=(x%100)/10; //取十位 l=x%10; //取個位 lcd_pos(0x02); lcd_wdat(digit); lcd_wdat(digit[j]); lcd_wdat(digit[k]); lcd_wdat(digit[l]); } /*顯示速度單位*/ void display_unit(void) { lcd_pos(0x06); lcd_wdat('r'); lcd_wdat('/'); lcd_wdat('m'); lcd_wdat('i'); lcd_wdat('n'); } /* 主函數 */ /*******************************************************************/ void main() { uint a; IRIN=1; //I/O口初始化 IE=0x83; //允許總中斷中斷,使能 INT0 外部中斷 TCON=TCON|0x01; //觸發方式為脈沖負邊沿觸發 lcd_init(); TMOD=0x51; TH0=(65536-50000)/256; TL0=(65536-50000)/256; TR0=1; count=0; display_sym(); display_vel(0); display_unit(); lcd_pos(0x40); g=0; while(begin[g]!='\0') { lcd_wdat(begin[g]); g++; } while(1) { TR1=1; TH1=0; TL1=0; flag=0; display_sym(); display_unit(); while(flag==0); v=(TH1*256+TL1)*60/20; display_vel(v); motor(); } } /**********************************************************/ void IR_IN() interrupt 0 using 0 { unsigned char j,k,N=0; unsigned char q=0; EX0 = 0; delay(15); if (IRIN==1) { EX0 =1; return; } //確認IR信號出現 while (!IRIN) //等IR變為高電平,跳過9ms的前導低電平信號。 delay(1); for (j=0;j<4;j++) //收集四組數據 { for (k=0;k<8;k++) //每組數據有8位 { while (IRIN) //等 IR 變為低電平,跳過4.5ms的前導高電平信號。 {delay(1);} while (!IRIN) //等 IR 變為高電平 delay(1); while (IRIN) //計算IR高電平時長 { delay(1); N++; if (N>=30) { EX0=1; return; } //0.14ms計數過長自動離開。 } //高電平計數完畢 IRCOM[j]=IRCOM[j] >> 1; //數據最高位補“0” if(N>=8) { IRCOM[j] = IRCOM[j] | 0x80; //數據最高位補“1” } N=0; } } if(IRCOM[2]!=~IRCOM[3]) { EX0=1; return; } IRCOM[5]=IRCOM[2] & 0x0F; //取鍵碼的低四位 IRCOM[6]=IRCOM[2] >> 4; //右移4次,高四位變為低四位 if(IRCOM[5]>9) { IRCOM[5]=IRCOM[5]+0x37; } else IRCOM[5]=IRCOM[5]+0x30; if(IRCOM[6]>9) { IRCOM[6]=IRCOM[6]+0x37; } else IRCOM[6]=IRCOM[6]+0x30; q= (((IRCOM[6]&0x0f)<<4) + (IRCOM[5]&0x0f)); switch(q) //判斷按鍵鍵碼值 { case 0x16:m=0;break; //串口發送0 case 0x03:m=1;t++;if(t>=5)t=4;break; //串口發送01 case 0x18:m=2;n=2;break; //串口發送02 case 0x55:m=3;t--;if(t<=0)t=0;break; //串口發送03 case 0x08:m=4;n=4;break; //串口發送04 case 0x13:m=5;n=5;break; //串口發送05 case 0x51:m=6;n=6;break; //串口發送06 case 0x42:m=7;break; //串口發送07 case 0x52:m=8;n=8;break; //串口發送08 case 0x41:m=9;break; //串口發送09 default :break; } lcd_display(); EX0 = 1; } /***************延時函數*****************************/ void delay(unsigned char x) //x*0.14MS { unsigned char i; while(x--) { for (i = 0; i<13; i++) {} } } void lcd_display() { g=0; switch( m) { case 1: lcd_init(); lcd_pos(0x40); while(cdis1[g]!='\0') //減速 { lcd_wdat(cdis1[g]); g++; }break; case 2: lcd_init(); lcd_pos(0x40); //前進 while(cdis2[g]!='\0') { lcd_wdat(cdis2[g]); g++; }break; case 3: lcd_init(); lcd_pos(0x40); //加速 while(cdis3[g]!='\0') { lcd_wdat(cdis3[g]); g++; }break; case 4: lcd_init(); lcd_pos(0x40); //左轉 while(cdis4[g]!='\0') { lcd_wdat(cdis4[g]); g++; }break; case 5: lcd_init(); lcd_pos(0x40); //停車 while(cdis5[g]!='\0') { lcd_wdat(cdis5[g]); g++; }break; case 6: lcd_init(); lcd_pos(0x40); //右轉 while(cdis6[g]!='\0') { lcd_wdat(cdis6[g]); g++; } break; case 8: lcd_init(); lcd_pos(0x40); //倒車 while(cdis8[g]!='\0') { lcd_wdat(cdis8[g]); g++; }break; default :break; }} void motor() { EN12=1; EN34=1; switch( n) { case 2: //前進 M1=1; M2=0; M3=1; M4=0; /* delayxms(5-t); M1=0; M3=0; elayxms(t); */ break; case 4: //左轉 M1=0; M2=0; M3=1; M4=0; /*delayxms(5-t); M1=0; M3=0; layxms(t+1); */ break; case 6: //右轉 M1=1; M2=0; M3=0; M4=0; /*delayxms(5-t); M1=0; M3=0; layxms(t+1); */ break; case 8: //后退 M1=0; M2=1; M3=0; M4=1; /*delayxms(5-t); M2=0; M4=0; layxms(t); */ break; case 5: EN12=0; EN34=0; break; default :break; } } /******************************************************* 函數功能:定時器T0的中斷服務函數 ********************************************************/ void Time0(void ) interrupt 1 using 1 //定時器T0的中斷編號為1,使用第1組工作寄存器 { count++; //T0每中斷1次,count加1 if(count==20) //若累計滿20次,即計滿1秒鐘 { flag=1; //計滿1秒鐘標志位置1 count=0; //清0,重新統計中斷次數 } TH0=(65536-46083)/256; //定時器T0高8位重新賦初值 TL0=(65536-46083)%256; //定時器T0低8位重新賦初值 } void delay1(int ms) { unsigned char y; while(ms--) { for(y = 0; y<250; y++) { _nop_(); _nop_(); _nop_(); _nop_(); } } } //************************************************************ void delayxms(uchar t) { uint i; uchar j; for(j=t;j>0;j--) for(i=80;i>0;i--); //延時124*8+10=1002us }
|