 |
這兩份程序本人花了好幾天才成功! 本程序適合於一個單片機不停地發數據,一個單片機不停地收。 1.兩片單片機使用同一個電源。 2.發送者的P2.6接接收者的P3.3口(外中斷1) 3.發送者的P2.7接接收者的P1.6口 4.接收方的P2口接共陽數碼管的位選,其中左邊第一個數碼管為P2.0,P0口接數碼管段選 5.兩個單片機都用11.0592M晶振。 我主要用在我的電子時鐘上。該電子時鐘時刻不停地往外發送時間和溫度信息,供其他單片機讀取利用。這兩個I/O口已 用排針引出。 實驗效果:接收方的數碼管上從17497300顯示到17497399 本方法不需要接收方對發送方進行任何I/O口操作就能收到數據,特別適合多個單片機接收一個單片機發出來的數據。
|
 |
//晶振:11.0592MHz //發數據 #include <AT89X52.h> sbit TSCLK=P2^6; sbit TSDAT=P2^7; //延遲n毫秒 void delay(unsigned int n) { while (n--) { TH2=0xfc; TL2=0x66; //11.0592MHz TF2=0; TR2=1; while (TF2==0); TF2=0; } } void superdelay(unsigned char h, unsigned char l) { TH2=h; TL2=l; TF2=0; TR2=1; while (TF2==0); TR2=0; } //延遲半毫秒 void delay500us() { superdelay(0xfe,0x33); }
void send_0() { //數據0:0.5ms低電平和0.5ms高電平 TSDAT=0; delay500us(); TSDAT=1; delay500us(); TSDAT=0; //把數據線拉低,免得程序卡在最後一個字節的高電平計時while循環里導致讀錯誤 } void send_1() { //數據1:0.5ms低電平和1.5ms高電平 TSDAT=0; delay500us(); TSDAT=1; delay500us(); delay500us(); delay500us(); TSDAT=0; } void sendbyte(unsigned char value) { unsigned char i; for (i=0;i<8;i++) { if (value&0x80) send_1(); else send_0(); value<<=1; //從高位發到低位 } } //數據輸出 unsigned char i=0; void output() { //發送引導碼 TSCLK=0; //時鐘線為低電平時表示正在發數據 TSDAT=0; //數據線1ms低電平和2.5ms高電平 delay(1); TSDAT=1; delay(2); delay500us(); //發送4個數字 sendbyte(17); sendbyte(49); sendbyte(73); sendbyte(i); //最後一個數字是不斷變化的 i+=1; if (i>99) i=0; TSCLK=1; //拉高時鐘線,表示發送數據完畢 TSDAT=1; //釋放數據線 delay(4); //使高電平保持一段時間 } void main() { T2MOD=0x01; //定時器2工作於16位查詢工作方式 TR2=0; while (1) { output(); delay(1000); } }
|
 |
//晶振:11.0592MHz //收數據 #include <AT89X52.h> sbit TSCLK=P3^3; sbit TSDAT=P1^6; sbit LED1=P2^0; sbit LED2=P2^1; sbit LED3=P2^2; sbit LED4=P2^3; sbit LED5=P2^4; sbit LED6=P2^5; sbit LED7=P2^6; sbit LED8=P2^7; sbit fmq=P3^6; //這是蜂鳴器 unsigned char num[4]={0,0,0,0}; unsigned char code DIS_SEG7[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; unsigned int lowtime,hightime; //延遲n毫秒 void delay(unsigned int n) { while (n--) { TH0=0xfc; TL0=0x66; //11.0592MHz TF0=0; TR0=1; while (TF0==0); TF0=0; } } void superdelay(unsigned char h, unsigned char l) { TH0=h; TL0=l; TF0=0; TR0=1; while (TF0==0); TR0=0; } //延遲半毫秒 void delay500us() { superdelay(0xfe,0x33); } //蜂鳴器 void beep() { unsigned char i; for (i=0;i<150;i++) { fmq=0; delay500us(); fmq=1; delay500us(); } } void receivebyte(unsigned char* Data) { unsigned char i; unsigned int time; for (i=0;i<8;i++) { *Data<<=1; //不應該在for循環的最後執行此操作,否則第一位會丟失 TH0=TL0=0; while (TSDAT==0); //跳過低電平 TR0=1; while (TSDAT==1 && TF0==0); //根據高電平長度判斷是0還是1 TR0=0; time=TH0*256+TL0; if (time>950) *Data|=0x01; //讀1 else *Data&=0xfe; //讀0 } } void Display() { P0=0xff; LED1=0; P0=DIS_SEG7[num[0]/10]; delay(1); LED1=1; P0=0xff; LED2=0; P0=DIS_SEG7[num[0]%10]; delay(1); LED2=1; P0=0xff; LED3=0; P0=DIS_SEG7[num[1]/10]; delay(1); LED3=1; P0=0xff; LED4=0; P0=DIS_SEG7[num[1]%10]; delay(1); LED4=1; P0=0xff; LED5=0; P0=DIS_SEG7[num[2]/10]; delay(1); LED5=1; P0=0xff; LED6=0; P0=DIS_SEG7[num[2]%10]; delay(1); LED6=1; P0=0xff; LED7=0; P0=DIS_SEG7[num[3]/10]; delay(1); LED7=1; P0=0xff; LED8=0; P0=DIS_SEG7[num[3]%10]; delay(1); LED8=1; } void main() { TMOD=0x01; //定時器2工作於16位查詢工作方式 TR0=0; EA=1; EX1=1; IT1=1; while (1) { P1_7=0; Display(); P1_7=1; } } void int1() interrupt 2 { EX1=0; //檢測引導碼 //數據線1ms低電平和2.5ms高電平 TH0=TL0=0; TR0=1; while (TSDAT==0); TR0=0; lowtime=TH0*256+TL0; TH0=TL0=0; TR0=1; while (TSDAT==1); TR0=0; hightime=TH0*256+TL0; //對於低電平:1000us/1.085=921,實際值通常為934 //對於高電平:2500/1.085=2304,實際值通常為2365或2367 if (lowtime>880 && lowtime<980 && hightime>2300 && hightime<2400) { receivebyte(&num[0]); receivebyte(&num[1]); receivebyte(&num[2]); receivebyte(&num[3]); delay500us(); //全部數據接收完畢後,等待時鐘線拉高,防止再次進入本中斷 } else beep(); //引導碼不合法 EX1=1; }
|
 |
接收方主函數裏的P1_7=0;可以去掉,是為了測試用的
|