Arduino串口通信

2023-10-26

通信类型

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

image-20200925105403249

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);
  }
}

实验现象:

实验2:

/**
 * 通过串口改变Arduino 9号针脚接的LED灯的亮度
 */

int i,j,val; //定义i、j、val三个整型变量
char A[10];  //定义一个无符号数组A

void 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的串口接线如下:

image-20200925214505843

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

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

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

首先,右侧中步骤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 <SoftwareSerial.h> 

//定义管脚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菜鸟通俗版解读系列(4)串口通信USART

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Arduino串口通信 的相关文章

  • VSCode 上的 PlatformIO 未编译:collect2.exe:错误:ld 返回 1 退出状态

    我最近不得不擦拭我的计算机 在一切准备就绪并运行之后 是时候打开我之前正在处理的一些 ESP32 程序了 发现 VSCode 上的 Platform IO 将不再编译 运行编译器后 我收到以下错误 Compiling pio build e
  • Arduino F()宏的实现

    我试图了解 Arduino 中的 F 宏实际上对 PGMEM 和 RAM 做了什么以及运行时的影响是什么 有人可以指出定义这个宏的文件吗 这可能是旧版本 但定义它的一个地方是Wstring h as in here http andybro
  • C++ 递减单字节(易失性)数组的元素不是原子的!为什么? (另外:如何在 Atmel AVR mcus/Arduino 中强制原子性)

    由于试图通过一些我不知道的简单内容来调试我的代码 我损失了几天的时间 实际上是大约 25 小时的工作 事实证明 在 AVR ATmega328 8 位微控制器 Arduino 上 用 C 递减单字节数组的元素不是原子操作 并且需要原子访问防
  • Arduino:字符串到整数得到奇怪的值

    我想转换一个String to an int 我所能找到的就是你必须将 String 转换为 char 数组 然后将该数组转换为int 但我的代码产生奇怪的值 我无法弄清楚问题是什么 void ledDimm String command
  • printf 的包装

    我在Arduino下编码 我想开发串行打印格式化功能 所以我尝试使用sprintf未知大小的缓冲区 基本上 我们可以避免谈论 Arduino 及其串行输出 并考虑将文本写入缓冲区 然后使用printf 我试过这个 include
  • 如何将 char 数组定义为常量?

    这里是 C C 菜鸟 我已经在头文件中定义了它 typedef unsigned char BitChar 9 8 data bytes chars and one width byte char extern BitChar BitFon
  • 如何将 ASCII char 转换为其 ASCII int 值?

    我想将 char 转换为它的ASCII http en wikipedia org wiki ASCIIint 值 我可以用所有可能的值填充一个数组并与其进行比较 但这对我来说似乎不正确 我想要类似的东西 char mychar k pub
  • sim800L GPRS 发布请求

    我一直在研究 LoNet 迷你 GSM 模块 SIM800L 并将其与 Arduino 连接 我已插入 SIM 移动卡并且可以连接互联网 通过串行监视器 我可以毫无问题地与它通信 但是当向网络服务器页面发出 GET 或 POST 请求时 它
  • C++ Linux (Ubuntu) 正确写入串行(对于 Arduino)

    我想知道是否有一种标准方法可以与高效的串行设备进行通信 我应该使用标准库吗 如果有 是哪一个 现在我正在摆弄让 LED 根据输入的数字以给定的量亮起 Arduino 代码如下 只是练习一些东西 看我过于简单且低效的测试 include
  • ESP32 Arduino-ide如何获取唯一id

    我试图自动为每个 esp32 设置一个唯一的 id 在我使用提供该方法的 ESP IDF 框架对设备进行编程之前esp efuse mac get default 这将返回一个 8 字节值 该值在我手上的所有设备上都是唯一的 在arduin
  • 在Python中快速绘制数据

    我正在尝试使用 arduino 绘制来自 mpu6050 imu 的数据 MPU6050 发送数据的速度比绘图快 Arduino 代码从串口提供 6 个数据 即偏航 俯仰 滚动 轴 ay 和 az 我需要快速情节的建议 Python代码 i
  • 为什么使用 libnfc 和 PN532 SHIELD 时“找不到 NFC 设备”

    我在 ArchLinux 上安装了 libnfc 并通过我的 Adafruit PN532 arduino SHIELD 使用它 nfc list返回消息 未找到 NFC 设备 我在 etc nfc devices d pn532 conf
  • Arduino:连接字符串时崩溃和错误

    我尝试将 AES 256 加密的输出连接到一个字符串 将此字符串与从 Android 手机发送的加密字符串进行比较 基本上 连接似乎有效 但在几次运行后会出现错误 不可读的字符 字符串变得更短而不是更长 或崩溃 它是可重现的 重启后在同一点
  • 如何为 Arduino 或类似的微控制器编写 JavaScript 编译器? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我意识到这个问题会引起一些人的注意 并且我意识到 JavaScript 传统上是一种解释性语言 请让我解释一下 我是一名专门从事 We
  • 使用 SPIFFS 加载文件时出现问题 (ERR_CONTENT_LENGTH_MISMATCH)

    好吧 这两天我一直在研究这个问题 但我仍然觉得我一无所获 我最近开始使用SPIFFS 文件系统 for Arduino开发于呼扎 ESP8266像FSBrowser ino例如 虽然它在分离代码方面非常出色 但随着我的代码不断增长 它在稳定
  • 在 Arduino 上将整数/小数转换为十六进制?

    如何将整数或小数变量转换为十六进制字符串 我可以做相反的事情 将十六进制转换为整数 但我无法找出其他方法 这是为了Serial print 数组中的十六进制值 查看 Arduino 字符串教程here http arduino cc en
  • 从 iBeacon 接收 BLE 信号到 Bluno(arduino with BLE)

    我想从 iBeacon 到 Bluno 接收 rssi 信号和 UUID Arduino 板具有 BLE 对此有一些疑问 有没有从 BLE 到 BLE 接收 UUID 和 rssi 的解决方案 两个BLE设备可以互相通信吗 我想找一些网站来
  • Arduino串口数据解析

    我正在编写一个应用程序 通过蓝牙用我的 Android 手机控制我的机器人 一切都很顺利 数据得到回显和验证 但我在协议方面遇到了一些问题 特别是我希望我的机器人的轮子在我发送时转动一个命令 例如s 10 100 or s 30 10 数值
  • 如何使用基于HM-10蓝牙模块的BLE Shield?

    我是 arduino 项目的新手 我想请你帮忙 我从 http imall iteadstudio com development platform arduino shields im130704001 html http imall i
  • 仅从日期计算夏令时

    我正在使用 Arduino 和实时时钟芯片 该芯片补偿了闰年等 因此它始终具有正确的日期 但我认为由于区域复杂性 它不处理夏令时 时钟可以给出日 月 年 从 1 开始 以及星期几 星期日 0 到星期六 6 因为我需要与用户输入的日期和时间进

随机推荐

  • 详解Java中的BIO、NIO、AIO

    1 详解Java中的BIO NIO AIO 1 1 引言 IO流是Java中比较难理解的一个知识点 但是IO流在实际的开发场景中经常会使用到 比如Dubbo底层就是NIO进行通讯 本文将介绍Java发展过程中出现的三种IO BIO NIO以
  • 渗透测试笔记(五)——XSS跨站脚本攻击

    XSS简介 XSS Cross Site Scripting 跨站脚本 为了避免与CSS混淆 所以简称XSS XSS是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点 进而添加一些代码 嵌入到Web页面中去 使别的用户访
  • 会话追踪技术:cookie、 URL重写

    servlet day4 会话追踪技术 cookie http协议的访问是无状态的访问 当前访问是不会知道之前访问的状态的 http协议的访问是不会帮我们保存访问的记录 痕迹的 有些时候需要记录之前的访问状态 比如在购物网站的时候 第一次访
  • 多线程与高并发编程进阶(二)

    前言 前文多线程与高并发入门中 已经介绍了多线程编程的目的以及实际应用中可能会遇到的问题 本文接着叙述关于多线程并发机制的底层原理 volatile以及synchronized 一般来说 Java代码从编写到最后的执行会经历以下的过程 Ja
  • 二叉树的基本操作(1)

    结点类型 struct TreeNode char val struct TreeNode l r TreeNode int x val x l nullptr r nullptr 新建一个类 名为solution 相关函数都放在这里面调用
  • 分类预测

    分类预测 MATLAB实现LSSVM 最小二乘支持向量机 分类 目录 分类预测 MATLAB实现LSSVM 最小二乘支持向量机 分类 最小二乘法 最小二乘支持向量机 程序设计 主程序 子程序 拓展知识 参考资料 致谢 最小二乘法 最小二乘法
  • 利用python实现163邮箱邮件的自动删除

    问题 163邮箱收信箱大量邮件无法批量删除 解决思路 利用python控制鼠标实现邮件自动删除 利用python的pyautogui实现鼠标的控制 import pyautogui as pg screenWidth screenHeigh
  • 海洋浮标数据显示系统

    R语言是现今世界上数据处理和可视化领域非常流行的数据处理语言 其类似于matlab 是开源的 功能强大的数据处理工具 Oracle是企业级的数据库 能够存储大量数据并且方便管理和使用 本文主要是基于R与oracle对美国国家海洋与大气管理局
  • 老师给我的指点——深刻剖析了我

    今天上午找导师有事 导师坐下来和我聊了聊 他说 就他的观察 我有以下几个方面的问题 一 感觉我在做事上总是欠缺那么一点东西 就是说 给我的事情 我是能做完也让别人没法批评我 但是总感觉欠缺一点东西 相比师妹 每次给任务1分可以做完1 2分
  • 函数式编程实例WordCount(林子雨老师慕课代码) 由于文件引入的问题之前报过Exception in thread “main“ java.lang.NullPointerExcept(已解决)

    函数式编程实例WordCount 数据文件目录 文件内容 刚开始在写文件的时候以为val dirfile new File data 这一行写的是具体文件 于是我写成了这样 运行之后始终给我报空指针异常 后面仔细研究文件 原来val dir
  • Linux 系统启动过程

    简介 Linux 系统启动过程大致分为5个阶段 1 内核的引导 2 运行 init 3 系统初始化 4 建立终端 5 用户登录系统 内核引导 计算机通电后 首先会进行 BIOS 开机自检 然后根据BIOS中设置的启动设备 一般是硬盘 来启动
  • Go开发 之 单端口转发到多个端口

    文章目录 1 背景 2 正题 3 源码 4 配置 5 效果 1 背景 运维和我提到这个需求的时候 我先是一愣 第一时间想到的是nginx 然后运维说nginx没有这个功能 之所以选择用go语言 主要两点 静态语言性能够用 不用部署其它包 可
  • 【linux操作系统知识】虚拟地址中:.data段和.bss段

    虚拟地址中 data段和 bss段 data段 为数据段 用来存放程序中已初始化并且初始化不为0的全局变量和静态局部变量 数据段属于静态内存分布 可读可写 bss段 称为未初始化段 用来存放未初始化或者初始化为0的全局变量和静态局部变量 b
  • MATLAB数据分析

    MATLAB数据分析 在实际应用中 经常需要对各种数据进行统计处理 以便为科学决策提供依据 这些统计处理包括求数据序列的最大值和最小值 和与积 平均值和中值 累加和与累乘积 标准方差和相关系数 排序等 MATLAB提供了相关的函数来实现 目
  • flutter实现可缩放可拖拽双击放大的图片功能

    flutter drag scale 可缩放可拖拽的功能 可实现图片或者其他widget的缩放已经拖拽 并支持双击放大的功能 我们知道官方提供了双击缩放 但是不支持拖拽的功能 我们要实现向百度地图那样可以缩放又可以拖拽的功能 官方的方法就不
  • unicloud 发布后小程序提示连接本地调试服务失败,请检查客户端是否和主机在同一局域网下

    1 hbuildx中小程序控制台切换连接方式 连接云端云函数 2 本地调试的话 连接本地云函数 并确定是否启动
  • 在eclipse的project explorer不小心删除了servers文件夹解决办法

    在eclipse的project explorer不小心删除了servers文件夹 解决办法 在Servers中删除tomcat 重新关联link一下就恢复了 但是得把build path的旧的server文件夹remove 再重新添加
  • 我们研究了853场世界杯比赛,发现了这几条稳赔不赚的竞猜攻略

    本文转载自大数据 ID hzdashuju 导读 世界杯开赛以来 据数据叔不完全统计 身边有66 6 的小伙伴上了天台 其中22 2 的人买了阿根廷赢 22 2 的人买了德国赢 还有22 2 的人买了巴西赢 剩下那33 4 的人 总是在问数
  • Unity性能优化

    Unity性能优化专栏第一期 目录 Unity性能优化专栏第一期 橙子前言 一 性能优化概念 Unity 3D 游戏优化瓶颈归根结底是开发过程中内存分配和使用不佳的结果 1 它们承担了它们这个级别不应该有的压力 2 它们没有受到应有的尊重
  • Arduino串口通信

    文章目录 通信类型 Arduino串口通信 硬串口 软串口 通信类型 通信是用来在不同电子设备之间交换数据用的技术 其实就是要实现不同电子设备之间的 通讯对话 Arduino串口通信 Arduino采用USART通信模式 可以有硬串口 软串