找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3422|回复: 1
收起左侧

经典的51单片机rs485驱动程序

[复制链接]
ID:70481 发表于 2014-12-17 13:56 | 显示全部楼层 |阅读模式

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

  4. #define uchar unsigned char
  5. #define uint unsigned int

  6. #define ACTIVE          0x11
  7. #define GETDATA          0x22
  8. #define READY                  0x33
  9. #define SENDDATA        0x44       

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

  12. uchar DevNo;                                        // 设备号
  13. xdata uchar StatusBuf[STATUSMAXLEN];

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

  37. #include "485Mon.h"

  38. void main(void)
  39. {
  40.         uchar type;

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

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

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

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

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

  100.                 /* 判断是否收到字符'

  101. ,其数值为0x24 */         
  102.                 if ((!Flag_StartRec) && (tmp == 0x24))
  103.                 {
  104.                         Flag_StartRec = 1;       
  105.                 }

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

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

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

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

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

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

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

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

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

  170. /* 采集数据函数经过简化处理,取固定的10个字节数据 */
  171. void Get_Stat(void)
  172. {
  173.         StatusBuf[0]=DATA0;
  174.         StatusBuf[1]=DATA1;
  175.         StatusBuf[2]=DATA2;
  176.         StatusBuf[3]=DATA3;
  177.         StatusBuf[4]=DATA4;
  178.         StatusBuf[5]=DATA5;
  179.         StatusBuf[6]=DATA6;
  180.         StatusBuf[7]=DATA7;
  181.         StatusBuf[8]=DATA8;
  182.         StatusBuf[9]=DATA9;
  183. }

  184. /* 发送单字节数据 */
  185. void Send(uchar m)
  186. {
  187.         TI = 0;
  188.         SBUF = m;
  189.     while(!TI);
  190.         TI = 0;       
  191. }

  192. /* 清除设备状态信息缓冲区函数*/
  193. void Clr_StatusBuf(void)
  194. {
  195.         uchar i;
  196.         for (i=0;i<STATUSMAXLEN;i++)
  197.                 StatusBuf[ i] = 0;       
  198. }                       
复制代码


回复

使用道具 举报

ID:121374 发表于 2016-5-17 10:41 | 显示全部楼层
这是放在主机还是从机的程序
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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