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); // 等待100msj = 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)通信类型总结

    推荐阅读