您的位置 首页 分销

单片机RS485通讯接口、控制线、原理图及程序教育实例

单片机RS485通信接口、控制线、原理图及程序教学实例-RS232 标准是诞生于 RS485 之前的,但是 RS232 有几处不足的地方:接口的信号电平值较高,达到十几 V,使用不当容易损坏接口芯片,

  [前语]RS232 规范是诞生于 RS485 之前的,可是 RS232 有几处缺乏的当地:接口的信号电平值较高,抵达十几 V,运用不当简略损坏接口芯片,电平规范也与TTL 电平不兼容。传输速率有限制,不能够过高,一般到一两百千比特每秒(Kb/s)就到极限了。接口运用信号线和 GND 与其它设备构成共地形式的通讯,这种共地形式传输简略发生搅扰,而且抗搅扰功用也比较弱。传输距离有限,最多只能通讯几十米。通讯的时分只能两点之间进行通讯,不能够完结多机联网通讯。针对 RS232 接口的缺乏,就不断出现了一些新的接口规范,RS485 便是其间之一。 RS232 规范是诞生于 RS485 之前的,可是 RS232 有几处缺乏的当地:

  接口的信号电平值较高,抵达十几 V,运用不当简略损坏接口芯片,电平规范也与TTL 电平不兼容。

  传输速率有限制,不能够过高,一般到一两百千比特每秒(Kb/s)就到极限了。

  接口运用信号线和 GND 与其它设备构成共地形式的通讯,这种共地形式传输简略发生搅扰,而且抗搅扰功用也比较弱。

  传输距离有限,最多只能通讯几十米。

  通讯的时分只能两点之间进行通讯,不能够完结多机联网通讯。

  针对 RS232 接口的缺乏,就不断出现了一些新的接口规范,RS485 便是其间之一,它具有以下的特色:

  选用差分信号。咱们在讲 A/D 的时分,讲过差分信号输入的概念,一同也介绍了差分输入的优点,最大的优势是能够按捺共模搅扰。特别当工业现场环境比较杂乱,搅扰比较多时,选用差分办法能够有用的进步通讯可靠性。RS485 选用两根通讯线,通常用 A 和 B 或许 D+和 D-来表明。逻辑“1”以两线之间的电压差为+(0.2~6)V 表明,逻辑“0”以两线间的电压差为-(0.2~6)V 来表明,是一种典型的差分通讯。

  RS485 通讯速率快,最大传输速度能够抵达 10Mb/s 以上。

  RS485 内部的物理结构,选用的是平衡驱动器和差分接纳器的组合,抗搅扰才干也大大增加。

  传输距离最远能够抵达 1200 米左右,可是它的传输速率和传输距离是成反比的,只要在 100Kb/s 以下的传输速度,才干抵达最大的通讯距离,假如需求传输更远距离能够运用中继。

  能够在总线上进行联网完结多机通讯,总线上答应挂多个收发器,从现有的 RS485芯片来看,有能够挂 32、64、128、256 等不同个设备的驱动器。

  RS485 的接口十分简略,与 RS232 所运用的 MAX232 是相似的,只需求一个 RS485转化器,就能够直接与单片机的 UART 串口连接起来,而且运用彻底相同的异步串行通讯协议。可是由于 RS485 是差分通讯,因而接纳数据和发送数据是不能一同进行的,也便是说它是一种半双工通讯。那咱们怎么判别什么时分发送,什么时分接纳呢?

  RS485 转化芯片许多,这节课咱们以典型的 MAX485 为例解说 RS485 通讯,如图 18-1所示。

  

  图 18-1 MAX485 硬件接口

  MAX485 是美信(Maxim)推出的一款常用 RS485 转化器。其间 5 脚和 8 脚是电源引脚;6脚和 7 脚便是 RS485 通讯中的 A 和 B 两个引脚;1 脚和 4 脚别离接到单片机的 RXD 和 TXD引脚上,直接运用单片机 UART 进行数据接纳和发送;2 脚和 3 脚是方向引脚,其间 2 脚是低电平使能接纳器,3 脚是高电平使能输出驱动器,咱们把这两个引脚连到一同,往常不发送数据的时分,坚持这两个引脚是低电平,让 MAX485 处于接纳状况,当需求发送数据的时分,把这个引脚拉高,发送数据,发送结束后再拉低这个引脚就能够了。为了进步 RS485 的抗搅扰才干,需求在接近 MAX485 的 A 和 B 引脚之间并接一个电阻,这个电阻阻值从 100欧到 1K 都是能够。

  在这里咱们还要介绍一下怎么运用 KST-51 单片机开发板进行外围扩展试验。咱们的开发板只能把根本的功用给同学们做出来供给试验操练,可是同学们学习的脚步不应该停留在这个试验板上。假如想进行更多的试验,就能够经过单片机开发板的扩展接口进行扩展试验。咱们能够看到蓝绿色的单片机座周围有 32 个插针,这 32 个插针便是把单片机的 32 个 IO 引脚全部都引出来了。在原理图上体现出来的便是 J4、J5、J6、J7 这 4 个器材,如图 18-2 所示。

  

  图 18-2 单片机扩展接口

  这 32 个 IO 口中并不是一切的都能够用来对外扩展,其间既作为数据输出,又能够作为数据输入的引脚是不能够用的,比方 P3.2、P3.4、P3.6 引脚,这三个引脚是不可用的。比方P3.2 这个引脚,假如咱们用来扩展,发送的信号假如和 DS18B20 的时序符合,会导致 DS18B20拉低引脚,影响通讯。除这 3 个 IO 口以外的其它 29 个,都能够运用杜邦线接上插针,扩展出来运用。当然了,假如把当时的 IO 口应用于扩展功用了,板子上的相应功用就完结不了了,也便是说需求扩展功用和板载功用之间二选一。

  在进行 RS485 试验中,咱们通讯用的引脚有必要是 P3.0 和 P3.1,此外还有一个方向操控引脚,咱们运用杜邦线将其连接到 P1.7 上去。RS485 的别的一端,咱们能够运用一个 USB转 RS485 模块,用双绞线把开发板和模块上的 A 和 B 别离对应连起来,USB 那头刺进电脑,然后就能够进行通讯了。

  学习了第 13 章有用的串口通讯办法和程序后,做这种串口通讯的办法就很简略了,根本是共同的。咱们运用有用串口通讯例程的思路,做了一个简略的程序,经过串口调试帮手下发恣意个字符,单片机接纳到后在结尾增加“回车+换行”符后再送回,在调试帮手上从头显示出来,先把程序贴出来。

  程序中需求留意的一点是:由于往常都是将 MAX485 设置为接纳状况,只要在发送数据的时分才将 MAX485 改为发送状况,所以在 UartWrite()函数最初将 MAX485 方向引脚拉高,函数退出前再拉低。可是这里有一个细节,便是单片机的发送和接纳中止发生的时刻都是在中止位的一半上,也便是说每逢中止位传送了一半的时分,RI 或 TI 就现已置位而且立刻进入中止(假如中止使能的话)函数了,接纳的时分天然不会存在问题,但发送的时分就不相同了:当紧接着向 SBUF 写入一个字节数据时,UART 硬件会在完结上一个中止位的发送后,再开端新字节的发送,但假如此刻不是继续发送下一个字节,而是现已发送结束了,要中止发送并将 MAX485 方向引脚拉低以使 MAX485 从头处于接纳状况时就有问题了,由于这时分最终的这个中止位实践只发送了一半,还没有彻底完结,所以就有了 UartWrite()函数内DelayX10us(5)这个操作,这是人为的增加了 50us 的延时,这 50us 的时刻正好让剩余的一半中止位完结,那么这个时刻天然便是由通讯波特率决议的了,为波特率周期的一半。

  /****************************RS485.c 文件程序源代码*****************************/

  纯文本仿制

  #include

  #include

  sbit RS485_DIR = P1^7; //RS485 方向挑选引脚

  bit flagFrame = 0; //帧接纳完结标志,即接纳到一帧新数据

  bit flagTxd = 0; //单字节发送完结标志,用来代替 TXD 中止标志位

  unsigned char cntRxd = 0; //接纳字节计数器

  unsigned char pdata bufRxd[64]; //接纳字节缓冲区

  extern void UartAcTIon(unsigned char *buf, unsigned char len);

  /* 串口装备函数,baud-通讯波特率 */

  void ConfigUART(unsigned int baud){

  RS485_DIR = 0; //RS485 设置为接纳方向

  SCON = 0x50; //装备串口为形式 1

  TMOD = 0x0F; //清零 T1 的操控位

  TMOD |= 0x20; //装备 T1 为形式 2

  TH1 = 256 – (11059200/12/32)/baud; //核算 T1 重载值

  TL1 = TH1; //初值等于重载值

  ET1 = 0; //制止 T1 中止

  ES = 1; //使能串口中止

  TR1 = 1; //发动 T1

  }

  /* 软件延时函数,延时时刻(t*10)us */

  void DelayX10us(unsigned char t){

  do {

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  } while (–t);

  }

  /* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */

  void UartWrite(unsigned char *buf, unsigned char len){

  RS485_DIR = 1; //RS485 设置为发送

  while (len–){ //循环发送一切字节

  flagTxd = 0; //清零发送标志

  SBUF = *buf++; //发送一个字节数据

  while (!flagTxd); //等候该字节发送完结

  }

  DelayX10us(5); //等候最终的中止位完结,延时时刻由波特率决议

  RS485_DIR = 0; //RS485 设置为接纳

  }

  /* 串口数据读取函数,buf-接纳指针,len-指定的读取长度,回来值-实践读到的长度 */

  unsigned char UartRead(unsigned char *buf, unsigned char len){

  unsigned char i;

  //指定读取长度大于实践接纳到的数据长度时,

  //读取长度设置为实践接纳到的数据长度

  if (len 》 cntRxd){

  len = cntRxd;

  }

  for (i=0; i

  *buf++ = bufRxd[i];

  }

  cntRxd = 0; //接纳计数器清零

  return len; //回来实践读取长度

  }

  /* 串口接纳监控,由闲暇时刻断定帧结束,需在守时中止中调用,ms-守时刻隔 */

  void UartRxMonitor(unsigned char ms){

  staTIc unsigned char cntbkp = 0;

  staTIc unsigned char idletmr = 0;

  if (cntRxd 》 0){ //接纳计数器大于零时,监控总线闲暇时刻

  if (cntbkp != cntRxd){ //接纳计数器改动,即刚接纳到数据时,清零闲暇计时

  cntbkp = cntRxd;

  idletmr = 0;

  }else{ //接纳计数器未改动,即总线空

  }else{ //接纳计数器未改动,即总线闲暇时,累积闲暇时刻

  if (idletmr 《 30){ //闲暇计时小于 30ms 时,继续累加

  idletmr += ms;

  if (idletmr 》= 30){ //闲暇时刻抵达 30ms 时,即断定为一帧接纳结束

  flagFrame = 1; //设置帧接纳完结标志

  }

  }

  }

  }else{

  cntbkp = 0;

  }

  }

  /* 串口驱动函数,监测数据帧的接纳,调度功用函数,需在主循环中调用 */

  void UartDriver(){

  unsigned char len;

  unsigned char pdata buf[40];

  if (flagFrame){ //有指令抵达时,读取处理该指令

  flagFrame = 0;

  len = UartRead(buf, sizeof(buf)-2); //将接纳到的指令读取到缓冲区中

  UartAction(buf, len); //传递数据帧,调用动作履行函数

  }

  }

  /* 串口中止服务函数 */

  void InterruptUART() interrupt 4{

  if (RI){ //接纳到新字节

  RI = 0; //清零接纳中止标志位

  //接纳缓冲区没有用完时,保存接纳字节,并递加计数器

  if (cntRxd 《 sizeof(bufRxd)){

  bufRxd[cntRxd++] = SBUF;

  }

  }

  if (TI){ //字节发送结束

  TI = 0; //清零发送中止标志位

  flagTxd = 1; //设置字节发送完结标志

  }

  }

  /*****************************main.c 文件程序源代码******************************/

  #include

  unsigned char T0RH = 0; //T0 重载值的高字节

  unsigned char T0RL = 0; //T0 重载值的低字节

  void ConfigTimer0(unsigned int ms);

  extern void UartDriver();

  extern void ConfigUART(unsigned int baud);

  extern void UartRxMonitor(unsigned char ms);

  extern void UartWrite(unsigned char *buf, unsigned char len);

  void main(){

  EA = 1; //开总中止

  ConfigTimer0(1); //装备 T0 守时 1ms

  ConfigUART(9600); //装备波特率为 9600

  while (1){

  UartDriver(); //调用串口驱动

  }

  }

  /* 串口动作函数,依据接纳到的指令帧履行呼应的动作

  buf-接纳到的指令帧指针,len-指令帧长度 */

  void UartAction(unsigned char *buf, unsigned char len){

  //在接纳到的数据帧后增加换车换行符后发回

  buf[len++] = ‘\r’;

  buf[len++] = ‘\n’;

  UartWrite(buf, len);

  }

  /* 装备并发动 T0,ms-T0 守时时刻 */

  void ConfigTimer0(unsigned int ms){

  unsigned long tmp; //暂时变量

  tmp = 11059200 / 12; //守时器计数频率

  tmp = (tmp * ms) / 1000; //核算所需的计数值

  tmp = 65536 – tmp; //核算守时器重载值

  tmp = tmp + 33; //补偿中止呼应延时形成的差错

  T0RH = (unsigned char)(tmp》》8); //守时器重载值拆分为凹凸字节

  T0RL = (unsigned char)tmp;

  TMOD = 0xF0; //清零 T0 的操控位

  TMOD |= 0x01; //装备 T0 为形式 1

  TH0 = T0RH; //加载 T0 重载值

  TL0 = T0RL;

  ET0 = 1; //使能 T0 中止

  TR0 = 1; //发动 T0

  }

  /* T0 中止服务函数,履行串口接纳监控 */

  void InterruptTimer0() interrupt 1{

  TH0 = T0RH; //从头加载重载值

  TL0 = T0RL;

  UartRxMonitor(1); //串口接纳监控

  }

  现在看这种串口程序,是不是感觉很简略了呢?串口通讯程序咱们反反复复的运用,加上跟着学习的模块越来越多,实践的越来越多,原先感觉很杂乱的东西,现在就会感到简略了。从设备管理器里能够检查一切的 COM 标语,咱们下载程序用的是 COM4,而 USB 转RS485 虚拟的是 COM5,通讯的时分咱们用的是 COM5 口,如图 18-3 所示。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/bandaoti/fenxiao/182878.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部