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. 串口初始化必须开启时钟、配置正确引脚模式
相关推荐
天空'之城13 小时前
单片机基础核心知识点汇总(三十五)
单片机·嵌入式硬件
secondyoung14 小时前
I2C通信协议详解
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·51单片机
anew___14 小时前
蜂鸣器播放音乐——让 Arduino 唱出旋律
c++·stm32·单片机·嵌入式硬件·c
jianqiang.xue15 小时前
ESP-IDF保姆级入门40|量产烧录与产线测试全解:批量烧录方案/校准流程/功能测试/不良分拣/产线追溯,掌握工业级量产交付全流程
单片机·物联网·esp32
Zw-awa15 小时前
001-01-从C语言的main到STM32的main-你的代码后来去了哪里
stm32
幼儿园蛋小黑18 小时前
单片机数码管LED灯独立按键中断定时器综合实战
单片机·嵌入式硬件
自小吃多19 小时前
PCB Editor软件复制、改变、删除操作笔记
笔记·嵌入式硬件
数字新视界20 小时前
数据中心基础设施管理系统发布新版本,助力企业云化转型
嵌入式硬件·物联网·数据中心·数据中心基础设施管理·dcim管理系统
SKH.20 小时前
单片机(1)
单片机·嵌入式硬件
llilian_1620 小时前
小切口解决大问题:时序校准场景下的标准时间间隔脉冲信号发生器应用方案
功能测试·单片机·嵌入式硬件·51单片机