找回密码
 立即注册

QQ登录

只需一步,快速开始

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


评分

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

查看全部评分

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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