串口通讯:串口通信是用来在不同电子设备之间交换数据用的技术,其实就是要实现不同电子设备之间的“通讯对话”。
串口给通讯应用例子:刚拿到Arduino进行Blink测试,程序通过引脚控制了小灯亮起,但是如果我们想要改变当前小灯的亮度,想要把这个“想法”传递给Arduino的时候,就需要串口通讯了。可以通过串口通讯,从PC端告诉Arduino程序我们想要改变当前小灯的亮度。
串口:Arduino和其它设备通信的接口。
Arduino通讯串口:Arduino的串口通常称为UART或USART,通过0(RX)和1(TX)引脚以及USB 端口,来和其它设备进行通信。
UART(Universal Asynchronous Receiver/Transmitter):UART是通用异步收发器,采用异步串行通信协议,通过信号线把需要发送的数据以二进制的形式发出,高电平为数据“1”,低电平为数据“0”。
通信传输线:串口通常会有三根线来完成通讯,分别是地线、发送线、接收线。串口通信是异步的,能够在一根线上发送数据同时在另一根线上接收数据,其他线用于握手。
数据帧:Arduino用Serial.print和Serial.println函数发送数据时候,其实是发出一连串数字信号,这些数字信号称为数据帧。数据帧通常由四个部分组成,分别是起始位、数据位、校验位和停止位。
串口通讯缓冲区:Arduino的USB端口有串口寄存器,可以用来暂存电脑从USB发送的数据。Arduino从串口寄存器读取的速度比串口发送数据的速度快,所以串口通讯读取数据前需要加一定延时。和电脑通信的时候,Arduino UNO的串口寄存器空间默认是63帧的数据帧大小,超出后信息会挤掉前面的信息。
Serial 类:通过 Serial 类来使用开发板上的UART串口,只需要指定波特率,就能使用了。
波特率(Baud Rate):在信息传输通道中,携带数据信息的信号单元叫码元,单位时间内通过信道传输的码元数称为码元传输速率,简称波特率。常用的波特率为9600、115200、4800等,波特率越大表明通信的速率越快。。当传输的码元信息量刚好为1比特的时候,波特率等于比特率。通信双方需要使用一致的的波特率才能正常通信。
Serial.begin()
函数作用:开启串口。
使用方法:speed为波特率;config为设置数据位、校验位和停止位。
Serial.end()
函数作用:禁止串口传输,此时串口0(RX)和1(TX)引脚可以作为数字引脚使用。
Serial.print()
函数作用:串口输出数据,写入字符数据到串口。
使用方法:val是打印的值;config输出数据格式,BIN(二进制)、OCT(八进制)、DEC(十进制)、HEX(十六进制)等。
Serial.println()
函数作用:串口输出数据并换行。
使用方法:
Serial.available()
函数作用:判断串口缓冲区的状态,返回从串口缓冲区读取的字节数。
Serial.read()
函数作用:读取串口数据,一次读一个字符,读完后删除已读数据;当没有可读数据时返回-1,整数类型。
Serial.peek()
函数作用:读取串口数据,一次读一个字符,读完后不删除;当没有可读数据时返回-1,整数类型。。
Serial.readString()
函数作用:每次读取一个字符串,返回一个String类型。
Serial.readStringUntil()
函数作用:每次读取一个字符串,知道遇到截止字符,返回一个String类型。
使用方法:inByte为截止字符。
了解字符串的常用函数,可以更好进行串口通讯中复杂指令的处理。
获取字符串中的部分内容:
比较两个字符串:
字符串类型转换:
获取字符串长度:
两个字符串之间的合并:
先处理一个简单的指令。
示例代码的解释:往串口每次输入一串指令“a1”后,Arduino返回“YES”。
String str;
void setup() {
Serial.begin(115200);// 设置波特率,上位机的波特率要保证相同,不然无法识别
str="";
}
void loop() {
delay(100);//等待100ms=0.1s,加延时是因为Arduino从串口寄存器读取的速度比串口发送数据的速度快
while (Serial.available() > 0)
{
str += char(Serial.read());// read是剪切,而不是复制
}
if(str=="a1\0"){
Serial.println("YES");
}
str="";
}
程序验证上传到Arduino后。
点击IDE右上角有个串口监视器。
点击后会有下方会出现串口监视器,调整波特率和代码对应,然后输入没有结束符的消息“a1”,就可以看到Arduino返回的“YES”。
在前面的入门示例中,要处理的上位机指令很简单,上位机每次只发送一个指令“a1”。
但是如果上位机发送的指令很长,而且还包含了数字,甚至可能发送指令的速度很快,“Serial.available() > 0”判断的时候可能有多条指令要区分。
下面是一个处理稍微复杂指令的示例代码,涵盖了处理复杂指令的基本操作。
示例代码的解释:指令格式为“指令类型+数字+\n”,前4位为指令类型分别有1001、1002和1003,分别对应的功能为对数字进行1次方、2次方和3次方,指令结尾为“\n”。该代码会对输入的指令进行解读,并且进行相应的功能,返回对应的数值。
String str,pre_str,last_str;
String type_str[] = {"1001", "1002", "1003"}; //指令前4位表示不同类型指令,其中1001表示1次方,1002表示2次方,1003表示3次方
int i,j,ans,cnt;
void setup() {
Serial.begin(115200);// 设置波特率
}
void loop() {
delay(100);//等待100ms=0.1s
while (Serial.available() > 0)
{
str= Serial.readStringUntil('\n');//读取指令,指令以“\n”结尾,通过“\n”来分割不同的指令
pre_str = str.substring(0, 4);//截取输入指令前4位
last_str= str.substring(5, str.length());//截取输入指令4位后的数据
cnt = last_str.toInt();//将字符串last_str转成数字cnt
ans=cnt;
// 根据不同指令计算cnt多少次方
for(i=0;i<3;i++){
if(pre_str.compareTo(type_str[i])==0){
for(j=0;j<i;j++){
ans*=cnt;
}
}
}
Serial.println(ans);
}
}