Arduino ESP32 串口通信

1. 串口通信

1.1串口通信介绍

串口是指外设和处理器之间通过数据信号线、地线和控制线等,按位进行传输数据的一种通讯方式。尽管传输速度比并行传输低,但串口可以在使用一根线发送数据的同时用另一根线接收数据。 这种通信方式使用的数据线少,在远距离通信中可以节约通信成本。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验位,这些参数在两个通信端口之间必须一致。

1.2 串口通信参数介绍

串口通信参数包括波特率(Baud Rate)、数据位(Data Bits)、校验位(Parity Bits)、停止位(Stop Bits)等。这些参数描述了传输数据的基本规格。例如,波特率定义了数据传输的速率,数据位确定每个数据字节中包含的位数,校验位用于数据的差错检测,停止位表示数据传输结束的标志等。

  • 波特率:衡量通信速度的参数,它表示每秒钟传送的 bit 的个数。
  • 数据位:衡量通信中实际数据位的参数,表示一个信息包里包含的数据位的个数。
  • 停止位:用于表示单个信息包的最后位,典型值为 1、1.5 和 2 位。由于数据是在传输线上传输的,每个设备都有自己的时钟,很有可能在通信过程中出现不同步,停止位不仅仅表示传输的结束,还能提供校正时钟同步的机会。停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率也越慢。
  • 奇偶检验位:表示一种简单的检查错误的方式。
    关于更为详细的介绍请搜索百度。

1.3 串口工作模式

串口工作模式分为三种:单工、全双工模式和半双工模式。

  • 单工:在通信的任意时刻,信息只能由 A 传到 B,或B传到A;
  • 半双工:在通信的任意时刻,信息即可由 A 传到 B,又能由 B 传到 A,但同时只能有一个方向上的传输存在;
  • 全双工:在通信的任意时刻,通信线路上存在 A 到 B 和 B 到 A 的双向信号传输;

1.4 串口通信协议

串口通信协议定义了在串口上进行数据交换的规则和格式。常见的串口通信协议包括ASCII协议、Modbus协议、RS-232协议等。协议规定了数据的帧结构、数据格式、校验方式等,确保发送和接收双方按照相同的规则进行数据交换,从而实现数据的正确传输和解析。
串口通信是一位一位地传输,每传输一个字符总是以起始位开始,以停止位结束,字符之间没有固定的时间间隔要求。每一个字符的前面都有一位起始位(低电平),后面由 7 位数据位组成,接着是一位校验位,最后是停止位。停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平。
在这里插入图片描述

1.5 串口通信的作用及优势

串口是计算机和外部设备之间最常见的通信接口之一,具有重要的作用和广泛的应用。在计算机领域,串口的重要性体现在以下几个方面:

  1. 数据传输:串口是一种常用的数据传输接口。通过串口,计算机可以与各种外部设备进行数据交换和通信。无论是传感器、执行器、显示器、打印机还是其他外部设备,串口通信都可以实现数据的传输和控制。
  2. 远程控制和监控:串口通信被广泛应用于远程控制和监控领域。通过串口,计算机可以远程控制设备的动作,并实时监测设备的状态和数据信息。这在工业控制、自动化系统、远程监控等场景中具有重要的作用。
  3. 调试和故障排查:串口通信是调试和故障排查的重要工具。通过串口,计算机可以与嵌入式系统、单片机等进行通信,实时监控和调试程序,输出调试信息,进行错误定位和排查,并对系统进行状态监测和故障诊断。
  4. 硬件连接:串口可以作为计算机与各种外部设备之间的连接桥梁。通过串口,可以连接和控制各类外部设备,如传感器、执行器、外围设备等。串口能够提供稳定的数据传输和双向通信功能。
  5. 通信协议:串口通信协议是计算机与外部设备之间数据传输的规范和约定。通过定义不同的协议,可以实现不同设备之间的数据交互和通信。常见的串口通信协议有UART、RS-232、RS-485等。
    总之,串口对于计算机和外部设备之间的通信具有重要的作用。它是数据传输、远程控制和监控、调试和故障排查的关键工具,是计算机与外部设备连接和通信的桥梁。

1.5 串口通信驱动流程

在ESP32S3上进行串口通信时,通常需要使用相应的串口驱动程序。ESP32提供了专门的串口库(例如Arduino环境中的Serial库),简化了串口通信的使用。通常的串口通信驱动流程包括初始化串口、设置通信参数、发送数据和接收数据等步骤。具体流程根据所使用的串口库和具体需求而定。常见步骤如下:

1. 初始化串口

在 setup() 函数中添加类似如下的语句来初始化串口:
在这里插入图片描述
需要注意的是,在arduino中,ESP32的串口0为Serial,串口1为Serial1,串口2为Serial2;
如果要修改引脚以及通信参数,可以这样写:
在这里插入图片描述
定义串口的TEPIN和RXPIN,在调用Serial.begin(115200,SERIAL_8N1,RXPIN,TXPIN);初始化串口
在这里插入图片描述
SERIAL_8N1表示数据位、校验位和停止位的配置。其中,8 表示数据位为 8 位,N 表示无校验位,1 表示停止位为 1 位。这个参数用于指定串口通信的数据格式。还可以设置为其他位置,例如:

  1. SERIAL_5N1、SERIAL_6N1、SERIAL_7N1、SERIAL_8N1、SERIAL_5N2、SERIAL_6N2、SERIAL_7N2、SERIAL_8N2等:这些参数用于配置数据位、校验位和停止位的不同组合方式。
  2. SERIAL_8E1、SERIAL_8E2、SERIAL_8E1、SERIAL_8O2等:这些参数用于配置数据位为8位、校验位为偶校验或奇校验、停止位为1位或2位的组合方式。
  3. SERIAL_8N1, SERIAL_8E1, SERIAL_8O1, SERIAL_8N2, SERIAL_8E2, SERIAL_8O2等:这些参数用于配置数据位为8位、校验位为无、偶校验或奇校验、停止位为1位或2位的组合方式。
  4. SERIAL_8N2, SERIAL_8E1_RXINV, SERIAL_8E1_TXINV等:这些参数用于配置数据位为8位、校验位为无或偶校验、停止位为2位,并可以设置接收引脚(RXPIN)的反转或发送引脚(TXPIN)的反转。

2. 设置串口中断回调函数

在这里插入图片描述
Serial1.onReceive() 是一个回调函数,用于注册接收串口数据时的回调函数。当通过串口接收到数据时,注册的回调函数会被自动调用,以处理接收到的数据。
在这里插入图片描述
可以通过以下代码示例来使用 Serial1.onReceive() 函数:

//当接收到数据时,将会执行该函数
void onDataReceived() 
{
  // 处理接收到的数据
  while (Serial1.available()) 
  {
    char receivedData = Serial1.read(); // 读取接收缓冲区中的数据
    // 进行数据处理操作
  }
}

void setup() 
{
  Serial1.begin(115200); // 初始化串口1,波特率为115200
  Serial1.onReceive(onDataReceived); // 注册接收数据时的回调函数
}
void loop() 
{
  // 其他的主循环代码
}

在上述示例中,onDataReceived() 是一个自定义的函数,用于处理串口接收到的数据。在 setup() 中,通过调用 Serial1.onReceive(onDataReceived) 将 onDataReceived() 函数注册为接收数据时的回调函数。当有数据通过 Serial1 串口接收时,将自动调用 onDataReceived() 函数,并在其中进行数据处理操作。
通过使用 Serial1.onReceive() 函数,可以提供一种异步的方式处理串口接收数据,而不需要在 loop() 函数中轮询串口的可用性。这样可以更加高效地处理串口数据,并充分利用处理器的资源。
需要注意的是,Serial1.onReceive() 函数只能用于硬件串口(如 Serial1),不能用于虚拟串口(如 SoftwareSerial)。另外,在使用 Serial1.onReceive() 函数时,需要保持 loop() 函数的快速执行,以免阻塞串口数据接收的回调函数的调用。

3. 发送与接收数据

发送数据:
在初始化串口后,可以使用 Serial1.write() 或 Serial1.print() 函数向串口发送数据。例如:
在这里插入图片描述
接收数据:
在程序中,可以使用 Serial1.available() 函数来检查串口是否有可用的数据。如果有数据可用,可以使用 Serial1.read() 函数来读取串口接收缓冲区中的数据。例如:
在这里插入图片描述

1.6 串口通信验证


```c
#define RXPIN 9
#define TXPIN 10
uint8_t dataSent[100];
//接收中断回调函数
void onReceiveFunction(void) 
{
  // 接收串口1发送过来的数据长度
  size_t available = Serial1.available();
  //显示接收长度
  Serial.printf("onReceive Callback:: There are %d bytes available: ", available);
  //接收长度不为0则一直减
  while (available --) 
  {
    //通过串口0显示串口1接收到的数据
    Serial.print((char)Serial1.read());
  }
  //显示换行
  Serial.println();
}
//Serial、Serial1、Serial2 分别对应了 UART0、UART1 和 UART2。
void setup() 
{
  // 初始化串口通信波特率
  //串口0初始化
  Serial.begin(115200);
  //初始化串口1,波特率115200,SERIAL_8N1=8数据位无校验位1停止位 RX引脚为9 TX引脚为10
  Serial1.begin(115200, SERIAL_8N1, RXPIN, TXPIN); 
  //为串口1设置回调函数
  Serial1.onReceive(onReceiveFunction); 
  //串口1发送数据 hello LCKFB,发送12个字节
  Serial1.write("hello LCKFB", 12);

}
void loop() 
{
  // 从串口监视器读取输入数据
  if (Serial.available()) 
  {
    char data = Serial.read();
    // 将数据发送到 UART1
    Serial1.write(data);
  }
  // 从UART1读取输入数据
  if (Serial1.available()) 
  {
    char data = Serial1.read();
    // 将数据发送到 UART0
    Serial.write(data);
  }
}
## 1.7. 串口通信效果
开发板上电通过串口1输出"hello LCKFB",然后串口0和串口1可以互发数据。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/526a5463a67b490bb074f964216dfe67.png)








Arduino ESP32S3是一款基于ESP32芯片的微控制器板,它内置了Real-Time Clock (RTC)模块,可以提供准确的时间信息,即使在无外部电源的情况下也能保持计时。以下是一个简单的Arduino ESP32S3实时时钟示例程序,用于设置、读取和显示时间: ```cpp #include <ESP32s3.h> #include <RTClib.h> // 引入RTC库 RTC_DS1307 rtc; // 创建RTC DS1307实例 void setup() { Serial.begin(9600); // 初始化串口通信 // 如果RTC初始化失败,尝试复位 if (!rtc.begin()) { Serial.println("RTC initialization failed. Attempting reset..."); delay(500); rtc.begin(); // 再次尝试 } // 设置RTC时间 Date now; now.minute = now.hour = now.day = now.month = now.year = SystemTime(); // 使用当前系统时间 rtc.adjust(now); // 更新RTC时间 Serial.println("RTC time set to: "); Serial.print(now.year, DEC); Serial.print("-"); Serial.print(now.month, DEC); Serial.print("-"); Serial.print(now.day, DEC); Serial.print(" "); Serial.print(now.hour, DEC); Serial.print(":"); Serial.print(now.minute, DEC); } void loop() { Date currentTime = rtc.now(); // 获取当前RTC时间 Serial.print("Current RTC time: "); Serial.print(currentTime.year, DEC); Serial.print("-"); Serial.print(currentTime.month, DEC); Serial.print("-"); Serial.print(currentTime.day, DEC); Serial.print(" "); Serial.print(currentTime.hour, DEC); Serial.print(":"); Serial.print(currentTime.minute, DEC); Serial.println(); delay(1000); // 每秒更新一次时间 } ``` 在这个程序中,我们首先包含了`RTClib`库,然后创建了一个`RTC_DS1307`对象。在`setup()`函数中,我们初始化RTC并将其时间设置为系统的当前时间。`loop()`函数则持续获取并打印当前的RTC时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值