STM32与Linux串口双向通信

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.hqwc.cn/news/787898.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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 分解就是一种基于边的划分方式,下面我们来介…

手把手教你—搭建Vue3企业级项目规范+基础封装配置

前言 如何搭建一个简易脚手架。核心需求是输入项目命令,clone准备好的项目模板,拉到本地后,装一下依赖,就可以直接开发了。不用每次都花大量时间,去搭建项目规范和做必要的封装配置。 经过简单寻找后,发现没有符合自己预期的。于是大雄从0到1搭建一个具备完善规范的Vue3开…

WPF 模板

一、数据模板继承了ItemConrol的控件对象(如ListView、ListBox、DataGrid、TabControl等等),都可以使用数据模板DataTemplate。 数据模板的作用在于决定每个Item中的数据的展示形式。 普通控件通过Template属性来定义模板,而子项容器控件则通过ItemTemplate属性来定义子项模…

算法与数据结构——队列

队列 队列(queue)是一种遵循先入先出规则的线性数据结构。队列模拟了排队现象,即新来的人不断加入队列尾部,而队列头部的人逐个离开。 如图所示,我们将队列头部称为“队首”,尾部称为“队尾”,将把元素加入队列尾部的操作称为“入队”,删除队首元素的操作称为“出队”。…

AD采集卡:FMC210-1路1Gsps AD、1路2.5Gsps DA的FMC子卡 信号采集卡

FMC210-1路1Gsps AD、1路2.5Gsps DA的FMC子卡 一、板卡概述FMC-1AD2DA是我司自主研发的一款1路1G AD采集、1路2.5G DA回放的FMC子卡。板卡采用标准FMC子卡架构,可方便的与其他FMC板卡实现高速互联,可广泛用于高频模拟信号采集、雷达系统测试等场合。    二、 功能介绍 2.1 …