单片机C语言应用程序设计3.1MCS-51机间通信的C语言编程3.2键盘和数码显示人机交互的C语言编程三C51应用编程设计单片机C语言应用程序设计3.1MCS-51机间通信的C语言编程3.1.1点对点的串行异步通信1.通信双方的硬件连接图3.18031间RS—232C电平信号的传单片机C语言应用程序设计2.通信双方的约定图3.2点对点通信的程序框图单片机C语言应用程序设计3.点对点通信编程点对点通信双方基本等同,只是人为规定一个为发送,一个为接收。要求两机串行口的波特率相同,因而发送和接收方串行口的初始化相同。可编制含有初始化函数、发送函数接收函数的程序,在主函数中根据程序的发送、接收设置TR,采用条件判别决定使用发送函数还是接收函数。这样点对点通信的双方都可运行此程序,只需在程序运行之前人为设置选择TR,一个令TR=0,一个令TR=1,然后分别编译,在两机上分别装入,同时运行。单片机C语言应用程序设计例1点对点通信。点对点通信的程序如下:#includereg51.h#defineucharunsignedchar#defineTR1/*发送接收差别值TR=0发送*/ucharidatabuf[10];ucharpf;voidinit(void)/*串行口初始化*/{TMOD=0x20;/*设T/C1为定时方式2*/TH1=0xe8;/*设定波特率*/单片机C语言应用程序设计TL1=0xe8;PCON=0x00;TR1=1;/*启动T/C1*/SCON=0x50;/*串行口工作在方式1*/}voidsend(ucharidata*d){uchari;do{SBUF=0xaa;/*发送联络信号*/while(TI==0);/*等待发送出去*/TI=0;单片机C语言应用程序设计while(RI==0);/*等待B机回答*/RI=0;}while((SBUF^0xbb)!=0);/*B机未准备好,继续联络*/do{pf=0;/*清校验和*/for(i=0;i16;i++){SBUF=d[i];/*发送一个数据*/pf+=d[i];/*求校验和*/while(TI==0);TI=0;}SBUF=pf;/*发送校验和*/单片机C语言应用程序设计while(TI==0);TI=0;while(RI==0);RI=0;/*等待B机回答*/}while(SBUF!=0);/*回答出错,则重发*/}voidreceive(ucharidata*d){uchari;do{while(RI==0);RI=0;}while((SBUF^0xaa)!=0);/*判A机请求否*/SBUF=0xbb;/*发应答信号*/单片机C语言应用程序设计while(TI==0);TI=0;while(1){pf=0;/*清校验和*/for(i=0;i16;i++){while(RI==0);RI=0;d[i]=SBUF;/*接收一个数据*/pf+=d[i];/*求校验和*/}while(RI==0);RI=0;/*接收A机校验和*/if((SBUF^pf)==0)/*比较校验和*/{SBUF=0x00;break;}/*校验和相同发00*/else{SBUF=0xff;/*出错发FF,重新接收*/单片机C语言应用程序设计while(TI==0);TI=0;}}}voidmain(void){init();if(TR==0){send(buf);}else{receive(buf);}}单片机C语言应用程序设计3.1.2多机通信1.通信接口图3.3总线式主从式多机系统单片机C语言应用程序设计2.通信协议根据MCS-51串行口的多机通信能力,多机通信可以按照以下协议进行:(1)首先使所有从机的SM2位置1处于只接收地址帧的状态。(2)主机先发送一帧地址信息,其中8位地址,第9位为地址/数据信息的标志位,该位置1表示该帧为地址信息。(3)从机接收到地址帧后,各自将接收的地址与本机的地址比较。对于地址相符的那个从机,使SM2位清零,以接收主机随后发来的所有信息;对于地址不符的从机,仍保持SM2=1,对主机随后发来的数据不予理睬,直至发送新的地址帧。单片机C语言应用程序设计(4)当从机发送数据结束后,发送一帧校验和,并置第9位(TB8)为1,作为从机数据传送结束标志。(5)主机接收数据时先判断数据结束标志(RB8),若RB8=1,表示数据传送结束,并比较此帧校验和,若正确,则会送正确信号00H,此信号令该从机复位(即重新等待地址帧);若校验和出错,则发送0FFH,令该从机重发数据。若接收帧的RB8=0,则原数据到缓冲区,并准备接收下帧信息。(6)若主机向从机发送数据,从机在第(3)步中比较地址相符后,从机令SM2=0,同时把本站地址发回主机。作为应答之后才能收到主机发送来的数据。其它从机(SM2=1),无法收到数据。单片机C语言应用程序设计(7)主机收到从机的应答地址后,确认地址是否相符。如果地址不符,发复位信号(数据帧中TB8=1);如果地址相符,则清TB8,开始发送数据。(8)从机接收到复位命令后回到监听地址状态(SM2=1)。否则开始接收数据和命令。单片机C语言应用程序设计3.通信程序设主机发送的地址联络信号00H,01H,02H为从机设备地址,地址FFH是命令各从机恢复SM2为1的状态,即复位。主机的命令编码为:01H请求从机接收主机的数据命令;02H请求从机向主机发送数据命令。其它都按从机向主机发送数据命令02H对待。单片机C语言应用程序设计从机的状态字节格式为:ERR00000TRDYRRDYD7D6D5D4D3D2D1D0RRDY=1:从机准备好接收主机的数据。TRDY=1:从机准备好向主机发送数据。ERR=1:从机接收到的命令是非法的。通常从机以中断方式控制和主机的通信。程序可分成主机程序和从机程序,约定一次传送的数据为16个字节,以02H地址的从机为例。单片机C语言应用程序设计1)主机程序图3.4多机通信主机程序流程图单片机C语言应用程序设计主机程序如下:#includereg51.h#defineucharunsignedchar#defineSLAVE0x02/*从机地址*/#defineBN16ucharidatarbuf[16];ucharidatatbuf[16]={mastertransmit};voiderr(void){SBUF=0xff;while(TI!=1);TI=0;}单片机C语言应用程序设计ucharmaster(charaddr,ucharcommand){ucharaa,i,p;while(1){SBUF=SLAVE;/*发呼叫地址*/while(TI!=1);TI=0;while(RI!=1);RI=0;/*等待从机回答*/if(SBUF!=addr)err()/*若地址错,发复位信号*/else{/*地址相符*/TB8=0;/*清地址标志*/SBUF=command;/*发命令*/while(TI!=1);TI=0;while(RI!=1);RI=0;单片机C语言应用程序设计aa=SBUF;/*接收状态*/if((aa&0x08)==0x08){TB8=1;err();}/*若命令未被接收,发复位信号*/else{if(command==0x01)/*是发送命令*/{if((aa&0x01)==0x01)/*从机准备好接收*/{do{p=0;/*清校验和*/for(i=0;iBN;i++){SBUF=tbuf[i];/*发送一数据*/p+=tbuf[i];/*校验和相加;*/单片机C语言应用程序设计while(TI!=1);TI=0;}SBUF=p;/*发送校验和*/while(TI==0);TI=0;while(RI==0);RI=0;}while(SBUF!=0);/*接收不正确,重新发送*/TB8=1;/*置地址标志*/return(0)}}else{if((aa&0x02)==0x02)/*是接收命令,从机准备好发送*/单片机C语言应用程序设计{while(1){p=0;/*清校验和*/for(i=0;iBN;i++){while(RI!=1);RI=0;rbuf[i]=SBUF;/*接收一数据*/P+=rubf[i];}while(RI==0);RI=0;if(SBUF==p){SBUF=0X00;/*校验和相同发00*/while(TI==0);TI=0;break;}单片机C语言应用程序设计else{SBUF=0xff;/*校验和不同发0FF,重新接收*/while(TI==0);TI=0;}}TB8=1;/*置地址标志*/Retuen(0);}}}}}}单片机C语言应用程序设计voidmain(viod){TMOD=0x20;/*T/C1定义为方式2*/TL1=0xfd;TH1=0xfd;/*置初值*/PCON=0x00;TR1=1;SCON=0xf0;/*串行口为方式3*/master(SLAVE,0x01);master(SLAVE,0x02);}单片机C语言应用程序设计2)从机程序图3.5多机通信的从机中断程序流单片机C语言应用程序设计从机程序如下:#includereg51.h#defineucharunsignedchar#defineSLAVE0x02#defineBN16ucharidatatrbuf[16];ucharidatarebuf[16];bittready;bitrready;voidmain(void){单片机C语言应用程序设计TMOD=0x20;/*T/C1定义为方式2*/TL1=0xfd;/*置初值*/TH1=0xfd;PCON=0x00;TR1=1;SCON=0xf0;/*串行口为方式3*/ES=1;EA=1;/*开串行口中断*/while(1){tready=1;rready=1;}/*假定准备好发送和接收*/}单片机C语言应用程序设计voidssio(void)interrupt4using1{voidstr(void);voidsre(void);uchara,i;RI=0;ES=0;/*关串行口中断*/if(SBUF!=SLAVE){ES=1;gotoreti;}/*非本机地址,继续监听*/SM2=0;/*取消监听状态*/SBUF=SLAVE;/*从本地址发回*/单片机C语言应用程序设计while(TI!=1);TI=0;while(RI!=1);RI=0;if(RB8==1){SM2=1;ES=1;gotoreti;}/*是复位信号,恢复监听*/a=SBUF;/*接收命令*/if(a=0x01)/*从主机接收的数据*/{if(rready==1)SBUF=0x01;/*接收准备好发状态*/elseSBUF=0x00;while(TI!=1);TI=0;while(RI!=1);RI=0;if(RB8==1){SM2=1;ES=1;gotoreti;}sre();/*接收数据*/}单片机C语言应用程序设计else{if(a=0x02)/*从机向主机发送数据*/{if(tready==1)SBUF=0x02;/*发送准备好发状态*/elseSBUF=0x00;while(TI!=1);TI=0;while(RI!=1);RI=0;if(RB8==1){SM2=1;ES=1;gotoreti;}str();/*发送数据*/}单片机C语言应用程序设计else{SBUF=0x80;/*命令非法,发状态*/while(TI!=1);TI=0;SM2=1;ES=1;/*恢复监听*/}}reti:;}voidstr(void)/*发数据块*/{ucharp,i;tready=0;do{p=0;/*清校验和*/单片机C语言应用程序设计for(i=0;iBN;i++){SBUF=trbuf[i];/*发送一数据*/p+=trbuf[i];while(TI!=1);TI=0;}SUBF=p;/*发送校验和*/while(TI==0);TI=0;wh