新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 51單片機(jī)串口程序,字符串/16進(jìn)制發(fā)送與接收

51單片機(jī)串口程序,字符串/16進(jìn)制發(fā)送與接收

作者: 時間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
這篇文章將說明51串口通信的發(fā)送與接收。分為:單個字符接收,字符串接收;十進(jìn)制發(fā)送與接收,十六進(jìn)制發(fā)送與接收。

字符串發(fā)送與十六進(jìn)制發(fā)送,參考:http://blog.csdn.net/yibu_refresh/article/details/22695063

本文引用地址:http://m.butianyuan.cn/article/201611/318162.htm

程序皆由PC串口工具發(fā)送,由單片機(jī)接收,并返回接收值給PC機(jī)。

一:單個字符的發(fā)送與接收

#include  #define uint unsigned int #define uchar unsigned char //定義接收 字符 uchar Buffer;  //串口初始化函數(shù) void   URATinit( ) {  TMOD=0x20;  SCON=0x50;  EA=1;  ES=1;  TR1=1;  TH1=0xfd;  TL1=0xfd; } //中斷函數(shù) void receive() interrupt 4 {  if(RI)  {    Buffer=SBUF;   RI=0;  }  SBUF=Buffer;  while(!TI);  TI=0; } //主函數(shù) void  main() {  URATinit( ); }
在中斷函數(shù)中,如果接收到數(shù)據(jù)則RI由硬件置1,這時候把SBUF緩沖區(qū)的數(shù)據(jù)賦值給Buffer,并將RI置0,等待下次接收。同時,將接收到的數(shù)據(jù)再放入緩沖區(qū),發(fā)送給PC機(jī)。當(dāng)發(fā)送完畢的時候TI會被硬件置1,這時候需要將TI置0,以待下次發(fā)送。

運(yùn)行效果:


發(fā)送數(shù)據(jù)1,則返回1。

二.字符串接收

(1)

#include  #define uint unsigned int #define uchar unsigned char //定義接收 數(shù)組 uchar Buffer[5]={0}; uchar i=0,j=0;  //串口初始化函數(shù) void   URATinit( ) {  TMOD=0x20;  SCON=0x50;  EA=1;  ES=1;  TR1=1;  TH1=0xfd;  TL1=0xfd; } //中斷函數(shù) void receive() interrupt 4 {  if(RI)  {    Buffer[i]=SBUF;   RI=0;  }  SBUF=Buffer[i];  while(!TI)	;  TI=0;  i++;  if(i>=5){  	i=0;  } } //主函數(shù) void  main() {  URATinit( ); }		 
在中斷函數(shù)當(dāng)中用Buffer[]接收收到的數(shù)據(jù),同時將Buffer[]再發(fā)送給上位機(jī)。這里要注意變量i的定義。如果定義為全局變量則Buffer[0-5]都可以接收到數(shù)據(jù),需要對i計數(shù),防止大于5溢出。

運(yùn)行效果:


(2)

#include  #define uint unsigned int #define uchar unsigned char //定義接收 數(shù)組 uchar Buffer[5]; uchar i=0,flag;  //延時函數(shù) delay(uint  ms) {  uchar i;  while(ms--)  for(i=0;i<123;i++); } //串口初始化函數(shù) void   URATinit( ) {  TMOD=0x20;  SCON=0x50;  EA=1;  ES=1;  TR1=1;  TH1=0xfd;  TL1=0xfd; } //中斷函數(shù) void receive() interrupt 4 {  if(RI)  {    Buffer[i++]=SBUF;   RI=0;	    if(i>=5){  	i=0;  	}   flag=1;  } } //主函數(shù) void  main() {  uchar k=0;  for(k;k<5;k++){  Buffer[k]=0;  }  URATinit( );  while(1){  if(flag) {  	uchar j=0;  	for(j;j<5;j++){  		SBUF=Buffer[j];  		while(!TI)	;  		TI=0; 		delay(50);  		}  	flag=0; 	} } }		  
這時不是從中斷函數(shù)中發(fā)送接收到的字符串,而是在主函數(shù)中發(fā)送接收到的字符串。于是需要flag標(biāo)志位來判斷是否接收到數(shù)據(jù),并且用while(1)循環(huán)來不斷判斷并輸出接收到的字符串。

運(yùn)行效果:


其實(shí)方法(1)優(yōu)于方法(2),現(xiàn)在來發(fā)送字符串"1234"與“123456”來看看效果:

發(fā)送“1234”(發(fā)送3次):



發(fā)送“123456”(發(fā)送3次):



可以看出(1)方法總是可以正確傳輸回并顯示所發(fā)送的字符串,而(2)方法則有一定的局限性,只有當(dāng)傳輸5個字符的字符串時才可以出現(xiàn)想要的顯示效果。

分析發(fā)現(xiàn):(1)中在中斷中直接發(fā)出收到的字符,接收一個發(fā)送一個,為實(shí)時效果。(2)則在主程序中整體發(fā)送接收到的Buffer數(shù)組,例如接收“1234”,當(dāng)“1234”發(fā)過來的時候由于Buffer為5位數(shù)組,因此第一次發(fā)送會給Buffer[0-3]賦值,Buffer[4]未賦值,返回給上位機(jī)第一次輸出為“1234”,但第二次發(fā)送時候會給Buffer[4]賦值,同時溢出把i歸為0。再次輸出Buffer時造成了傳輸字符串的重疊與混亂。其實(shí)(1)也有這個現(xiàn)象,只是(1)的返回為及時返回。

三. 字符串發(fā)送與十六進(jìn)制發(fā)送:

#include #define uchar unsigned char #define uint unsigned int uchar num;  sbit dula=P2^6;		//申明U1鎖存器的鎖存端 sbit wela=P2^7;		//申明U2鎖存器的鎖存端  uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71};  void delay(uint xms)				 { 	uint i,j; 	for(i=xms;i>0;i--)		      //i=xms即延時約xms毫秒 		for(j=110;j>0;j--); }  void display(uint value)  //顯示子函數(shù) { 	uchar wan,qian,bai,shi,ge;   //定義萬千百十個位 	wan=value/10000;                	qian=value%10000/1000; 	bai=value%1000/100;		 	shi=value%100/10; 	ge=value%10; 	 	dula=1; 	P0=table[wan];     	dula=0; 	P0=0xff;	 	wela=1;			 	P0=0xfe;		 	wela=0; 	delay(2);	   	 	dula=1; 	P0=table[qian]; 	dula=0; 	P0=0xff; 	wela=1; 	P0=0xfd; 	wela=0; 	delay(2); 	 	dula=1; 	P0=table[bai]; 	dula=0; 	P0=0xff; 	wela=1; 	P0=0xfb; 	wela=0; 	delay(2); 	 	dula=1; 	P0=table[shi]; 	dula=0; 	P0=0xff; 	wela=1; 	P0=0xf7; 	wela=0; 	delay(2);	 	 	dula=1; 	P0=table[ge]; 	dula=0; 	P0=0xff; 	wela=1; 	P0=0xef; 	wela=0; 	delay(2);	 }  void init()         //初始化函數(shù) { 	TMOD=0x20;      //設(shè)置定時器1工作方式 	TH1=0xfd; 	TL1=0xfd; 	TR1=1; 	SM0=0; 	SM1=1; 	REN=1; 	EA=1; 	ES=1; }  void main() {     init(); 	while(1) 	{ 	    display(num); 	} 		 }  void ser() interrupt 4     //串口中斷函數(shù) { 	if(RI){ 	   num=SBUF;                  RI=0; 	   }              //置RI為0以便接收下一個數(shù)據(jù) 	   SBUF=num; 	   while(!TI); 	   TI=0; }
這個程序可以在數(shù)碼管上顯示接收到的字符/數(shù)據(jù),同時將接收到的數(shù)據(jù)返回給上位機(jī)顯示。

先發(fā)送字符‘a’,即默認(rèn)的字符串發(fā)送方式:


發(fā)送字符‘a’,這時單片機(jī)返回給上位機(jī)的也為‘a’(默認(rèn)的字符串顯示方式)。但是數(shù)碼卻顯示97,為‘a’的ASCII碼。這說明在傳輸過程中,始終為ASCII碼傳輸。數(shù)碼管之所以沒顯示‘a’,因?yàn)閿?shù)碼管為十進(jìn)制顯示方式,故顯示97。(‘a’(ASCII顯示)——>97(十進(jìn)制顯示)——>a(ASCII碼顯示))

發(fā)送字符‘a’,選擇16進(jìn)制發(fā)送,16進(jìn)制顯示:


這時發(fā)送端為16進(jìn)制‘a’,即10進(jìn)制的10。數(shù)碼管顯示10,而返回的值用16制顯示為0A。

由文章開始的參考文章知道16進(jìn)制發(fā)送時每次發(fā)送兩位數(shù)據(jù),如:發(fā)送十進(jìn)制20,即16進(jìn)制的14,這時數(shù)碼管會顯示20。(14(16進(jìn)制顯示)——>20(10進(jìn)制顯示)——>14(16進(jìn)制顯示))。



評論


技術(shù)專區(qū)

關(guān)閉