> 文档中心 > Arduino串口通信

Arduino串口通信

文章目录

          • 通信类型
          • Arduino串口通信
            • 硬串口
            • 软串口
通信类型

通信是用来在不同电子设备之间交换数据用的技术,其实就是要实现不同电子设备之间的“通讯对话”。

Arduino串口通信

Arduino串口通信

Arduino采用USART通信模式,可以有硬串口,软串口两种实现方式。

通常将Arduino UNO上自带的串口0(RX)、1(TX)称为硬件串口,可与外围串口设备通信。而使用SoftwareSerial类库模拟成的串口,称为软件模拟串口(简称软串口)。如果要连接更多的串口设备,可以使用软串口。

硬串口

硬串口的操作类为HardwareSerial,定义于HardwareSerial.h源文件中,并对用户公开声明了Serial对象,用户在Arduino程序中直接调用Serial,就可实现串口通讯。

常用函数有:

Serial.begin()

  • 描述:开启串口,通常置于setup()函数中。
  • 原型:
    • Serial.begin(speed)
    • Serial.begin(speed, config)
  • 参数:
    • speed:波特率,一般取值9600,115200等。
    • config:设置数据位、校验位和停止位。默认SERIAL_8N1表示8个数据位,无校验位,1个停止位。
  • 返回值:无。

Serial.end()

  • 描述:禁止串口传输。此时串口Rx和Tx可以作为数字IO引脚使用。
  • 原型:Serial.end()
  • 参数:无。
  • 返回值:无。

Serial.print()

  • 描述:串口输出数据,写入字符数据到串口。
  • 原型:
    • Serial.print(val)
    • Serial.print(val, format)
  • 参数:
    • val:打印的值,任意数据类型。
    • config:输出的数据格式。BIN(二进制)、OCT(八进制)、DEC(十进制)、HEX(十六进制)。对于浮点数,此参数指定要使用的小数位数。
  • 示例:
    • Serial.print(78, BIN) 得到 “1001110”
    • Serial.print(78, OCT) 得到 “116”
    • Serial.print(78, DEC) 得到 “78”
    • Serial.print(78, HEX) 得到 “4E”
    • Serial.print(1.23456, 0) 得到 “1”
    • Serial.print(1.23456, 2) 得到 “1.23”
    • Serial.print(1.23456, 4) 得到 “1.2346”
    • Serial.print(‘N’) 得到 “N”
    • Serial.print(“Hello world.”) 得到 “Hello world.”
  • 返回值:返回写入的字节数。

Serial.println()

  • 描述:串口输出数据并换行。
  • 原型:
    • Serial.println(val)
    • Serial.println(val, format)
  • 参数:
    • val:打印的值,任意数据类型。
    • config:输出的数据格式。
  • 返回值:返回写入的字节数。

Serial.available()

  • 描述:判断串口缓冲区的状态,返回从串口缓冲区读取的字节数。
  • 原型:Serial.available()
  • 参数:无。
  • 返回值:可读取的字节数。

Serial.read()

  • 描述:读取串口数据,一次读一个字符,读完后删除已读数据。
  • 原型:Serial.read()
  • 参数:无。
  • 返回值:返回串口缓存中第一个可读字节,当没有可读数据时返回-1,整数类型。

具体操作函数参考

实验1:

String str="";void setup() {  Serial.begin(9600); //set up serial library baud rate to 9600}void loop() {  str = "";  while (Serial.available() > 0)  {    str += char(Serial.read());   // read是剪切,而不是复制    delay(10);  // 延时  }  if (str.length() > 0)  {    Serial.print(F("命令行发送内容:"));    Serial.println(str);  }}

实验现象:

Arduino串口通信

实验2:

Arduino串口通信

/** * 通过串口改变Arduino 9号针脚接的LED灯的亮度 */int i,j,val; //定义i、j、val三个整型变量char A[10];  //定义一个无符号数组Avoid setup(){  Serial.begin(9600);  pinMode(9,OUTPUT);}void loop(){  delay(100);  // 等待100ms  j = Serial.available();  // 读取串口寄存器中的信息的帧数  if(j != 0){   // 如果串口寄存器中有数据,那么依次读取这些数据,并存放到数组A中    for(i = 0; i < j; i++){      A[i] = Serial.read();     }    val = strtol(A,NULL,10);  // 将A中的字符转换成十进制数  }  analogWrite(9,val); // 将转换好的val输出给三号端口,驱动LED灯的亮度}

实验分析:

在理解Arduino串口通信前需要知道一些先验知识。

计算机和Arduino的串口接线如下:

Arduino串口通信

在Arduino的USB接口连接一个串口寄存器,用来暂时存放电脑传过来的信息(之后Arduino会根据开发者的程序,从串口寄存器中提取数据,保存到Arduino内存中),在和电脑通过USB串口通信时,默认分配给Arduino UNO的串口寄存器空间可存放63帧的信息。(一帧信息包括帧头、数据和帧尾。)超出得话后面的信息就会挤兑前面的信息,造成信息丢失。

read函数读取串口寄存器中的信息。但是Arduino的主频有16M,也就是每秒运算160万次;而串口通信的速度(也就是前面讲到的波特率)最高一般用到115200,也就是每秒115200个比特,约为14400个字节。所以Arduino读取的速度比串口发送的速度快得多,在读取之前需要加一定的延时。

现在假设我们从电脑上发送了三个帧的数据给到Arduino,这三个帧的内容分别是’a’,‘b’,‘c’。

Arduino串口通信

首先,右侧中步骤1至步骤4这段时间内,信息一帧一帧地进入串口寄存器中,假如我们想要一次性读取所有的信息,那么在步骤1到步骤4的这段时间内我们不能够对信息进行读取,因为这个时候信息还没有完全传送完毕,也就是说所有信息没有全部进入寄存器。假如我们在图6中的步骤2就开始读取寄存器中的信息,那么我们将只能获得’a’这个信息。对于Arduino这个1秒钟运算160万次的芯片来说,串口信息的传送是很慢的,所以我们必须在开头给Arduino设置一个等待时间,这个等待时间一般就设定100ms即可,这就是为什么要加上delay(100)这条命令的原因。

然后,当等待时间结束,这时候我们认为信息已经完全传送完毕。当然,说实话这都是靠猜,我们估计100ms信息传送完毕了,可能信息早在10ms 的时候就传送完毕了,不过没关系,为了保险我们宁可多等待一会儿,反正是毫秒级的时间损失,对于我们来说多等几十毫秒根本感觉不出来,当然你觉得有把握的话也可以把等待时间缩短一些,比如50ms甚至20ms都可以,你可以尝试着用,假如没有出现信息丢失那你完全可以用更短的等待时间。信息完全传送完毕后,我们才开始要把信息从串口寄存器中都读取出来了,也即是步骤5到步骤7的过程。注意,图6中的黑线指向的那个“大箭头”是Arduino内部的一个指针,这个指针时刻监测着串口寄存器,我们随时可以使用命令Serial.available()来调动这个指针,获取传入信息的数量,当然如我们所说,要等信息全部传送完毕后再开始调用,假如我们在步骤2就调用Serial.available()的话,我们只能探测到一个数据。而在图6中的步骤4我们可以看到,总共有三个信息传入了寄存器,所以这个时候调用Serial.available()获得的值是3,然后我们把这个值赋给变量j,于是变量j就代表了寄存器中信息的数量。

最后,还是这个指针,我们可以使用命令Serial.read()来调动这个指针来抓取数据,注意Serial.read()每次可以抓取一帧的信息,每次抓取走信息后,寄存器中原本存放这个信息的空间就空了出来,我的意思是:Serial.read()命令不是复制信息而是剪切信息。好,回过头来说,3个信息每次抓取1个,那么为了抓取寄存器中的所有信息,我们需要抓取3次,于是我们采用了一个 for循环,循环数设定为j,这样就可以自动抓取所有寄存器中的信息了。每次抓取的数据我们将会存储到数组A中,A是我们在程序开头就定义好的一个字符型数组。关于A数组要注意两点:1)必须定义为字符型数组,因为我们讲过电脑串口输入的所有信息都是字符形式传输的,就算是阿拉伯数字也只是一个字符,而不是真的阿拉伯数字;2)A数组的空间大小在定义的时候要给足,假如我们打算每次处理1帧的数据,那么A的空间就要给到1帧或更多;假如我们每次打算处理3帧的数据,那么A的空间就要大于等于3帧。然后我们把“帧”换算成字节来定义A的空间。

软串口

软串口的操作类为SoftwareSerial,定义于SoftwareSerial.h源文件中,但不像硬串口那样,源文件中并没有事先声明软串口对象,Arduino程序中需要手动创建软串口对象。

在使用前需要先声明包含SoftwareSerial.h头文件。

之后调用SoftwareSerial类的构造函数,通过它可指定软串口RX、TX引脚。

SoftwareSerial mySerial= SoftwareSerial(rxPin, txPin)SoftwareSerial mySerial(rxPin, txPin)
  • mySerial:用户自定义软件串口对象
  • rxPin:软串口接收引脚
  • txPin:软串口发送引脚

SoftwareSerial类中定义的成员函数与硬件串口类似,available()、begin()、read()、write()、print()、println()、peek() 等用法相同。

测试代码:

#include  //定义管脚2/3分别为RX,TX.  SoftwareSerial mySerial(2, 3); // RX, TX  void setup()  {    mySerial.begin(9600);  }  void loop()   {     mySerial.println("Hello, world?");     //TX输出   delay(1000);  } 

运行程序,会发现串口监视器并没有任何字符串输出,这是为什么?

在硬串口的部分提到过,计算机是通过硬串口TX(1)和RX(0)进行Arduino串口通信的,当我们使用软串口的时候,计算机连接的仍然是这两个引脚。所以即使软串口TX(3)在进行输出,仍然是不会被计算机读取显示的。所以将硬串口TX(1)和软串口TX(3)连接即可,这样软串口TX(3)的输出就会进入到硬串口TX(1)中,进而发送给计算机。

Arduino串口通信

实验现象:

Arduino串口通信

参考:

Arduino菜鸟通俗版解读系列(4)串口通信USART

Arduino菜鸟通俗版解读系列(7)通信类型总结