串口通信代码的一些解释

串口(UART/USART)是单片机内部 的一个通信硬件模块,通过 TX 和 RX 引脚让设备之间以字节为单位交换数据。

UART 是一种:

  • 异步(无时钟);字符串式(按字节发送);全双工(收发独立);基于电平高低的通信协议

串口通信是"双向的",你可以同时:

  • 用 TX 把调试数据打印到电脑

  • 用 RX 让电脑发送命令给 STM32(如电脑发送:"LEDON",STM32 收到后点灯)

常见格式:起始位:1 bit(低电平) ;数据位:8 bit; 校验位:可选; 停止位:1 bit

波特率:9600 / 115200 等

串口发送

一.对比串口通信中Serial_SendXXX和Serial_Printf

串口(UART)只能发送"字节数据",不能直接发送"数字本身"。

1.串口发送的本质:只能发送 0~255 的字节

UART 的发送寄存器(USARTx->DR)每次只能发送1 个字节(8 bit)。

例如:Serial_SendByte(0x41);

串口只知道:我要发一个字节:0x41,它 不知道什么是整数 123、浮点数 3.14,它只会发出一个又一个字节。

2.C 语言里"数字"不是 ASCII 字符

例如数字:123(int 类型),它在内存里的存储是 二进制整数:0x00 0x00 0x00 0x7B

串口如果直接发这些字节,电脑会收到乱码。

但我们希望电脑串口助手看到的是:123 ,也就是字符 '1' '2' '3'

ASCII 对应是:'1' → 0x31 '2' → 0x32 '3' → 0x33

因此必须先把数字变成字符(字符串)。

Serial_SendNumber(123, 3) 会把整数 123:

1>分解成每个数字:1、2、3

2>把每个数字+0x30 转成 ASCII

3>再通过串口一个一个发出去

最终电脑看到:123

3.如果不转换成字符串,会发生什么?

例如直接发 int 类型:int a = 123;

Serial_SendByte(a); // 错误示例

实际发送的是 0x7B(也就是 123 的低 8 位),终端只会看到乱码或一个不可打印字符。

函数名 作用 是否支持格式化 典型用途
Serial_SendByte 发送 1 个字节 ❌ 不支持 发送单字符或控制字节
Serial_SendArray 发送字节数组 ❌ 不支持 发送二进制数据、ASCII 字节流
Serial_SendString 发送字符串(以 \0 结尾) ❌ 不支持 发送固定内容字符串
Serial_SendNumber 将数字转为字符串并发送 ❌(仅数字) 显示整数、计数等
Serial_Printf 发送格式化字符串 ✅ 支持格式化 功能类似 printf,用最强大最灵活

1.所有 Serial_SendXXX 函数 只能发送已经存在的内容:

  • 要么是固定字符串 "Hello"

  • 要么是数字 123

  • 要么是字节数组 {0x41, 0x42,...}

它们不能自动组合字符串、不能插入变量、不能格式化内容。

2.Serial_Printf 能做更多:支持格式化、变参、字符串构造

比如:Serial_Printf("温度=%.2f C, 湿度=%d%%\r\n", temp, hum);

它会自动:格式化字符串(构造最终字符串)把 "温度=21.53 C, 湿度=45%" 通过串口发出去

相当于**:** sprintf(buffer, ...); Serial_SendString(buffer);

但开发者不用自己写缓冲区,因为已经封装好了。

3.使用场景对比

🔹 使用 Serial_SendXXX 的场景

  • 发送固定内容(例如指令、固定格式)

  • 调试简单输出

  • 发送二进制数据(例如传输结构体、传感器原始数据)

  • 节省程序空间(不需要 printf 库)

🔹 使用 Serial_Printf 的场景

  • 输出调试信息

  • 输出变量值

  • 输出格式化数据(浮点、整型、字符串混合等)

  • 需要像 printf 一样灵活的输出


4.总结:一句话区分它们

Serial_SendXXX:直接发已有内容,不格式化

("我给你什么,你就发什么")

Serial_Printf:先拼接格式化字符串,再发送

("我告诉你模板,你自动把内容拼好再发")

二.三种常见在嵌入式系统中输出格式化字符串的做法

方法1:直接重定向printf,但printf函数只有一个,此方法不能在多处使用

printf("\r\nNum2=%d", 222);

串口发送printf打印的格式化字符串,需要重定向fputc函数,并在工程选项里勾选Use MicroLIB

解释:

1>你用 printf() 想把内容输出到串口,但printf 默认输出到"标准输出 stdout**"。** 在电脑上,stdout = 屏幕,在 STM32 上,stdout = 没有实际设备(默认什么都不输出),所以如果你直接写:printf("Hello"); STM32 不知道"要送到哪里",所以 不会显示、也不会自动发到串口。printf 发送每个字符时,调用 fputc() 函数输出单个字符。所以你要告诉 fputc:"每次 printf 输出字符,都帮我通过串口发送"。这样做,所有 printf() 输出内容 → 自动发送到串口助手。如 printf("Num=%d\r\n", 123); 会通过 USART(串口)打印到电脑。

2>在工程选项里勾选 Use MicroLIB"是什么意思?

这是 Keil MDK 的一个选项,MicroLIB = 微型 C 标准库**,**勾上后:含有更小的 printf库,代码更小,适合 Flash 很小的 MCU更好支持用户重定向 printf

Keil → Options for Target →Target→ Use MicroLIB ✔

方法2:使用sprintf打印到字符数组,再用串口发送字符数组,此方法打印到字符数组,之后想怎么处理都可以,可在多处使用

char String[100];

sprintf(String, "\r\nNum3=%d", 333);

Serial_SendString(String);

定义字符数组,使用sprintf,把格式化字符串打印到字符数组串口发送字符数组(字符串)

**方法3:**将sprintf函数封装起来,实现专用的printf,此方法就是把方法2封装起来,更加简洁实用,可在多处使用

Serial_Printf("\r\nNum4=%d", 444); //串口打印字符串,使用自己封装的函数实现printf的效果

Serial_Printf("\r\n");

三.串口打印实现过程

1.Serial_Printf("Num=%d\r\n", 444);

会让单片机做以下事情:

① 把字符串格式化为 "Num=444\r\n"

② 一个字节一个字节写入串口的发送寄存器 USARTx->DR

③ 串口硬件把这些字节调制成 UART 信号

④ 通过 TX 引脚(如 PA9)发送出去

2.电脑并不能直接接收 UART 信号所以需要一个 USB 转串口(TTL)模块,如 CH340、CP2102。

STM32 TX ------> USB串口模块 RX

STM32 RX ------> USB串口模块 TX(如果需要接收)

STM32 GND ------> USB串口模块 GND

模块通过 USB 线连接电脑。

  1. 电脑串口助手(Serial Assistant)显示数据

电脑打开串口助手,当串口助手检测到数据从 USB 来,就显示出来。

最终你会看到:Num=444

四. 数据流的全过程

Serial_Printf()

格式化字符串

Serial_SendByte()

USART1->DR(数据寄存器)

串口硬件把数据从 TX 引脚送出去

USB 转串口模块(CH340等)

USB 电缆

电脑驱动(虚拟串口 COMx)

串口助手显示出来

总结:串口打印的数据永远是从 STM32 单片机发出来的,最后显示在电脑的串口助手软件中。

在 STM32 芯片内部,大概是这样:

DR 寄存器在 STM32 内部, 数据从 DR → TX 引脚,然后通过 USB 转串口模块 → 电脑 → 串口助手

串口助手显示的数据来自STM32 内部 USART 外设(DR 寄存器)发送的数据

字符 → 写入 STM32 内部 DR → 移位寄存器 → TX 引脚 → USB 转串口 → 电脑串口助手

烧录程序:CPU把"程序代码"写入 STM32 的 Flash(程序存储器)里。

串口发送:把"数据"写入 STM32 内部的 USART 寄存器 DR,再从 TX 引脚发出去。

写 Flash = 烧录程序,写寄存器 = 运行时操作(通信)

串口接收

一.串口接收的过程

TX 发出的电压波形 → MCU RX 引脚接收到

RX 引脚 → 串口硬件 → 移位寄存器 → DR寄存器

触发接收中断 → 程序读数据

电脑发送数据----波形来到 STM32 的 RX 引脚----串口硬件自动"采样并解码"----串口硬件把字节放进接收寄存器 DR----硬件置位 RXNE(接收非空标志,RXNE = 1 ,意味着 DR里有数据可读)----如果开了接收中断,会进入 USART1_IRQHandler----应用层使用收到的数据电脑 → 发送 "1"(如STM32 → 控制LED亮)

相关推荐
悟空空心2 分钟前
服务器长ping,traceroute
linux·服务器·网络·ssh·ip·ping++
Ghost Face...4 分钟前
Docker实战:从安装到多容器编排指南
运维·docker·容器
此生只爱蛋29 分钟前
【Linux】正/反向代理
linux·运维·服务器
qq_54702617936 分钟前
Linux 基础
linux·运维·arm开发
zfj32142 分钟前
sshd除了远程shell外还有哪些功能
linux·ssh·sftp·shell
废春啊1 小时前
前端工程化
运维·服务器·前端
我只会发热1 小时前
Ubuntu 20.04.6 根目录扩容(图文详解)
linux·运维·ubuntu
爱潜水的小L1 小时前
自学嵌入式day34,ipc进程间通信
linux·运维·服务器
保持低旋律节奏1 小时前
linux——进程状态
android·linux·php
zhuzewennamoamtf1 小时前
Linux I2C设备驱动
linux·运维·服务器