找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12551|回复: 30
收起左侧

基于RS485主从结构通信单片机代码和proteus仿真

  [复制链接]
ID:206075 发表于 2017-5-30 15:31 | 显示全部楼层 |阅读模式
RS485主从结构通信代码,用于组网内部通信

proteus仿真原理图如下(proteus仿真工程文件可到本帖附件中下载):

0.png 0.png

单片机源程序如下:
  1. #ifndef        _485MON_H                                 // 防止485Mon.h被重复引用
  2. #define        _485MON_H

  3. #include <reg52.h>                            // 引用标准库的头文件
  4. #include <stdio.h>
  5. #include <string.h>

  6. #define uchar unsigned char
  7. #define uint unsigned int

  8. #define ACTIVE          0x11
  9. #define GETDATA          0x22
  10. #define READY                  0x33
  11. #define SENDDATA        0x44        

  12. #define RECFRMMAXLEN 16                 // 接收帧的最大长度,超过此值认为帧超长错误
  13. #define STATUSMAXLEN 10                        // 设备状态信息最大长度         

  14. uchar DevNo;                                        // 设备号
  15. xdata uchar StatusBuf[STATUSMAXLEN];

  16. //为简化起见,假设了10位固定的采集数据
  17. #define DATA0          0x10
  18. #define DATA1          0x20
  19. #define DATA2          0x30
  20. #define DATA3          0x40
  21. #define DATA4          0x50
  22. #define DATA5          0x60
  23. #define DATA6          0x70
  24. #define DATA7          0x80
  25. #define DATA8          0x90
  26. #define DATA9          0xA0
  27. sbit DE = P1^6;                        //驱动器使能,1有效
  28. sbit RE = P1^7;                        //接收器使能,0有效
  29. void init();                                        // 系统初始化
  30. void Get_Stat();                                // 简化的数据采集函数
  31. bit Recv_Data(uchar *type);                // 接收数据帧函数
  32. void Send(uchar m);                                        // 发送单字节数据
  33. void Send_Data(uchar type,uchar len,uchar *buf);                                // 发送数据帧函数        
  34. void Clr_StatusBuf();                        //  清除设备状态信息缓冲区函数   
  35. /****************************************/
  36. /* Copyright (c) 2005, 通信工程学院     */
  37. /* All rights reserved.                 */
  38. /****************************************/

  39. #include "485Mon.h"
  40. void main(void)
  41. {
  42.         uchar type;

  43.         /* 初始化 */
  44.         init();
  45.         
  46.         while (1)
  47.         {
  48.                 if (Recv_Data(&type)==0)                        // 接收帧错误或者地址不符合,丢弃
  49.                         continue;
  50.                 switch (type)
  51.                 {
  52.                         case ACTIVE:                                // 主机询问从机是否在位
  53.                                 Send_Data(READY,0,StatusBuf);        // 发送READY指令
  54.                                 break;
  55.                         case GETDATA:                                // 主机读设备请求
  56.                                 Clr_StatusBuf();
  57.                                 Get_Stat();                                // 数据采集函数
  58.                                 Send_Data(SENDDATA,strlen(StatusBuf),StatusBuf);
  59.                                 break;
  60.                         default:
  61.                                 break;                                        // 指令类型错误,丢弃当前帧
  62.                 }
  63.         }
  64. }

  65. /* 初始化 */
  66. void init(void)
  67. {
  68.         P1 = 0xff;
  69.         DevNo = (P1&0x00111111);                        // 读取本机设备号

  70.         TMOD = 0x20;
  71.         SCON = 0x50;
  72.         TH1 = 0xfd;
  73.         TL1 = 0xfd;
  74.         TR1 = 1;
  75.         PCON = 0x00;                                                // SMOD=0
  76.         EA = 0;
  77.                                                 
  78. }

  79. /* 接收数据帧函数,实际上接收的是主机的指令 */
  80. bit Recv_Data(uchar *type)
  81. {
  82.         uchar tmp,rCount,i;
  83.         uchar r_buf[RECFRMMAXLEN];                        // 保存接收到的帧
  84.         uchar Flag_RecvOver;                                // 一帧接收结束标志        
  85.         uchar Flag_StartRec;                                // 一帧开始接收标志
  86.         uchar CheckSum;                                                // 校验和
  87.         uchar DataLen;                                                // 数据字节长度变量
  88.                
  89.         /* 禁止发送,允许接收 */
  90.         DE = 0;
  91.         RE = 0;

  92.         /* 接收一帧数据 */
  93.         rCount = 0;
  94.         Flag_StartRec = 0;
  95.     Flag_RecvOver = 0;
  96.         while (!Flag_RecvOver)
  97.         {
  98.                 RI = 0;
  99.                 while (!RI);
  100.                 tmp = SBUF;
  101.                 RI=0;

  102.                 /* 判断是否收到字符',其数值为0x24 */         
  103.                 if ((!Flag_StartRec) && (tmp == 0x24))
  104.                 {
  105.                         Flag_StartRec = 1;        
  106.                 }

  107.                 if (Flag_StartRec)
  108.                 {
  109.                         r_buf[rCount] = tmp;
  110.                         rCount ++;               
  111.                         
  112.                         /* 判断是否收到字符'*',其数值为0x2A,根据接收的指令设置相应标志位 */
  113.                         if (tmp == 0x2A)
  114.                                 Flag_RecvOver = 1;
  115.                 }

  116.                 if (rCount == RECFRMMAXLEN)                // 帧超长错误,返回0
  117.                         return 0;
  118.         }
  119.         
  120.         /* 计算校验和字节 */
  121.         CheckSum = 0;
  122.         DataLen = r_buf[3];
  123.         for (i=0;i++;i<3+DataLen)
  124.         {
  125.                 CheckSum = CheckSum + r_buf[i+1];
  126.         }
  127.         
  128.         /* 判断帧是否错误 */
  129.         if (rCount<6)                                                // 帧过短错误,返回0,最短的指令帧为6个字节                                                
  130.                 return 0;
  131.         if (r_buf[1]!=DevNo)                                  // 地址不符合,错误,返回0
  132.                 return 0;
  133.         if (r_buf[rCount-2]!=CheckSum)                // 校验错误,返回0
  134.             return 0;

  135.         *type = r_buf[2];                                        // 获取指令类型

  136.         return 1;                                                        // 成功,返回1
  137. }

  138. /* 发送数据帧函数 */
  139. void Send_Data(uchar type,uchar len,uchar *buf)
  140. {
  141.         uchar i,tmp;
  142.         uchar CheckSum = 0;
  143.         
  144.         /* 允许发送,禁止接收 */
  145.         DE = 1;
  146.         RE = 1;
  147.         
  148.         /* 发送帧起始字节 */
  149.         tmp = 0x24;
  150.         Send(tmp);
  151.         
  152.         Send(DevNo);                                                // 发送地址字节,也即设备号
  153.         CheckSum = CheckSum + DevNo;

  154.         Send(type);                                                        // 发送类型字节
  155.         CheckSum = CheckSum + type;

  156.         Send(len);                                                        // 发送数据长度字节
  157.         CheckSum = CheckSum + len;

  158.         /* 发送数据 */
  159.         for (i=0;i<len;i++)                        
  160.         {
  161.                 Send(*buf);
  162.                 CheckSum = CheckSum + *buf;
  163.                 buf++;
  164.         }
  165.         
  166.         Send(CheckSum);                                                // 发送校验和字节

  167.         /* 发送帧结束字节 */
  168.         tmp = 0x2A;
  169.         Send(tmp);
  170. }

  171. /* 采集数据函数经过简化处理,取固定的10个字节数据 */
  172. void Get_Stat(void)
  173. {
  174.         StatusBuf[0]=DATA0;
  175.         StatusBuf[1]=DATA1;
  176.         StatusBuf[2]=DATA2;
  177.         StatusBuf[3]=DATA3;
  178. ……………………

  179. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
RS485通信程序.rar (72.5 KB, 下载次数: 673)
回复

使用道具 举报

ID:72951 发表于 2017-10-25 08:25 | 显示全部楼层
谢谢楼主分享
回复

使用道具 举报

ID:96474 发表于 2017-11-7 13:07 | 显示全部楼层
谢谢楼主,正需要呢
回复

使用道具 举报

ID:284987 发表于 2018-2-23 15:27 | 显示全部楼层
谢谢楼主分享,借鉴下。
回复

使用道具 举报

ID:282795 发表于 2018-4-4 11:13 | 显示全部楼层
谢谢楼主。借鉴中。。。
回复

使用道具 举报

ID:47652 发表于 2018-4-9 10:33 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

ID:47652 发表于 2018-4-9 10:33 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

ID:308735 发表于 2018-4-16 09:26 | 显示全部楼层
这个是如何使用的?
回复

使用道具 举报

ID:365727 发表于 2018-7-5 20:05 | 显示全部楼层
谢谢楼主了哈~
回复

使用道具 举报

ID:301544 发表于 2018-7-5 21:50 | 显示全部楼层
缺少头文件啊,楼主
回复

使用道具 举报

ID:369814 发表于 2018-7-17 12:31 | 显示全部楼层
厉害厉害
回复

使用道具 举报

ID:66287 发表于 2018-7-20 10:08 | 显示全部楼层
好东东,谢谢分享!
回复

使用道具 举报

ID:196319 发表于 2018-9-29 10:00 | 显示全部楼层
正好项目用到,帮助很大
回复

使用道具 举报

ID:407357 发表于 2018-10-10 09:08 | 显示全部楼层
很受益,挺好,
回复

使用道具 举报

ID:407021 发表于 2018-10-10 10:46 | 显示全部楼层
谢谢楼主,学习中
回复

使用道具 举报

ID:407378 发表于 2018-10-10 10:46 | 显示全部楼层
谢谢楼主~~!
回复

使用道具 举报

ID:407378 发表于 2018-10-10 10:54 | 显示全部楼层
谢谢楼主分享,借鉴下。
回复

使用道具 举报

ID:409168 发表于 2018-11-9 16:21 | 显示全部楼层
正需要,谢谢楼主
回复

使用道具 举报

ID:224177 发表于 2018-12-18 22:37 | 显示全部楼层
楼主,请问下,这个是两个单片机之间进行通讯吗?想设计一块单片机走modbus协议和工控屏通讯,请问proteus中图应该怎么改进
回复

使用道具 举报

ID:350791 发表于 2019-1-14 14:19 | 显示全部楼层
楼主怎样实现的
回复

使用道具 举报

ID:151749 发表于 2019-1-28 00:48 | 显示全部楼层
好,谢谢提供!
回复

使用道具 举报

ID:507538 发表于 2019-4-9 08:55 | 显示全部楼层
谢谢提供
回复

使用道具 举报

ID:505762 发表于 2019-4-13 19:22 | 显示全部楼层
谢谢分享,感谢
回复

使用道具 举报

ID:563476 发表于 2019-6-16 10:54 | 显示全部楼层
怎么输入不了
回复

使用道具 举报

ID:563476 发表于 2019-6-16 10:55 | 显示全部楼层
tik8436 发表于 2017-11-7 13:07
谢谢楼主,正需要呢

怎么在软件上操作啊
回复

使用道具 举报

ID:155141 发表于 2020-2-2 14:18 | 显示全部楼层
厉害了。能够完美仿真485,传输字符串无压力。
有点可惜不能传输中文。
回复

使用道具 举报

ID:155141 发表于 2020-2-2 14:24 | 显示全部楼层
缺少的头文件不影响功能,厉害了,楼主
回复

使用道具 举报

ID:308785 发表于 2020-2-28 15:07 | 显示全部楼层
写写分享 我可以借鉴一下思想了
回复

使用道具 举报

ID:748018 发表于 2020-5-26 10:20 来自手机 | 显示全部楼层
谢谢楼主
回复

使用道具 举报

ID:122089 发表于 2020-8-15 10:58 | 显示全部楼层
有多从机的仿真吗?
回复

使用道具 举报

ID:903594 发表于 2021-4-14 21:43 | 显示全部楼层
怎么实现的呀,实验现象是什么

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表