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. 串口初始化必须开启时钟、配置正确引脚模式
相关推荐
linbaiwan66618 分钟前
42V/50V/60V高耐压OVP保护芯片的应用——PW1600实测70V耐压
嵌入式硬件
嵌入式小站23 分钟前
STM32 零基础可移植教程 24:SPI Flash 读数据,先从指定地址读几个字节
chrome·stm32·嵌入式硬件
崇山峻岭之间1 小时前
单片机汉字显示实验
单片机·嵌入式硬件
guygg882 小时前
基于C# + Halcon的通用ROI绘制工具
stm32·单片机·c#
yugi9878382 小时前
基于 RFID 的智能公交刷卡系统
stm32·嵌入式硬件
点灯小铭2 小时前
基于单片机的雨量检测智能汽车雨刮器模拟系统设计与实现
单片机·嵌入式硬件·汽车·毕业设计·课程设计·期末大作业
三佛科技-134163842123 小时前
腕式血压计方案开发设计,腕式血压计MCU控制芯片选择
单片机·嵌入式硬件·物联网·智能家居
cici158743 小时前
C# LAS 点云读取与处理工具
stm32·单片机·c#
listhi5204 小时前
基于 LabVIEW 和 51 单片机的温度检测系统
单片机·mongodb·labview
三佛科技-187366133974 小时前
GD32F103RCT6兆易创新LQFP64,32 位 ARM Cortex-M3 微控制器芯片解析
单片机·嵌入式硬件