首页 > 系统相关 >STM32与Linux串口双向通信

STM32与Linux串口双向通信

时间:2024-08-27 11:14:49浏览次数:5  
标签:tty buffer 双向通信 Linux STM32 串口 serial

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 bit
    tty.c_cflag &= ~CSTOPB; // 1 stop bit
    tty.c_cflag &= ~CSIZE;  // clear transimit bit
    tty.c_cflag |= CS8;     // set data bits to 8 bits
    tty.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 second
    tty.c_cc[VTIME] = 1;    // inter-character timer unused
    tty.c_cc[VMIN] = 1;     // wait for up to 1 second for 1 byte

    if (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平台的串口双向阻塞式通讯,根据实验效果验证效果可行。

标签:tty,buffer,双向通信,Linux,STM32,串口,serial
From: https://www.cnblogs.com/muheandrabbit/p/18381596/STM32UartLinux

相关文章

  • STM32 - 按键控制LED灯
    功能:按键控制LED的亮灭。两个按键:PE3和PE2两个LED:PE5和PB5按键PE3控制LED2-PE5;按键PE2控制LED3-PB5main.c:#include"stm32f10x.h"//Deviceheader#include"Delay.h"#include"LED.h"#include"Key.h"uint8_tKeyNum;i......
  • 搭建多协议的串口服务器流程:RS-232、RS-485和TCP/IP、MQTT网络协议(代码示例)
    一、项目概述在物联网(IoT)和自动化控制的快速发展中,串口通信作为一种经典的通信方式,依然发挥着重要作用。本项目旨在构建一个支持多种协议的串口服务器,能够通过串口接收和发送数据,并通过网络协议(如TCP/IP、MQTT等)与其他设备和系统进行交互。项目的目标和用途本项目的目标......
  • stm32之I2C通信协议
    文章目录前言一、I2C通信协议二、I2C硬件电路三、I2C时序基本单元3.1起始与终止信号3.2发送与接收一个字节3.3发送与接收应答四、I2C时序分析4.1指定地址写4.2当前地址读4.3指定地址读前言提示:本文主要用作在学习江科大自化协STM32入门教程后做的归纳总结笔......
  • C#如何开发通过USB进行串口通讯的Androud上位机
    使用C#在windows上进行串口通讯应该是相当简单的,在.net里面有SerialPort类。但是假如不是windows,而是在Android上开发一个连接串口设备而进行通讯的软件?也是可以的,但是需要去了解一下.net中如何开发Android应用。一.准备通讯线一般Android手机基本都有TypeC口,首先需要一根OTG转......
  • 基于STM32F103的FreeRTOS系列(十一)·信号量·二值信号量与计数信号量详细使用以及移植
    目录1. 信号量简介1.1 同步和互斥1.1.1 同步1.1.2 互斥1.1.3 总结1.2 分类1.2.1 二值信号量1.2.2 计数信号量1.2.3 互斥信号量1.2.4 递归信号量2. 信号量控制块3. 常用信号量API函数3.1 创建信号量函数3.1.1 创建二值信号量 xSe......
  • USART之串口发送+接收应用案例
    文章目录前言一、电路接线图二、应用案例代码三、应用案例分析3.1USART模块初始化3.1.1RCC开启时钟3.1.2GPIO初始化3.1.3配置USART3.1.4开启中断、配置NVIC3.1.5开启USART3.2USART串口收发模块3.2.1Serial_SendByte(发送一个字节数据)3.2.2USART1_IRQHandler(串口......
  • C#串口读写,遇到数据粘连怎么处理
    在读取串口数据时,可能会出现"粘连"的情况,即一次读取的数据中包含了多个数据包。这通常是由于数据的传输速度和读取速度不匹配导致的。解决这种情况的常见方法有以下几种:一、使用缓冲区可以使用一个缓冲区来暂时存储读取的数据,并对缓冲区中的数据进行分析,找出完整的......
  • C#串口读写,如果是按位读取,遇到有结束符号“0D0A”16进制终止符号的时候,怎么处理,并且保
    对于串口数据存在以0D0A(回车换行)作为结束符号的情况,可以按照以下步骤设计相应的处理逻辑:一、定义数据包结构首先定义一个数据包结构,包含数据包长度和实际数据内容两个部分。示例代码:publicstructSerialPacket{publicintLength;publicbyte[]Data;......
  • STM32寄存器操作、模板构建
    目录外设寄存器查找①名称②偏移地址③寄存器位表④位功能说明寄存器基本操作C语言的置位和清零具体方法设置GPIO流程给寄存器赋值带参数宏STM32F1xx芯片识别存储器映射寄存器映射让GPIOB端口的16个引脚输出高电平,要怎么实现?STM32寄存器映射C语言对寄存器的封装新建寄......
  • STM32常用下载程序方式
    常用下载程序的两种方式:、通过下载工具(FlyMCU)将hex文件下载到FLASH存储区。、使用烧写器将xxx.axf文件下载到存储区。(KEIL5经过烧写器配置后,直接点击download)有的朋友肯定好奇说:FLASH存储区存的都是最“干净”的二进制数据,hex文件还有那么多描述信息呢。答案:hex文件当然不是......