Arduino程序设计(十二)串口通信实验(上位机发送指令,下位机执行)_arduino串口通信-程序员宅基地

技术标签: arm开发  Arduino  单片机  


前言

  • 本文主要介绍String类函数、Serial类函数及两个串口通信实验,分别是:
  • 1、字符串数据类型操作;
  • 2、串口通信介绍;
  • 3、上位机控制LED灯;
  • 4、上位机实现按键检测。

一、字符串数据类型操作

1、字符串简介

  • (1)字符串用于存储文本,可用于在LCD或Arduino IDE串行监视器窗口中显示文本。 同时字符串对于存储用户输入也很有用。 例如,用户在连接到Arduino的键盘上键入的字符。

  • (2)Arduino编程中有两种类型的字符串:

  • ① 字符数组,与C编程中使用的字符串相同;

  • ② Arduino String,它允许我们在程序中使用字符串对象。

  • (3)构造 String 类的实例,以下都是字符串的有效声明:

String stringOne = "Hello String";                    // 用双引号括起来的常量字符串(即 char 数组)
String stringOne = String('a');                       // 单个常量字符,用单引号括起来
String stringTwo = String("This is a string");        // converting a constant string into a String object
String stringOne = String(stringTwo + " with more");  //concatenating two strings
String stringOne = String(13);                        // 一个常量整数
String stringOne = String(analogRead(0), DEC);        // using an int and a base
String stringOne = String(45, HEX);                   // using an int and a base (hexadecimal)
String stringOne = String(255, BIN);                  // using an int and a base (binary)
String stringOne = String(millis(), DEC);             // using a long and a base
String stringOne = String(5.698, 3);                  // 浮点数或双精度数,使用指定的小数位
  • (4)String 类的声明:
  • 从数字构造字符串会生成一个包含该数字的 ASCII 表示形式的字符串,默认是十进制。
字符串声明 功能说明
String thisString = String(13) 十进制字符串"13"
String thisString = String(13, HEX) 字符串"d",它是 13 的十六进制表示
String thisString = String(13, BIN) 字符串"1101",它是 13 的二进制表示
String(val) val:要格式化为字符串的变量。允许的数据类型:string、char、byte、int、long、unsigned int、unsigned long、float、double。
String(val, base) val同上,base:(可选)格式化整数值的基数
String(val, decimalPlaces) val同上,decimalPlaces:仅当 val 为 float 或 double 时.所需的小数位

2、常见的字符串操作函数

String类 功能描述
String() String 类的实例,注意:在“双引号”中指定的常量字符串被视为char数组,不是String类的实例
charAt(n) 返回字符串中第n个字符
compareTo(S2) 和给的S2字符串比较,如果两个字符串相同,返回值等于0;否则,返回值不等于0
equals() 比较两个字符串是否相等。 比较区分大小写,这意味着字符串“hello”不等于字符串“HELLO”。
length() 返回字符串中的字符数
substring(from, to) 获取String的子字符串。从指定的起始索引 " from " 到结束索引 " to " (不包括)截取字符串的子串。
substring(from) 返回一个从给定索引" from " 到结尾的新的字符串
toInt() 返回字符串中数字为整数值
toCharArray(buf,len) 把字符串转换成数组char[]。buf:指定char[]的位置,char[] 的大小一定要>=字符串的大小,len:复制的长度
strlen() 用于获取字符串的长度。 字符串的长度仅适用于可打印字符,不包括空终止符。
sizeof() 用于获取包含字符串的数组的长度。 长度包括空终止符,因此长度比字符串的长度多一个。
strcat() 将传递给它的第二个字符串放到传递给它的第一个字符串的末尾
concat(S2) 返回字符串和字符串S2合并后的新字符串
equals(S2) 如果字符串和S2完全相符,就返回TRUE

二、串口通信介绍

1、基础知识

  • (1)串口通信协议:

  • 串行通信协议应严格遵守,串行通信协议是一套规则,必须应用这些规则才能使设备正确地解释它们相互交换的数据。但是,Arduino 会自动处理这个问题,这样程序员/用户的工作就可以简化为简单的写(发送的数据)和读(接收的数据)。Arduino 串口通信的优缺点如下:

  • ① 优点:传输线少,长距离传送时成本低

  • ② 缺点:数据的传送控制比并行通信复杂

  • (2)串行通信的分类:

  • 同步通信 —— 同步的设备使用相同的时钟,它们的时序彼此同步。

  • 异步通信 —— 异步的设备具有各自的时钟,并由前一状态的输出触发。

  • 如果给所有连接的设备提供相同的时钟,则它们是同步的。如果没有时钟线,它是异步的。

  • (3)串行通信的传输方向:

  • ① 单工:是指数据传输仅能沿一个方向,不能实现反向传输。

  • ② 半双工:是指数据传输可以沿两个方向,但需要分时进行。

  • ③ 全双工:是指数据可以同时进行双向传输。

  • (4)串口通信定义:串口通信(Serial CommunicaTIons)是指串口按位(bit)发送和接收字节。串口用于ASCII码字符的传输,通信使用3根线完成,分别是地线、发送线、接收线。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据,其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。 对于两个进行通信的端口,这些参数必须要匹配。

  • (5)波特率:通信双方需要使用一致的的波特率才能正常通信。 Arduino串口通信通常会使用以下波特率:300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600、115200等,最常用的是9600。波特率越大,说明串口通信的速率越快。

  • (6)Arduino UNO通信:通过Arduino上的USB接口与计算机连接而进行Arduino与计算机之间的串口通信。除此之外,还可以使用串口引脚连接其他的串口设备进行通信。需要注意的是,通常一个串口只能连接一个设备进行通信。

2、工作原理

  • (1)在 Arduino 与其他器件通信的过程中,数据传输实际上都是以数字信号(即电平高低变化)的形式进行的,串口通信也是如此。当使用 Serial. print() 函数输出数据时,Arduino 的发送端会输出一连串的数字信号,称这些数字信号为数据帧。
  • (2)UART模式的数据格式如下:
    在这里插入图片描述
数据格式 功能描述
起始位 起始位总为低电平,是一组数据帧开始传输的信号。
数据位 数据位是一个数据包,其中承载了实际发送的数据的数据段。 当Arduino通过串口发送一个数据包时,实际的数据可能不是8位的,比如,标准的ASCII码是0-127(7位)。而扩展的ASCII码则是0-255(8位)。如果数据使用简单的文本(标准ASCII码),那么每个数据包将使用7位数据。Arduino 默认使用8位数据位,即每次可以传输1B数据。
校验位 校验位是串口通信中一种简单的检错方式。可以设置为偶校验或者奇校验。当然,没有校验位也可以。Arduino 默认无校验位。
停止位 每段数据帧的最后都有停止位表示该段数据帧传输结束。停止位总为高电平,可以设置停止位为1位或2位。Arduino默认是1位停止位。当串口通信速率较高或外部干扰较大时,可能会出现数据丢失的情况。为了保证数据传输的稳定性,最简单的方式就是降低通信波特率或增加停止位和校验位。在Arduino中,可以通过 Serial.begin(speed,config) 语句配置串口通信的数据位、停止位和校验位参数。
  • (3)硬件串口通信:
  • 硬件串口的操作类为HardwareSerial,定义于 HardwareSerial.h 源文件中,并对用户公开声明了Serial对象,用户在Arduino程序中直接调用Serial, 就可实现串口通讯。常用的成员函数如下:
Serial类 功能描述 语法 参数 返回值
begin() 初始化串口,通常置于setup()函数中,该函数可配置串口的各项参数。 Serial.begin(speed);Serial.begin(speed, config); speed:波特率,一般取值9600,115200等。config:设置数据位、校验位和停止位。例如Serial. begin(9600 , SERIAL _8E2) 语句设置串口波特率为9600,数据位为8,偶校验,停止位为2。
end() 结束串口通信,该操作可以释放该串口所在的数字引脚,此时串口Rx和Tx可以作为数字IO引脚使用。 Serial.end();
available() 判断串口缓冲区的状态,获取串口接收到的数据个数,即获取串口接收缓冲区中的字节数。接收缓冲区最多可保存64B的数据。 Serial.available(); 可读取的字节数
print() 串口输出数据,写入字符数据到串口。将数据输出到串口。数据会以ASCII码形式输出。如果想以字节形式输出数据,则需要使用 write() 函数。 Serial.print(val);Serial.print(val, format); val:需要输出的数据,任意数据类型。format:输出的数据格式。BIN(二进制)、OCT(八进制)、DEC(十进制)、HEX(十六进制)。对于浮点数,此参数指定要使用的小数位数(默认输出2位)。 返回输出的字节数
println() 将数据输出到串口,并回车换行。数据会以ASCII码形式输出。 Serial.println(val);Serial.println(val, format); val:需要输出的数据,任意数据类型。format:输出的数据格式。和 Serial.print(val) 和相同。 返回输出的字节数
readBytes() 从接收缓冲区读取指定长度的字符,并将其存人一个数组中。若等待数据时间超过设定的超时时间,则退出该函数。 Serial.readBytes(buffer, length); buffer:用于存储数据的数组(char[]或者byte[])。length:需要读取的字符长度。 读到的字节数;如果没有找到有效的数据,则返回0。
peek() 返回1字节的数据,但不会从接收缓冲区删除该数据。与read()函数不同,read()函数读取数据后,会从接收缓冲区删除该数据。 Serial. peek(); 进入接收缓冲区的第1字节的数据;如果没有可读数据,则返回-1。
write() 输出数据到串口。以字节形式输出到串口。 Serial. write(val);Serial. write(str);Serial. write(buf, len); val:发送的数据。str:String型的数据。.buf:数组型的数据。len:缓冲区的长度。 输出的字节数
read() 读取串口数据,一次读一个字符,读完后删除已读数据。 Serial.read(); 返回串口缓存区中第一个可读字节,当没有可读数据时返回-1。
readString() 每次读取一个字符串,程序不知道什么时候能够读取完整的字符串,会默认系统等待1s的时间 serial.readString() String
readStringUntil() 每次读取一个字符串,知道遇到截至字符,比如:Serial.readStringUntil(‘,’):程序遇到逗号就不读取串口中的内容了,系统也不会等待,所以你只需要把你要传达的命令放在逗号之前就可以了,相当于给系统一个明确的提示,花费的时间与read()不相上下,但是又能成功读取到字符串。 serial.readStringUntil(inByte) inByte (int) 指定用于标记数据结束的字符 String
  • 本文未涉及软件模拟串口通信,所以软串口操作类SoftwareSerial暂不介绍。

三、串口通信实验

1、上位机控制LED灯

  • (1)本实验采用Arduino UNO R3开发板D13引脚对应的LED及Arduino软件自带的串口调试助手,实现预设功能。
  • (2)实现功能:
  • ① 串口发送 " led_on() " 点亮LED,单片机返回一次" ON ";
  • ② 串口发送 " led_off() " 熄灭LED,单片机返回一次" OFF ";
  • ③ 串口发送 " led_flash(x) " 使LED闪烁x次,单片机返回一次" OK "。

代码实现:

//串口通信实验
//串口助手发送"led_on()"点亮LED,发送"led_off()"熄灭LED,发送led_flash(x)使LED闪烁x次,单片机收到指令后并执行后返回"OK"
//x范围任意

int led = 13;

String myString = ""; //接收串口发送过来的值

String short_String = ""; //存储myString截取后的字符串

String xstr = ""; //存储led_flash(x)的字符串x

String Control_LED[] = {
    "led_on()", "led_off()", "led_flash(x)"}; //定义字符串数组

int x = 0;//存储led_flash(x)的整数x

void setup()
{
    
  pinMode(led, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
    
  if (Serial.available() > 0)//如果串口有数据
  {
    
    myString = Serial.readStringUntil('\n');//读取字符串
    short_String = myString.substring(0, 8);//截取输入字符串myString的前8位字符
    Control_LED[0] = Control_LED[0].substring(0, 8);//截取字符串Control_LED[0]的前8位字符
    Control_LED[1] = Control_LED[1].substring(0, 8);//截取字符串Control_LED[1]的前8位字符
    Control_LED[2] = Control_LED[2].substring(0, 8);//截取字符串Control_LED[2]的前8位字符

    if (myString.length() > 10)
    {
    
      xstr = myString.substring(10, myString.length() - 1) ; //提取灯的闪烁次数xstr字符串
      x = xstr.toInt();//将字符串xstr转成数字x
    }

    if (short_String.compareTo(Control_LED[0]) == 0)//比较short_String和截取后led_on()是否相同
    {
    
      Serial.println("ON");
      digitalWrite(led, HIGH);
    }
    else if (short_String.compareTo(Control_LED[1]) == 0)//比较short_String和截取后led_off()是否相同
    {
    
      Serial.println("OFF");
      digitalWrite(led, LOW);
    }
    else if (short_String.compareTo(Control_LED[2]) == 0 ) //比较short_String和截取后led_flash(x)是否相同
    {
    
      Serial.println("OK");

      while (x > 0)
      {
    
        x--;//x为灯的闪烁次数
        digitalWrite(led, HIGH);
        delay(500);
        digitalWrite(led, LOW);
        delay(500);
      }
    }
  }
}
  • (3)实现现象(部分展示):
    在这里插入图片描述
  • 注意:红色箭头标注的LED灯,对应D13引脚。

2、上位机实现按键检测

  • (1)本实验采用Arduino UNO R3开发板及自主搭建电路的方式,实现预设功能。

  • (2)上位机实现按键检测的电路图,如下图所示:

在这里插入图片描述

  • (3)实现功能:串口发送 " read_key() " 读取按键状态,如果按键的IO口为高电平,返回一次 " key=1 " ;如果为低电平,返回一次 " key=0 " 。

代码实现:

//串口通信实验
//串口助手发送"read_key()"读取按键状态,如果按键的IO口为高电平返回"key=1",如果为低电平返回"key=0"
//按下只返回一次"key=0",松开只返回一次"key=1"

int KEY = 8;
bool flag = 0;
String myString = ""; //接收串口发送过来的值
String KEY_String = "read_key()";//定义字符串

void setup() {
    
  pinMode(KEY, INPUT_PULLUP);
  Serial.begin(9600);
}
void loop()
{
    
  if (Serial.available() > 0)//如果串口有数据
  {
    
    myString = Serial.readStringUntil('\n');//读取字符串
  }

  if (myString.compareTo(KEY_String) == 0)//比较myString和"read_key()"是否相同
  {
    
    if (digitalRead(KEY) == LOW)        //有按键按下
    {
    
      delay(10);                        //延时去抖动
      if (digitalRead(KEY) == LOW)      //有按键按下
      {
    
        if (flag == 1)
        {
    
          flag = 0;
          Serial.println("key = 0");//有按键按下,IO口为低电平,打印"key = 0"
        }
      }
    }
    else
    {
    
      if (flag == 0)
      {
    
        flag = 1;
        Serial.println("key = 1");//没有按键按下,IO口为高电平,打印"key = 1"
      }
    }
  }
}

  • (4)实现现象(部分展示):
    在这里插入图片描述
  • 现象说明:串口发送 " read_key() " ,单片机返回 " key=1 ",按下按键,单片机返回 " key=0 ",松开按键,单片机返回 " key=1 "。

参考资料1: Arduino String()用法及代码示例
参考资料2: Arduino - 字符串( Strings)
参考资料3: Arduino字符串操作函数
参考资料4: Arduino基础篇(五)-- 如何快速上手串口通信(Serial)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44887565/article/details/133071202

智能推荐

[ADAS预研笔记]感知模型的训练与部署 - 结合TDA4 SDK_adas 算法部署-程序员宅基地

文章浏览阅读738次,点赞2次,收藏12次。预训练和微调都在PC端进行,根据需求选择合适的深度学习框架,如Caffe、PyTorch、TensorFlow等。就是指预先训练的一个模型或者指预先训练模型的过程;就是指将预训练过的模型作用于自己的数据集,并使参数适应自己数据集的过程。在 CNN 领域中,实际上,很少人自己从头训练一个 CNN 网络。主要原因是自己很小的概率会拥有足够大的数据集,基本是几百或者几千张,不像 ImageNet 有 120 万张图片这样的规模。拥有的数据集不够大,而又想使用很好的模型的话,很容易会造成过拟合。_adas 算法部署

关于卷积填充和步长等计算_人工智能卷积神经网络卷积扫描填充公式-程序员宅基地

文章浏览阅读1.2w次,点赞12次,收藏27次。4.1卷积神经网络1.4Padding 一张6∗6大小的图片,使用3∗3的卷积核设定步长为1,经过卷积操作后得到一个4∗4的图像。 特征图大小公式 设定原始图像大小为n∗n,卷积核大小为f∗f,则经过卷积操作后特征图大小为(n−f+1)∗(n−f+1) 不使用Padding的缺点 经过卷积操作后图像会缩小. 如果你注意角落边的像素,则此像素点只会被卷积核触..._人工智能卷积神经网络卷积扫描填充公式

String字符串分割的3种方法 Java_string切割字符串-程序员宅基地

文章浏览阅读2.8w次,点赞5次,收藏33次。String字符串分割的3种方法 Java_string切割字符串

倾斜摄影的单体化建模研究 和osg 关系_倾斜摄影上叠加单体化数据-程序员宅基地

文章浏览阅读1.3k次。针对倾斜摄影模型“一张皮”,无法对目标进行单独操作和管理的问题,归纳总结了3种倾斜摄影单体化方法,并将分析结果进行对比,运用于实际生产中。_倾斜摄影上叠加单体化数据

Zabbix服务器监控基本应用详解(一)-程序员宅基地

文章浏览阅读78次。原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://gzsamlee.blog.51cto.com/9976612/1865381 Zabbix基本概述:Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方..._zabbix 各个服务的具体作用,数据怎么接收发送

视频教程-Docker入门与进阶实战(基于Java,通俗易懂,附源码)-Java-程序员宅基地

文章浏览阅读214次。Docker入门与进阶实战(基于Java,通俗易懂,附源码) 拥有8年JAV..._java基础进阶 docker入门 实战

随便推点

jsp/servlet/struts/hibernate/spring内部实现机制_spring + hibernate + jsp-程序员宅基地

文章浏览阅读1.3k次。http://blog.csdn.net/wishfly/article/details/8574564目录(?)[+]jsp原理一、JSP工作原理JSP程序需要运行于特定的Web服务器中,例如Tomcat/WebLogic等。所有JSP文件,在执行的时候都会被服务器端的JSP引擎转换为Servlet程序(Java源文件),然后调用Java编译器将S_spring + hibernate + jsp

选择开发操作系统的编程工具_选择开发系统的工具-程序员宅基地

文章浏览阅读1k次。选择开发操作系统的编程工具编程语言编程平台16位编程工具16位C语言编译器 - Borland C/C++ 3.116位汇编语言编译器 - MASM32 v1132位编程工具代码编辑器 - Visual Studio Community 201932位C语言编译器 - Visual Studio Community 201932位汇编语言编译器 - Visual Studio Community ..._选择开发系统的工具

安全套接层Secure Sockets Layer,SSL_netscape’ s secure sockets layers-程序员宅基地

文章浏览阅读2.5k次。http://zh.wikipedia.org/wiki/%E5%AE%89%E5%85%A8%E5%A5%97%E6%8E%A5%E5%B1%82安全套接层(Secure SocketsLayer,SSL)是一种安全协议,在網景公司(Netscape)推出首版Web浏览器的同时提出,目的是为网络通信提供安全及数据完整性保障,SSL在传输层中对网络通信进行加密。SSL采用公开密钥技术,_netscape’ s secure sockets layers

Oracle Easy Connect Naming method-程序员宅基地

文章浏览阅读356次。在Oracle 10g中,Oracle还提供了一种称为“Oracle Easy Connect Naming method"的连接方式。这种方法是对hostnaming method的一种改进,因为hostnaming meth..._oracle naming methods

桁架工业机器人编程_一小时能搞定的可编程工业机器人 丹麦协作机器人优傲发力中国...-程序员宅基地

文章浏览阅读208次。IT时报见习记者 陶泳“来来,机器往下一点,再加入一个编程命令就可以完成整套设计了。”6月4日下午,优傲机器人位于上海南京西路的办公室里,一群毫无AI基础的记者们在短短一个小时的培训后都“变身”编程高手,在一个类似平板电脑的操作台上进行简单操作之后,一个个像人类手臂一样的协作机器人便可以根据指令完成类似搬运物品等各种操作。如此简单的操作,正是北汽李尔选择优傲机器人(Universal Robots..._协作机器人编程方法

glibc 小白指南_pkuseg glibc-程序员宅基地

文章浏览阅读1.6k次,点赞2次,收藏9次。欢迎来到glibc教程!本教程将介绍glibc (GNU C Library) 的基础知识和使用方法。glibc是一个标准的C语言库,用于GNU操作系统和其他类Unix系统,它提供了大量的基础函数和例程,对于大多数C程序的正确运行是必不可少的。让我们开始吧!_pkuseg glibc

推荐文章

热门文章

相关标签