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. 串口初始化必须开启时钟、配置正确引脚模式
相关推荐
这波不该贪内存的10 小时前
裸机开发VS单片机:架构与实战对比
单片机
山羊硬件Time10 小时前
自动化管理Linux的好工具:shell script
linux·嵌入式硬件·硬件工程师·基带工程·硬件开发
神一样的老师10 小时前
【兆易创新GD32VW553开发板试用】红外遥控接入天气时钟实战
驱动开发·单片机·嵌入式硬件
asjodnobfy11 小时前
Π型滤波电路
嵌入式硬件·硬件工程
多看多敲多思考13 小时前
华润微CS32ME10 MCU使用教程(2)---CS32ME10之UART串口模块使用
stm32·单片机·嵌入式硬件·mcu
神一样的老师13 小时前
【兆易创新GD32VW553开发板试用】天气时钟设计与调试实战
单片机·嵌入式硬件·物联网
国科安芯13 小时前
核电站仪控与监测系统中抗辐射 MCU 芯片应用研究
单片机·嵌入式硬件·macos·无人机·cocos2d·核电站
黑白园14 小时前
STM32系统时钟由72M修改为36M验证示例
stm32·单片机·嵌入式硬件
LCG元14 小时前
基于ARM7的LCD设计与实现:S3C4510B通用IO口控制液晶模块
stm32·单片机·嵌入式硬件