51单片机多机通信程序(主机部分)/* multi_m.c *//* 多机通信的主机部分*/#ifndef __MULTI_M_C__#define __MULTI_M_C__#include <AT89X51.H>#include <STRING.H>#define __MAX_LEN_ 64 // 数据最大长度#define _MHZ_ 11 // 设置单片机使用的晶振频率(11.0592MHz)/* 以下为程序协议中使用的握手信号*/#define __SUCC_ 0x0f // 数据传送成功#define __ERR_ 0xf0 // 数据传送错误void init_serial(); // 串口初始化void send_data(unsigned char *buf); // 发送数据void delay10ms(unsigned int count); // 延时子程序(10ms)void main(){char buf[__MAX_LEN_];unsigned char i = 0;unsigned char tmp;unsigned char addr; // 该字节用于保存要通信的从机地址/* 为缓冲区赋初值*/P0 = 0xff;while(P1 != 0) // 每隔100ms从P0口读取,若读取到0则表明数据采集结束{*(buf+i) = P0;delay10ms(10); // 延时100msP0 = 0xff;i++;}*(buf+i) = 0; // 缓冲区最后一个字节为0表示数据结束/* 读要访问的分机地址*/P0 = 0xff;addr = P0;/* 串口初始化*/init_serial(); // 初始化串口EA = 0; // 关闭所有中断/* 发送地址帧并接收应答信息,如果接收的信号与发送的地址信息不同,则重新发送地址帧*/tmp = addr-1;while(tmp != addr){/* 发送从机地址*/TB8 = 1; // 发送地址帧SBUF = addr;while(!TI);TI = 0;/* 接收从机应答*/RI = 0;while(!RI);tmp = SBUF;RI = 0;}/* 发送数据并接收校验信息,如果接收的信号为0FH,表示从机接收成功,否则将重新发送该组数据*/tmp = __ERR_;while(tmp != __SUCC_){send_data(buf); // 发送数据RI = 0;while(!RI);tmp = SBUF;RI = 0;}while(1); // 程序结束,进入死循环}/* 初始化串口*/void init_serial(){TMOD = 0x20; //定时器T1使用工作方式2TH1 = 250; // 设置初值TL1 = 250;TR1 = 1; // 开始计时PCON = 0x80; // SMOD = 1SCON = 0xd0; //工作方式3,9位数据位,波特率9600bps,允许接收}/* 发送数据*/void send_data(unsigned char *buf){unsigned char len; // 保存数据长度unsigned char ecc; // 保存校验字节len = strlen(buf); // 计算要发送数据的长度ecc = len; // 开始进行校验字节计算/* 发送数据长度*/TB8 = 0; // 发送数据帧SBUF = len; // 发送长度while(!TI);TI = 0;/* 发送数据*/for(i=0; i<len; i++){ecc = ecc^(*buf); // 计算校验字节TB8 = 0; // 发送数据帧SBUF = *buf; // 发送数据buf++;while(!TI);TI = 0;}/* 发送校验字节*/TB8 = 0; // 发送数据帧SBUF = ecc; // 发送校验字节while(!TI);TI = 0;}/* 延时10ms,精度较低,参数count为延时时间*/void delay10ms(unsigned int count){unsigned int i, k;unsigned char j;unsigned int tmp;tmp = (int)((100*_MHZ_)/12);for(i=0; i<count; i++)for(j=0; j<100; j++)for(k=0; k<tmp; k++);}#endif51单片机多机通信程序(从机部分)/* multi_s.c *//* 多机通信的从机部分*/#ifndef __MULTI_S_C__#define __MULTI_S_C__#include <AT89X51.H>#include <STRING.H>#define __MAX_LEN_ 64 // 数据最大长度#define _MHZ_ 11 // 设置单片机使用的晶振频率(11.0592MHz)/* 以下为程序协议中使用的握手信号*/#define __SUCC_ 0x0f // 数据传送成功#define __ERR_ 0xf0 // 数据传送错误void init_serial(); // 串口初始化unsigned char recv_data(unsigned char *buf); // 接收数据void Beep_ok(); // 蜂鸣表示数据接收ok,该函数代码未给出void main(){char buf[__MAX_LEN_];unsigned char i = 0;unsigned char tmp = 0xff;unsigned char addr; // 保存本机地址/* 从P1口读取本机地址*/P1 = 0xff;addr = P1;/* 串口初始化*/init_serial(); // 初始化串口EA = 0; // 关闭所有中断/* 进入设备应答阶段*/while(1){SM2 = 1; // 只接收地址帧/* 如果接收到的地址帧不是本机地址,则继续等待*/tmp = addr-1;while(tmp != addr){RI = 0;while(!RI);tmp = SBUF;RI = 0;}/* 发送应答信号,并做好接收数据的准备*/TI = 0;TB8 = 0; // 主机不检测该位SBUF = addr;while(!TI);TI = 0;SM2 = 0; // 允许接收数据信息/* 数据接收*/tmp = 0xff;while(tmp == 0xff) // 如果数据校验失败则重新接收数据{tmp = recv_data(buf); // 校验失败返回0xff,检测到地址帧则返回0xfe,接收成功则返回0}if(tmp == 0xfe) // 在数据接收过程中,如果发现地址帧,则重新开始整个接收过程continue;Beep_ok(); // 蜂鸣表示数据接收成功}}/* 初始化串口*/void init_serial(){TMOD = 0x20; //定时器T1使用工作方式2TH1 = 250; // 设置初值TL1 = 250;TR1 = 1; // 开始计时PCON = 0x80; // SMOD = 1SCON = 0xd0; //工作方式3,9位数据位,波特率9600bps,允许接收}/* 接收数据,注意该函数使用buf指向的缓冲区保存数据,在数据末尾使用’\0’表示数据结束* 返回值为0,数据校验成功,返回值为0xfe,接受过程中接收到地址帧,返回值为0xff,数据校验失败*/unsigned char recv_data(unsigned char *buf){unsigned char len; // 该字节用于保存数据长度unsigned char ecc; // 该字节用于保存校验字节unsigned char i,tmp;/* 接收数据长度*/RI = 0;while(!RI);if(RB8 == 1) // 若当前接收为地址帧则返回0xfereturn 0xfe;len = SBUF;RI = 0;/* 使用len的值为校验字节ecc赋初值*/ecc = len;/* 接收数据*/for(i=0; i<len; i++){while(!RI);if(RB8 == 1) // 若当前接收为地址帧则返回0xfe return 0xfe;*buf = SBUF; // 接收数据ecc = ecc^(*buf); // 进行字节校验RI = 0;buf++;}*buf = 0; // 表示数据结束/* 接收校验字节*/while(!RI);if(RB8 == 1) // 若当前接收为地址帧则返回0xfe return 0xfe;tmp = SBUF;RI = 0;/* 进行数据校验*/ecc = tmp^ecc;if(ecc != 0) // 校验失败{*(buf-len) = 0; // 清空数据缓冲区TI = 0; // 发送校验失败信号TB8 = 0;SBUF = __ERR_;while(!TI);TI = 0;return 0xff; // 返回0xff表示校验错误}TI = 0; // 校验成功TB8 = 0;SBUF = __SUCC_;while(!TI);TI = 0;return 0; // 校验成功,返回0}#endif。