STM32——串口中断接收

一、实验功能

本实验实现 STM32 串口 三大核心功能:

  1. printf 重定向:单片机向上位机发送字符串
  2. 串口中断接收 :电脑发送数据 → 单片机自动触发中断读取数据
  3. 接收回显:单片机收到什么数据,立刻通过 printf 发回电脑显示

1、什么是串口中断接收?(通俗解释)

  • 普通接收(轮询) :主循环里一直while读取,CPU 累死,效率低
  • 中断接收 :CPU 正常干自己的事,数据来了自动喊 CPU ,CPU 停下手里的活,立刻读取数据不占 CPU 资源、响应最快、串口开发标准用法

2、串口中断接收完整工作流程

  1. 电脑发送一个字符 → 单片机 RX 引脚(PA10)收到
  2. 硬件自动把数据存入接收寄存器
  3. 触发 RXNE 接收中断(RX Non Empty)
  4. CPU 暂停主循环while(1)
  5. 自动跳转到 USART1_IRQHandler() 执行
  6. 读取数据 → printf 回显
  7. 清除中断标志 → 回到主循环继续执行

二、硬件连接

  • USART1_TX (PA9) :串口发送
  • USART1_RX (PA10) :串口接收
  • 波特率:115200
  • 数据位:8,停止位:1,校验位:无

三、完整代码

1.main.c 主程序文件

复制代码
// 包含STM32标准库底层驱动
#include "stm32f10x.h"
// 主头文件
#include "main.h"
// 串口驱动头文件
#include "usart.h"
// 标准输入输出头文件(使用printf必须包含)
#include "stdio.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()
{
    // 1. 配置中断分组(整个工程只配置1次)
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	// 2. 初始化串口(包含:GPIO、波特率、中断、NVIC)
	my_usart_init();
	
	// 3. 上电后发送一条欢迎信息
	printf("hello\r\n");
	
	// 4. 主循环死等
	// 所有接收逻辑交给【中断】自动处理,主循环无需任何代码!
	while(1)
    {
			
    }
}

2.usart.c 串口驱动文件(核心重点

复制代码
// 包含STM32标准库
#include "stm32f10x.h"
// 串口驱动头文件
#include "usart.h"
// 标准输入输出头文件
#include "stdio.h"

/**
  * @brief  串口初始化函数(发送+接收+中断)
  * @param  无
  * @retval 无
  */
void my_usart_init(void)
{
    // 定义配置结构体
	GPIO_InitTypeDef GPIOInitStruct;
	USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	// ===================== 1. 开启时钟 =====================
	// 同时开启 GPIOA 时钟 和 USART1 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
	
	// ===================== 2. 配置 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);
	
	// ===================== 3. 配置 RX 引脚 PA10 =====================
	// 接收引脚配置为:上拉输入
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIOInitStruct);
	
	// ===================== 4. 配置串口通信参数 =====================
	USART_InitStruct.USART_BaudRate = 115200;                     // 波特率115200
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无流控
	USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;   // 同时开启发送和接收
	USART_InitStruct.USART_Parity = USART_Parity_No;               // 无校验位
	USART_InitStruct.USART_StopBits = USART_StopBits_1;            // 1位停止位
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;        // 8位数据位
	
	// 初始化串口寄存器
	USART_Init(USART1, &USART_InitStruct);
	
	// ===================== 5. 使能串口外设 =====================
	USART_Cmd(USART1, ENABLE);
	
	// ===================== 6. 开启【串口接收中断】 =====================
	// 开启:RXNE 接收非空中断(当RX寄存器收到数据时,触发中断)
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	// ===================== 7. 配置 NVIC 中断控制器 =====================
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;              // 选择USART1中断通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;     // 抢占优先级0
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;            // 子优先级0
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;               // 使能该中断通道
	
	// 初始化NVIC
	NVIC_Init(&NVIC_InitStruct);
}

/**
  * @brief  串口发送一个字节
  */
void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data)
{
	// 写入数据到发送寄存器
	USART_SendData(USARTx, Data);
	// 等待发送完成(TXE=1表示发送完成)
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}

/**
  * @brief  串口发送字符串
  */
void My_Usart_Send_String(USART_TypeDef* USARTx, char * str)
{
	uint16_t i = 0;
	do
	{
		My_Usart_Send_Byte(USARTx,*(str+i));
		i++;
	}while(*(str+i) != '\0');
	// 等待整个字符串发送完成
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
}

// ===================== printf 重定向函数 =====================
/**
  * @brief  重写fputc函数,将printf输出到串口1
  */
int fputc(int ch, FILE * p)
{
	// 通过串口发送一个字符
	USART_SendData(USART1, (u8)ch);
	// 等待发送完成
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
	// 返回字符
	return ch;
}

// ===================== 【重点】串口中断服务函数 =====================
/**
  * @brief  USART1中断服务函数
  * @note   函数名固定!!!不能修改
  */
void USART1_IRQHandler()
{
    // 定义变量存储接收到的数据
	char str;
	
	// 1. 判断中断标志:是否是【接收中断】触发的
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		// 2. 读取串口接收寄存器的数据
		str = USART_ReceiveData(USART1);
		
		// 3. 把收到的数据通过printf回显到电脑
		printf("receive data: %c \r\n",str);
		
		// 4. 清除中断标志位(硬件自动清除,也可手动清除)
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
}

①. 开启接收中断

复制代码
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  • USART_IT_RXNE接收寄存器非空中断
  • 作用:只要 RX 收到数据,就立刻触发中断
  • 不开启这行 → 中断永远不触发

②. NVIC 配置(中断管家)

复制代码
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  • NVIC 是所有中断的大管家
  • 必须开启对应中断通道,中断才能生效

③. 【最重要】串口中断服务函数

复制代码
void USART1_IRQHandler()

✅ 规则:

  1. 函数名固定,不能自定义!
  2. 中断触发后,硬件自动调用这个函数
  3. 接收逻辑必须写在这里面

函数内部逻辑:

复制代码
// 判断是不是接收中断
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
    // 读取收到的数据
    str = USART_ReceiveData(USART1);
    
    // 回显数据
    printf("receive data: %c \r\n",str);
    
    // 清除中断标志
    USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}

四、运行效果


五、必记 5 大规则

  1. 中断服务函数名固定,不能写错
  2. 必须开启 USART_IT_RXNE 接收中断
  3. 必须配置 NVIC 使能中断通道
  4. 中断里尽量少写代码,快进快出
  5. printf 必须重定向 fputc + 勾选 MicroLIB
相关推荐
广州灵眸科技有限公司9 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) 开发(编译)方式说明
linux·服务器·单片机·嵌入式硬件·电脑
IT_阿水10 小时前
STM32 HAL库输入捕获配置
stm32·单片机·嵌入式硬件
nuoxin11410 小时前
WILX1200HC-5TG144I替代 LCMXO2-1200HC-5TG144I(富利威)
人工智能·嵌入式硬件·fpga开发·电脑·硬件工程·dsp开发
zlinear数据采集卡10 小时前
555触摸延时开关深度解析:从电路原理到智能楼道灯应用
单片机·嵌入式硬件
国科安芯14 小时前
国科安芯推出商业航天级抗辐照全双工 RS485/422 收发器 ASC491S2Y
网络·分布式·单片机·架构·安全性测试
czhaii14 小时前
LCD320240间接接口 RA8835控制器 温度MAX6675显示
单片机·嵌入式硬件·硬件工程
破晓单片机14 小时前
030、STM32项目分享:计时充电桩系统
stm32·单片机·嵌入式硬件
森利威尔电子-15 小时前
森利威尔SL3150H |PIN TO PIN 替换 MRDC88-1 10~150V 输入 0.6A 降压电源芯片
单片机·嵌入式硬件·物联网·集成电路·芯片
kebidaixu15 小时前
FreeRTOS 移植到 STM32F407VETX 记录
stm32·单片机
qq_4112624215 小时前
硬件是ESP32-P4连接LAN8720A,正常初始化之后,设备DHCP失败
stm32·单片机·fpga开发