Arduino 电子积木 RS485串口模块

Written by on 2010/11/30 in Arduino, 产品 - No comments

RS232串口是我们非常熟悉的一种Arduino与计算机之间进行数据交换的手段,虽然最新的Arduino在设计时都采用了USB转串口的方式,但最初一版的Arduino的确是基于RS232串口的。直到现在,RS232仍然在实际的工程项目中大量用到,不过这种方式有两个致命的弱点:一是传输距离不能太长,二是只能实现两个设备之间的点对点通信。我们这里要介绍的RS485模块正好解决了这两个问题:

RS485串行总线接口标准以差分平衡方式传输信号,具有很强的抗共模干扰的能力,允许一对双绞线上一个发送器驱动多个 负载设备,其理论的通讯距离是1200米,速率高达20Mbps,并可以用在强噪声的环境中正常工作,因此在工业通讯领域中被广泛应用。 当我们在Arduino上使用RS485时,更多的可能是借助其互连功能,将多个Arduino连接成一个RS485网络,来实现各个Arduino之间的通信。

在由RS485构成的多机串行通信系统中,一般采用的都是主从式结构:也就是说主机负责所有的通信协调过程,从机一般被动地接收主机发送过来的数据,或者根据主机的命令向主机反馈相应的数据,各个从机之间一般不进行数据交换,而是通过主机进行中转。之所以采用这种方式是因为于RS485是一种半双工通讯,发送和接收共用同一物理信道,在任一时刻都只允许一台设备处于发送状态。如果在时序上配合不好,就会发生总线冲突,使整个系统的通讯瘫痪,从而无法正常工作。

我们以一个三个结点的网络为例,介绍如何利用RS485串口模块来构建一个RS485网络,该网络中包括一台作为主机使用的Arduino(S)和两台作为从机使用的Arduino(CA, CB)。对于网络中的每一台Arduino来讲,硬件连接上我们都需要一块Arduino专用传感器扩展板、一条COM连接线和一条通用传感器连接线,其中COM连接线用来将RS485串口模块与传感器扩展板上的COM口连接起来,而通用传感器连接线则用来将RS485串口模块上的RE/DE引脚和标号为2的数字I/O口连接起来:

我们之前已经介绍过,RS485网络上的任何时候都只有一台设备处于发送状态,而其它设备则应该全部都处于接收状态。Arduino正是通过对RE/DE引脚的控制,来指定该设备是向RS485网络中发送数据,还是从RS485网络中接收数据。为了说明上的方便,在我们的例子中主设备S一直都处于发送状态,相应的RE/DE引脚一直处于高电平状态;两台从设备CA和CB一直处于接收状态,相应的RE/DE引脚则一直处于低电平状态。

在RS485串口模块上另一个需要引起我们注意的就是标记为“TERM?”的开关,它是用来控制终端电阻的,目的是为了吸收RS485网络中的反射信号,以保证正常传输的信号不受到干扰。不过该电阻只能在RS485总线上的最后一台设备上出现,这也是为什么叫做终端电阻的原因。在我们上面给出的网络拓朴图中不难看出,从机CB是总线上的最后一台设置,因此我们需要在该设备所对应的RS485串口模块上将“TERM?”开关拨到“Y”的位置:

而在主机S和从机CA上该开关都需要设置到与之相反的位置上:

由于是要将三个Arduino连接成一个RS485网络,因此我们还需要将RS485 串口模块两两连接起来,这是通过RS485串口模块上的“485 IN”和“485 THU”两个插座来实现的。具体说来,就是我们需要将前一个RS485串口模块的“485 THU”接口,与下一个RS485串口模块的“485 IN”接口连接起来,连接的时候我们可以使用模拟传感器连接线,或者是普通的杜邦线。对于我们正在构建的三个结点的RS485网络来讲,则是要求主机S的“485 THU”与从机CA的“485 IN”连接起来,然后再将从机CA的“485 THU”与从机CB的“485 IN”连接起来,实验中我们使用的是长度为2米的模拟传感器连接线。下图中从左至右依次为主机S,从机CA和从机CB:

硬件都连接好之后,下面我们就可以为各个Arduino来编写相应的程序了。下面是主机S的代码:

int EN = 2;

void setup()
{
  pinMode(EN, OUTPUT);
  Serial.begin(19200);
}

void loop()
{
// send data 
  digitalWrite(EN, HIGH);//使能发送
  Serial.print('A');
  Serial.print('B');
  delay(1000);
}

从主机S的代码不难看出,虽然采用的是RS485串口协议,但编程时使用的还是普通的串口操作语句。

下面是从机CA所使用的代码:

int ledPin = 13;
int EN = 2;
int val;

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(EN, OUTPUT);
  Serial.begin(19200);
}

void loop()
{
  // receive data
 digitalWrite(EN, LOW);//使能接收
 val = Serial.read();
  if (-1 != val) {
    if ('A' == val) {
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
    }
 }
}

下面是从机CB所使用的代码:

int ledPin = 13;
int EN = 2;
int val;

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(EN, OUTPUT);
  Serial.begin(19200);
}

void loop()
{
  // receive data
 digitalWrite(EN, LOW);//使能接收
 val = Serial.read();
  if (-1 != val) {
    if ('B' == val) {
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
    }
 }
}

从代码中不难看出,CA和CB分别响应主机S发送过来的字母A或者B,然后做相应的反应:点亮一个LED灯。在将三台Arduino都分别通电之后,你就可以看到作为主机的CA和CB在接到主机S发过来的命令之后,分别做相应的点灯动作。

最后需要说明的一点是,虽然在我们的例子中演示的是主机S不断向从机CA和CB发送数据的单向通信过程,但其实在RS485网络中也是可以实现双向通信的,只但需要在代码上做更多的工作,并且需要在主机和从面之间根据应用的需要定义一个相应的数据通信协议。

Leave a Comment

使用新浪微博登录