STM32与Linux串口双向通信

news/2024/10/12 6:21:21

STM32 与 linux 双向串口通信实验

       本文记录STM32 与 linux 双向串口通信,包含stm32发送、Linux阻塞式接收;Linux发送,STM32阻塞式接收;本实验的目的在于调通数据链路,为之后使用奠定基础。
实验平台为:
       STM32方面用的是STM32H723ZGT6为核心的开发板;开发环境为 VSCode + AC5编译器,调试器用的是STLINK-V2;
       Linux方面:用的是luckfox的RV1106-G3为核心的开发板;开发环境为window环境下的Clion+交叉编译器,linux为Ubuntu22.04虚拟机,使用ADB将编译后的程序发送到linux开发板;

STM32 向 Linux 串口发送数据

       STM32方面代码使用CubuMx生成,串口基本参数为:
      1.波特率:115200;
      2.数据宽度为8bits;
      3.无停止位;
      4.无奇偶校验位;
      5.一个停止位;
      初始化方面代码比较简单,故不放了,放一张CubeMx的配置截图:

      发送代码在main的while循环中,代码逻辑为:每隔500ms发送一次数据,发送10次数据后发送"exit",使Linux端退出阻塞式接收,代码如下:

  uint8_t TransTemp[] = {"receiveTemp"};while (1){/* Transmit data code*/for(int i=0; i<10; i++){HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);    HAL_UART_Transmit(&huart2, TransTemp, sizeof(TransTemp), 0xffff);HAL_Delay(500);}HAL_UART_Transmit(&huart2, "exit", 4, 0xffff);}

      Linux方面:如果没有开启串口,需要在设备数中开启串口,开启过程可以见Luckfox的wiki:https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-UART#5修改设备树
      Linux方面串口配置和接收逻辑直接由代码配置,代码逻辑为:首先以打开UART3,对其进行基本配置,配置完成后进入阻塞式接收程序,串口一直接收数据并打印,若一段时间未接收到数据则打印Timeout,开始下一轮接收;直到接收到"exit"数据,退出接收,关闭串口。程序如下:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
int main() {int serial_port_num=3;char serial_port[15];sprintf(serial_port,"/dev/ttyS%d",serial_port_num);int serial_fd;serial_fd = open(serial_port, O_RDWR | O_NOCTTY);if (serial_fd == -1) {perror("Failed to open serial port");return 1;}struct termios tty;memset(&tty, 0, sizeof(tty));if (tcgetattr(serial_fd, &tty) != 0) {perror("Error from tcgetattr");return 1;}cfsetospeed(&tty, B115200);cfsetispeed(&tty, B115200);tty.c_cflag &= ~PARENB; // NO parity bittty.c_cflag &= ~CSTOPB; // 1 stop bittty.c_cflag &= ~CSIZE;  // clear transimit bittty.c_cflag |= CS8;     // set data bits to 8 bitstty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines// Set input mode (non-canonical, no echo,...)tty.c_lflag &= ~ICANON;tty.c_lflag &= ~ECHO;// Set output mode (no post-processing)tty.c_oflag &= ~OPOST;      // no post-processiing means that out row data// Set timeout to 1 secondtty.c_cc[VTIME] = 1;    // inter-character timer unusedtty.c_cc[VMIN] = 1;     // wait for up to 1 second for 1 byteif (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {perror("Error from tcsetattr");return 1;}/* Receive data in block mode! */char rx_buffer[16] = {};int bytes_read;// 主循环while (1) {memset(rx_buffer, 0, sizeof(rx_buffer)); // 清空缓冲区bytes_read = read(serial_fd, rx_buffer, sizeof(rx_buffer) - 1);if (bytes_read > 0) {rx_buffer[bytes_read] = '\0'; // 添加字符串结束符printf("\rrx_buffer: %s\n", rx_buffer);} else if (bytes_read == 0) {printf("No data received.\n");} else {if (errno == EAGAIN || errno == EWOULDBLOCK) {printf("Timeout occurred.\n");} else {perror("Error reading from serial port");}}// 检查是否接收到 "exit" 以退出循环if (strncmp(rx_buffer, "exit", 4) == 0) {break;}}close(serial_fd);return 0;
}

      实验现象见图,在Linux端可以一直接收到数据,直到STM32端exit数据发送。

      可以看到最后一个数据为"exitreceiveTemp"这是为什么呢?
从STM32端的代码可以发现:

      这两个发送间距很快,因此接收端认为其是一次发送;

Linux 向 STM32 串口发送数据

      发送完成后,接收就大同小异,STM32方面代码较为简单,逻辑为:阻塞式接收,通过判断接收首位是否为0及字符'\0',判断是否接收到数据,若接收到数据则printf出来,代码如下:

  uint8_t ReceiveTemp[11] = {};while (1){/* Receive data code */memset(ReceiveTemp, 0, sizeof(ReceiveTemp));HAL_UART_Receive(&huart2, ReceiveTemp, 11, 0xffff);if(ReceiveTemp[0] != 0){printf("Receive data:%s\n", ReceiveTemp);}HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);}

      Linux方面,只需将接收部分换成发送即可,代码逻辑为:定时发送。代码如下:

   /* Transmit data in 1s intervals */char tx_buffer[] = {"0123456789"};while(1){ssize_t bytes_written = write(serial_fd, tx_buffer, sizeof(tx_buffer));if(bytes_written != sizeof(tx_buffer)){fprintf(stderr, "Filed to send all data. Sent %zd out of %zu bytes.\n",bytes_written, sizeof(tx_buffer));}else{printf("Data send successfully.Data len is:%d\n", bytes_written);}sleep(1);}

实验现象为:
      Linux方面:每发送成功一次则打印一次;

STM32方面:每接收成功一次则将接收结果打印出来;

总结

      本文实现了STM32 与 Linux平台的串口双向阻塞式通讯,根据实验效果验证效果可行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/53397.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Java基础-学习笔记14

Collection、Map 类实现14 集合 Collection、Map 第一部分 Collection的框架体系 1) 可以动态保存任意多个对象,使用比较方便 2) 提供了一系列方便的操作对象的方法:add、remove、set、get等 3) 使用集合添加、删除新元素简单便捷。 集合 Collection 主要是两组:单列集合…

Apache SeaTunnel技术架构演进及其在AI领域的应用

随着数据集成需求的增长,Apache SeaTunnel作为新一代的数据同步引擎,不仅在技术架构上不断演进,也在AI领域展现出其独特的应用价值。在CommunityOverCode Asia 2024大会上,Apache SeaTunnel PMC Chair 高俊 深入探讨SeaTunnel的技术演进路径,分析其在AI领域的应用案例,并…

Windows 系统 局域网文件夹共享无法访问的终极解决方法

先介绍 Win10 无法访问其他电脑的解决方法首先,Win10 能成功访问共享文件夹,必须有安装 SMB1 协议,否则会提示找不到网络名称的提示。 方法很简单,点击 微软小娜 Cortana 输入 启用或关闭 Windows 功能(或者直接输入 功能 也能找到),打开 启用或关闭 Windows 功能 对话框…

使用 updateAppConfig 更新 Nuxt 应用配置

title: 使用 updateAppConfig 更新 Nuxt 应用配置 date: 2024/8/27 updated: 2024/8/27 author: cmdragon excerpt: 通过使用 updateAppConfig,你可以轻松地在应用运行时更新配置,而无需重新启动应用。这对于需要在运行时调整设置的应用场景非常有用。 categories:前端开发…

AtCoder Beginner Contest 051

A - Haiku 直接模拟。 #include <bits/stdc++.h>using namespace std; using i64 = long long;int main() {ios::sync_with_stdio(false), cin.tie(nullptr);string s;cin >> s;string a, b, c;a = s.substr(0, 5);b = s.substr(6, 7);c = s.substr(14);cout <&…

PEP 508:为不同版本Python指定不同依赖

如果使用Python第三方包的某一个版本有问题,而不同版本Python所对应的软件最新版本又不一致,这种情况下如何在requirements.txt文件中指定软件最高版本是非常重要的。这里根据PEP 508的规范,做了一个Numpy版本要求numpy<=1.21.6 || 1.28>numpy>=1.23的示例。问题背…

经验分享|如何发现并利用信息泄露漏洞?

信息泄露漏洞是发现和报告的重要目标。虽然它们可能不会带来很丰厚的回报,但发现它们表明Web应用程序的安全性较差,这可能有助于发现更严重的漏洞。 一、常见的信息泄露漏洞类型 1.1服务器标识版本 服务器标识版本能够揭示服务器上运行的特定软件及其版本,这可以被用来寻找已…

简单萌萌哒 Top Tree(上)

前情提要。 Top Cluster 分解与 Top Tree 情景导入 我们总是想要以一种合适的方式对树进行划分,但是对于菊花图而言,基于点的划分总是不合适的,这启发我们基于边进行划分。事实上可以证明,基于边的划分总是可行的。 Top Cluster 分解就是一种基于边的划分方式,下面我们来介…