找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 975|回复: 0
打印 上一主题 下一主题
收起左侧

单片机RS485程序

[复制链接]
跳转到指定楼层
楼主
ID:735148 发表于 2020-4-23 10:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

  1. #ifndef __485_C__
  2. #define __485_C__
  3. #include <reg51.h>
  4. #include <string.h>
  5. #define unsigned char uchar
  6. #define unsigned int uint
  7. /*
  8. 通信命令
  9. */
  10. #define __ACTIVE_ 0x01    //
  11. 主机询问从机是否存在
  12. #define __GETDATA_ 0x02    //
  13. 主机发送读设备请求
  14. #define __OK_ 0x03    //
  15. 从机应答
  16. #define __STATUS_ 0x04    //
  17. 从机发送设备状态信息
  18. #define __MAXSIZE 0x08    //
  19. 缓冲区长度
  20. #define __ERRLEN 12    //
  21. 任何通信帧长度超过
  22. 12
  23. 则表示出错
  24. uchar dbuf[__MAXSIZE];    //
  25. 该缓冲区用于保存设备状态信息
  26. uchar dev;    //
  27. 该字节用于保存本机设备号
  28. sbit M_DE = P1^0;    //
  29. 驱动器使能,
  30. 1
  31. 有效
  32. sbit M_RE = P1^1;    //
  33. 接收器使能,
  34. 0
  35. 有效
  36. void get_status();    //
  37. 调用该函数获得设备状态信息,函数代码未给出
  38. void send_data(uchar type, uchar len, uchar *buf);    //
  39. 发送数据帧
  40. bit recv_cmd(uchar *type);    //
  41. 接收主机命令,主机请求仅包含命令信息
  42. void send_byte(uchar da);    //
  43. 该函数发送一帧数据中的一个字节,

  44. send_data()

  45. 数调用
  46. void main()
  47. {
  48. uchar type;
  49. uchar len;
  50. /*
  51. 系统初始化
  52. */
  53. P1 = 0xff;    //
  54. 读取本机设备号
  55. dev = (P1>>2);
  56. TMOD = 0x20; //
  57. 定时器
  58. T1
  59. 使用工作方式
  60. 2
  61. TH1 = 250;    //
  62. 设置初值
  63. TL1 = 250;
  64. TR1 = 1;    //
  65. 开始计时
  66. PCON = 0x80;    // SMOD = 1
  67. SCON = 0x50; //
  68. 工作方式
  69. 1
  70. ,波特率
  71. 9600bps
  72. ,允许接收
  73. ES = 0;    //
  74. 关闭串口中断
  75. IT0 = 0;    //
  76. 外部中断
  77. 0
  78. 使用电平触发模式
  79. EX0 = 1;    //
  80. 开启外部中断
  81. 0
  82. EA = 1;    //
  83. 开启中断
  84. /*
  85. 主程序流程
  86. */
  87. while(1)    //
  88. 主循环
  89. {
  90.    if(recv_cmd(&type) == 0)    //
  91. 发生帧错误或帧地址与本机地址不符,
  92. 丢弃当前帧后
  93. 返回
  94.     continue;
  95.    switch(type)
  96.    {
  97.     case __ACTIVE_:    //
  98. 主机询问从机是否存在
  99.      send_data(__OK_, 0, dbuf);    //
  100. 发送应答信息,这里
  101. buf
  102. 的内容并未用到
  103.      break;
  104.     case __GETDATA_:
  105.      len = strlen(dbuf);
  106.      send_data(__STATUS_, len, dbuf);    //
  107. 发送设备状态信息
  108.      break;
  109.     default:
  110.      break;    //
  111. 命令类型错误,丢弃当前帧后返回
  112.    }
  113. }
  114. }
  115. void READSTATUS() interrupt 0 using 1    //
  116. 产生外部中断
  117. 0
  118. 时表示设备状态发生改
  119. 变,该函数使用寄存器组
  120. 1
  121. {
  122. get_status();    //
  123. 获得设备状态信息,并将其存入
  124. dbuf
  125. 指向的存储区,数据最后一字
  126. 节置
  127. 0
  128. 表示数据结束
  129. }
  130. /*
  131. 该函数接收一帧数据并进行检测,无论该帧是否错误,函数均会返回
  132. *
  133. 函数参数
  134. type
  135. 保存接收到的命令字
  136. *
  137. 当接收到数据帧错误或其地址位不为
  138. 0
  139. 时(非主机发送帧),函数返回
  140. 0
  141. ,反之返回
  142. 1
  143. */
  144. bit recv_cmd(uchar *type)
  145. {
  146. bit db = 0;    //
  147. 当接收到的上一个字节为
  148. 0xdb
  149. 时,该位置位
  150. bit c0 = 0;    //
  151. 当接收到的上一个字节为
  152. 0xc0
  153. 时,该位置位
  154. uchar data_buf[__ERRLEN];    //
  155. 保存接收到的帧
  156. uchar tmp;
  157. uchar ecc = 0;
  158. uchar i;
  159. M_DE = 0;    //
  160. 置发送禁止,接收允许
  161. M_RE = 0;
  162. /*
  163. 接收一帧数据
  164. */
  165. i = 0;
  166. while(!c0)    //
  167. 循环直至帧接收完毕
  168. {
  169.    RI = 0;
  170.    while(!RI);
  171.    tmp = SBUF;
  172.    RI = 0;
  173.    if(db == 1)    //
  174. 接收到的上一个字节为
  175. 0xdb
  176.    {
  177.     switch(tmp)
  178.     {
  179.      case 0xdd:
  180.       data_buf[i] = 0xdb;    // 0xdbdd
  181. 表示
  182. 0xdb
  183.       ecc = ecc^0xdb;
  184.       db = 0;
  185.       break;
  186.      case 0xdc
  187.       data_buf[i] = 0xc0;    // 0xdbdc
  188. 表示
  189. 0xc0
  190.       ecc = ecc^0xc0;
  191.       db = 0;
  192.       break;
  193.      default
  194.       return 0;    //
  195. 帧错误,返回
  196.     }
  197.     i++;
  198.    }
  199.    switch(tmp)    //
  200. 正常情况
  201.    {
  202.     case 0xc0:    //
  203. 帧结束
  204.      c0 = 1;
  205.      break;
  206.     case 0xdb:    //
  207. 检测到转义字符
  208.      db = 1;
  209.      break;
  210.     default:    //
  211. 普通数据
  212.      data_buf[i] = tmp;    //
  213. 保存数据
  214.      ecc = ecc^tmp;    //
  215. 计算校验字节
  216.      i++;
  217.    }
  218.    if(i == __ERRLEN)    //
  219. 帧超长,错误,返回
  220.     return 0;
  221. }
  222. /*
  223. 判断帧是否错误
  224. */
  225. if(i<4)    //
  226. 帧过短,错误,返回
  227.    return 0;
  228. if(ecc != 0)    //
  229. 校验错误,返回
  230.    return 0;
  231. if(data_buf[0] != dev)    //
  232. 非访问本机命令,错误,返回
  233.    return 0;
  234. *type = data_buf[1];    //
  235. 获得命令字
  236. return 1;    //
  237. 函数成功返回
  238. }
  239. /*
  240. 该函数发送一帧数据帧,参数
  241. type
  242. 为命令字、
  243. len
  244. 为数据长度、
  245. buf
  246. 为要发送的数据内

  247. */
  248. void send_data(uchar type, uchar len, uchar *buf)
  249. {
  250. uchar i;
  251. uchar ecc = 0;    //
  252. 该字节用于保存校验字节
  253. M_DE = 1;    //
  254. 置发送允许,接收禁止
  255. M_RE = 1;
  256. send_byte(dev);    //
  257. 发送本机地址
  258. ecc = dev;
  259. send_byte(type);    //
  260. 发送命令字
  261. ecc = ecc^type;
  262. send_byte(len);    //
  263. 发送长度
  264. ecc = ecc^len;
  265. for(i=0; i<len; i++)    //
  266. 发送数据
  267. {
  268.    send_byte(*buf);
  269.    ecc = ecc^(*buf);
  270.    buf++;
  271. }
  272. send_byte(ecc);    //
  273. 发送校验字节
  274. TI = 0;    //
  275. 发送帧结束标志
  276. SBUF = 0xc0;
  277. while(!TI);
  278. TI = 0;
  279. }
  280. /*
  281. 该函数发送一个数据字节,若该字节为
  282. 0xdb
  283. ,则发送
  284. 0xdbdd
  285. ,若该字节为
  286. 0xc0
  287. 则,发

  288. 0xdbdc */
  289. void send_byte(uchar da)
  290. {
  291. switch(da)
  292. {
  293.    case 0xdb:    //
  294. 字节为
  295. 0xdb
  296. ,发送
  297. 0xdbdd
  298.     TI = 0;
  299.     SBUF = 0xdb;
  300.     while(!TI);
  301.     TI = 0;
  302.     SBUF = 0xdd;
  303.     while(!TI)
  304.     TI = 0;
  305.     break;
  306.    case 0xc0:    //
  307. 字节为
  308. 0xc0
  309. ,发送
  310. 0xdbdc
  311.     TI = 0;
  312.     SBUF = 0xdb;
  313.     while(!TI);
  314.     TI = 0;
  315.     SBUF = 0xdc;
  316.     while(!TI)
  317.     TI = 0;
  318.     break;
  319.    default:    //
  320. 普通数据则直接发送
  321.     TI = 0;
  322.     SBUF = da;
  323.     while(!TI);
  324.     TI = 0;
  325. }
  326. }
  327. #endif
复制代码


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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