STM32——串口通信发送字符串

一、实验功能

本程序实现 STM32 通过串口(USART1)上电后发送一串数据,包含:

  1. 发送单个字节:A B C
  2. 发送完整字符串:hello world
  3. 封装了可复用的串口发送函数,是所有串口项目的基础框架。

二、完整代码

main.c

复制代码
// STM32 标准库底层头文件
#include "stm32f10x.h"
// 主头文件
#include "main.h"
// 串口驱动头文件
#include "usart.h"

/**
  * @brief  毫秒级软件延时函数
  * @param  time: 延时时间,单位 1ms
  * @retval 无
  */
void delay(uint16_t time)
{
	uint16_t i = 0;
	while(time --)
	{
		i = 12000;
		while(i --);
	}
}

/**
  * @brief  主函数
  * @retval int
  */
int main()
{
    // 中断分组(整个工程只配置一次)
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	// 初始化串口 USART1
	my_usart_init();
	
	// ========== 串口发送测试 ==========
	My_Usart_Send_Byte(USART1,'A');    // 发送单个字节 A
	My_Usart_Send_Byte(USART1,'B');    // 发送单个字节 B
	My_Usart_Send_Byte(USART1,'C');    // 发送单个字节 C
	
	// 发送字符串 hello world,并换行
	My_Usart_Send_String(USART1,"hello world \r\n");
	
}

usart.c

复制代码
#include "stm32f10x.h"
#include "usart.h"

/**
  * @brief  初始化 USART1 串口
  * @param  无
  * @retval 无
  */
void my_usart_init(void)
{
	GPIO_InitTypeDef GPIOInitStruct;
	USART_InitTypeDef USART_InitStruct;
	
	// 开启 GPIOA 和 USART1 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
	
	// ========== 配置 TX 引脚 PA9 ==========
	// 复用推挽输出(串口发送必须用这个模式)
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_9;
	GPIOInitStruct.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(GPIOA, &GPIOInitStruct);
	
	// ========== 配置 RX 引脚 PA10 ==========
	// 上拉输入模式
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIOInitStruct);
	
	// ========== 配置串口通信参数 ==========
	USART_InitStruct.USART_BaudRate = 115200;                // 波特率 115200
	USART_InitStruct.USART_HardwareFlowControl = NONE;       // 无硬件流控
	USART_InitStruct.USART_Mode = Tx + Rx;                    // 发送 + 接收模式
	USART_InitStruct.USART_Parity = NO;                       // 无校验位
	USART_InitStruct.USART_StopBits = 1;                      // 1 位停止位
	USART_InitStruct.USART_WordLength = 8;                    // 8 位数据位
	
	USART_Init(USART1, &USART_InitStruct);                   // 初始化串口
	USART_Cmd(USART1, ENABLE);                               // 使能串口
}

// ========================= 重点函数 1 =========================
/**
  * @brief  串口发送一个字节(8 位数据)
  * @param  USARTx:串口编号,如 USART1
  * @param  Data:要发送的字节数据(如 'A'、0x41)
  * @retval 无
  */
void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data)
{
	// 1. 调用库函数,把数据写入发送寄存器
	USART_SendData(USARTx, Data);
	
	// 2. 等待发送完成
	// TXE=1 表示发送完成,可以发下一个
	while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}

// ========================= 重点函数 2 =========================
/**
  * @brief  串口发送一个字符串
  * @param  USARTx:串口编号
  * @param  str:字符串首地址
  * @retval 无
  */
void My_Usart_Send_String(USART_TypeDef* USARTx, char * str)
{
	uint16_t i = 0;  // 定义下标变量
	
	// 循环发送每一个字符,直到遇到 '\0' 结束
	do
	{
		// 取出当前字符,调用单字节发送函数
		My_Usart_Send_Byte(USARTx, *(str + i));
		
		// 下标 +1,取下一个字符
		i++;
		
	// 判断:当前字符不是结束符 '\0',就继续循环
	}while(*(str + i) != '\0');
	
	// 等待整个字符串发送完成
	while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
}

usart.h

复制代码
#ifndef USART_H_
#define USART_H_

#include "stm32f10x.h"

// 函数声明
void my_usart_init(void);
void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data);
void My_Usart_Send_String(USART_TypeDef* USARTx, char * str);
	
#endif	

三、重点详细讲解

🔴 重点 1:My_Usart_Send_Byte 函数(发送单个字节)

函数作用

发送 1 个字节(8 位数据),比如字母、数字、符号。

复制代码
void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data)
  • USARTx:指定用哪个串口(USART1/2/3)

  • Data:要发送的数据

    USART_SendData(USARTx, Data);

把数据写入串口的发送数据寄存器,硬件自动开始发送。

复制代码
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
  • TXE = Transmit Data Register Empty
  • 意思是:数据寄存器空了 = 上一个字节发完了
  • 等待 TXE=1,再发下一个,防止数据覆盖、发送错乱

一句话总结

发送一个字节 → 等待发送完成 → 再退出函数保证发送稳定、不丢数据。

🔴 重点 2:My_Usart_Send_String 函数(发送字符串)

函数作用

发送一串字符(字符串) ,比如 hello world

字符串在 C 语言中的规则

字符串最后一定有一个结束符:\0所以我们循环发送,直到遇到 \0 停止

复制代码
uint16_t i = 0;

定义下标,用来逐个取字符。

复制代码
do
{
	My_Usart_Send_Byte(USARTx, *(str + i));
	i++;
}while(*(str + i) != '\0');

*(str + i) 是什么意思?

  • str 是字符串首地址
  • str+i 是第 i 个字符的地址
  • *(str+i)取出第 i 个字符的值

② 执行流程

i=0 → 取第 0 个字符 → 发送i=1 → 取第 1 个字符 → 发送...直到遇到 \0 停止。

③ 循环结束条件

复制代码
while(*(str + i) != '\0')

没到字符串结尾就继续发

复制代码
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
  • TC = Transfer Complete
  • 整个字符串全部发完了,TC 才会变成 1
  • 加这句保证字符串发送完整

四、整体运行流程

  1. 上电
  2. 初始化串口
  3. 发送 A
  4. 发送 B
  5. 发送 C
  6. 发送 hello world
  7. 进入死循环等待

串口助手显示:

五、关键点

  1. 发送字节必须等待 TXE,不然会发丢
  2. 发送字符串必须等待 TC,保证发完整
  3. 字符串以 \0 结束,循环靠它判断
  4. 串口初始化必须开启时钟、配置正确引脚模式
相关推荐
国科安芯3 小时前
航天器多路并联大功率电源系统设计与ASP4644均流特性分析
单片机·嵌入式硬件·fpga开发·安全性测试
茯苓gao5 小时前
嵌入式开发笔记:CANopen相关移位运算与通信协议术语详解
网络·嵌入式硬件·学习·信息与通信
梁朝辉8 小时前
STM32H750VBT6中ADCINP与INN什么区别
stm32·单片机·嵌入式硬件
省四收割者9 小时前
一文详解信号完整性(1)
python·嵌入式硬件·数学建模·信息与通信·信号处理·智能硬件
崇山峻岭之间10 小时前
单片机无感FOC驱动之ADC
单片机·嵌入式硬件
Ligocious10 小时前
1.点亮一颗小小的LED
单片机·嵌入式硬件
KaifuZeng14 小时前
通信与接口协议面试八、CAN通信
单片机·嵌入式硬件·面试·通信与接口协议
智源单片机设计15 小时前
基于单片机的直流电机双闭环调速系统设计
单片机·嵌入式硬件
kebidaixu16 小时前
两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片详解
stm32
kebidaixu16 小时前
两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片调试实录:四个关键问题与解决方案
stm32