基于RS485主从结构通信单片机代码
2020-08-21 来源:51hei
RS485主从结构通信代码,用于组网内部通信
单片机源程序如下:
#ifndef _485MON_H // 防止485Mon.h被重复引用
#define _485MON_H
#include #include #include #define uchar unsigned char #define uint unsigned int #define ACTIVE 0x11 #define GETDATA 0x22 #define READY 0x33 #define SENDDATA 0x44 #define RECFRMMAXLEN 16 // 接收帧的最大长度,超过此值认为帧超长错误 #define STATUSMAXLEN 10 // 设备状态信息最大长度 uchar DevNo; // 设备号 xdata uchar StatusBuf[STATUSMAXLEN]; //为简化起见,假设了10位固定的采集数据 #define DATA0 0x10 #define DATA1 0x20 #define DATA2 0x30 #define DATA3 0x40 #define DATA4 0x50 #define DATA5 0x60 #define DATA6 0x70 #define DATA7 0x80 #define DATA8 0x90 #define DATA9 0xA0 sbit DE = P1^6; //驱动器使能,1有效 sbit RE = P1^7; //接收器使能,0有效 void init(); // 系统初始化 void Get_Stat(); // 简化的数据采集函数 bit Recv_Data(uchar *type); // 接收数据帧函数 void Send(uchar m); // 发送单字节数据 void Send_Data(uchar type,uchar len,uchar *buf); // 发送数据帧函数 void Clr_StatusBuf(); // 清除设备状态信息缓冲区函数 /****************************************/ /* Copyright (c) 2005, 通信工程学院 */ /* All rights reserved. */ /****************************************/ #include '485Mon.h' void main(void) { uchar type; /* 初始化 */ init(); while (1) { if (Recv_Data(&type)==0) // 接收帧错误或者地址不符合,丢弃 continue; switch (type) { case ACTIVE: // 主机询问从机是否在位 Send_Data(READY,0,StatusBuf); // 发送READY指令 break; case GETDATA: // 主机读设备请求 Clr_StatusBuf(); Get_Stat(); // 数据采集函数 Send_Data(SENDDATA,strlen(StatusBuf),StatusBuf); break; default: break; // 指令类型错误,丢弃当前帧 } } } /* 初始化 */ void init(void) { P1 = 0xff; DevNo = (P1&0x00111111); // 读取本机设备号 TMOD = 0x20; SCON = 0x50; TH1 = 0xfd; TL1 = 0xfd; TR1 = 1; PCON = 0x00; // SMOD=0 EA = 0; } /* 接收数据帧函数,实际上接收的是主机的指令 */ bit Recv_Data(uchar *type) { uchar tmp,rCount,i; uchar r_buf[RECFRMMAXLEN]; // 保存接收到的帧 uchar Flag_RecvOver; // 一帧接收结束标志 uchar Flag_StartRec; // 一帧开始接收标志 uchar CheckSum; // 校验和 uchar DataLen; // 数据字节长度变量 /* 禁止发送,允许接收 */ DE = 0; RE = 0; /* 接收一帧数据 */ rCount = 0; Flag_StartRec = 0; Flag_RecvOver = 0; while (!Flag_RecvOver) { RI = 0; while (!RI); tmp = SBUF; RI=0; /* 判断是否收到字符',其数值为0x24 */ if ((!Flag_StartRec) && (tmp == 0x24)) { Flag_StartRec = 1; } if (Flag_StartRec) { r_buf[rCount] = tmp; rCount ++; /* 判断是否收到字符'*',其数值为0x2A,根据接收的指令设置相应标志位 */ if (tmp == 0x2A) Flag_RecvOver = 1; } if (rCount == RECFRMMAXLEN) // 帧超长错误,返回0 return 0; } /* 计算校验和字节 */ CheckSum = 0; DataLen = r_buf[3]; for (i=0;i++;i<3+DataLen) { CheckSum = CheckSum + r_buf[i+1]; } /* 判断帧是否错误 */ if (rCount<6) // 帧过短错误,返回0,最短的指令帧为6个字节 return 0; if (r_buf[1]!=DevNo) // 地址不符合,错误,返回0 return 0; if (r_buf[rCount-2]!=CheckSum) // 校验错误,返回0 return 0; *type = r_buf[2]; // 获取指令类型 return 1; // 成功,返回1 } /* 发送数据帧函数 */ void Send_Data(uchar type,uchar len,uchar *buf) { uchar i,tmp; uchar CheckSum = 0; /* 允许发送,禁止接收 */ DE = 1; RE = 1; /* 发送帧起始字节 */ tmp = 0x24; Send(tmp); Send(DevNo); // 发送地址字节,也即设备号 CheckSum = CheckSum + DevNo; Send(type); // 发送类型字节 CheckSum = CheckSum + type; Send(len); // 发送数据长度字节 CheckSum = CheckSum + len; /* 发送数据 */ for (i=0;i Send(*buf); CheckSum = CheckSum + *buf; buf++; } Send(CheckSum); // 发送校验和字节 /* 发送帧结束字节 */ tmp = 0x2A; Send(tmp); } /* 采集数据函数经过简化处理,取固定的10个字节数据 */ void Get_Stat(void) { StatusBuf[0]=DATA0; StatusBuf[1]=DATA1; StatusBuf[2]=DATA2; StatusBuf[3]=DATA3; ……………………