基于STM32的中断串口通信实现:接收数据自动回传与LED指示

一、项目概述

本文将实现一个基于STM32的中断驱动串口通信系统,主要功能包括:

  1. 计算机通过串口助手发送数据给STM32
  2. STM32使用USART中断接收数据
  3. 接收到的数据立即通过串口回传给计算机
  4. LED灯周期性闪烁指示系统运行状态

硬件需求

  • STM32开发板(本文以STM32F103C8T6为例)
  • USB转TTL模块(CH340/CP2102等)
  • LED灯(开发板自带或外接)
  • 杜邦线若干

开发环境

  • Keil MDK-ARM
  • STM32标准外设库
  • 串口调试助手(推荐XCOM或SSCOM)

二、硬件连接

STM32引脚连接目标
PA9 (TX)USB-TTL的RX
PA10 (RX)USB-TTL的TX
PC13LED阳极
3.3VUSB-TTL的3.3V
GNDUSB-TTL的GND

硬件连接示意图

三、代码实现

1. 初始化配置(main.c)

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"

// 定义LED引脚
#define LED_PIN     GPIO_Pin_13
#define LED_PORT    GPIOC

// 环形缓冲区配置
#define BUF_SIZE 128
uint8_t rx_buf[BUF_SIZE];
volatile uint16_t rx_head = 0;  // 接收头指针
volatile uint16_t rx_tail = 0;  // 接收尾指针

void GPIO_Config(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | 
                          RCC_APB2Periph_GPIOC | 
                          RCC_APB2Periph_AFIO, ENABLE);
    
    // LED配置(PC13)
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = LED_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(LED_PORT, &GPIO_InitStruct);
    
    // USART1引脚配置(PA9-TX, PA10-RX)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void USART1_Config(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    
    USART_InitTypeDef USART_InitStruct;
    USART_InitStruct.USART_BaudRate = 115200;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStruct);
    
    // 使能接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    
    // 中断优先级配置
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    
    USART_Cmd(USART1, ENABLE);  // 使能串口
}

2. 环形缓冲区实现

// 环形缓冲区写入(中断中使用)
void buf_write(uint8_t data) {
    uint16_t next_head = (rx_head + 1) % BUF_SIZE;
    if (next_head != rx_tail) {  // 缓冲区未满
        rx_buf[rx_head] = data;
        rx_head = next_head;
    }
}

// 主循环中读取缓冲区数据
uint8_t buf_read(uint8_t *data) {
    if (rx_head == rx_tail) 
        return 0;  // 缓冲区空
    
    *data = rx_buf[rx_tail];
    rx_tail = (rx_tail + 1) % BUF_SIZE;
    return 1;
}

3. 中断服务函数

void USART1_IRQHandler(void) {
    // 检查接收中断标志
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t ch = USART_ReceiveData(USART1);  // 读取接收数据
        buf_write(ch);                           // 写入缓冲区
        
        // 立即回发数据(回显)
        USART_SendData(USART1, ch);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // 等待发送完成
    }
}

4. 主循环处理

int main(void) {
    SystemInit();  // 系统时钟初始化
    GPIO_Config();
    USART1_Config();
    
    while(1) {
        // LED闪烁(500ms周期)
        GPIO_SetBits(LED_PORT, LED_PIN);
        Delay(250);
        GPIO_ResetBits(LED_PORT, LED_PIN);
        Delay(250);
        
        // 处理缓冲区数据
        uint8_t data;
        while (buf_read(&data)) {
            // 此处可扩展数据处理逻辑
            // 例如: 协议解析, 控制其他外设等
        }
    }
}

// 简单延时函数(实际项目建议用SysTick)
void Delay(uint32_t nCount) {
    for(; nCount != 0; nCount--);
}

四、关键代码解析

1. 中断处理流程

graph TD

A[串口接收到数据] --> B[触发USART_IT_RXNE中断]

B --> C[进入USART1_IRQHandler]

C --> D[读取USART1->DR寄存器]

D --> E[数据存入环形缓冲区]

E --> F[立即回发相同数据]

F --> G[清除中断标志]

2. 环形缓冲区优势

  1. 数据安全:隔离中断与主循环
  2. 防数据丢失:当主循环处理不及时时缓冲数据
  3. 高效处理:避免在中断中执行耗时操作

3. LED指示设计

  • 闪烁周期:500ms(250ms亮 + 250ms灭)
  • 作用:直观显示系统运行状态
  • 扩展:可通过改变闪烁频率指示不同状态

五、测试与验证

测试步骤:

  1. 使用Keil编译并烧录程序
  2. 连接硬件(注意TX/RX交叉)
  3. 打开串口助手(波特率115200)
  4. 发送测试数据:"Hello STM32!"

预期结果:

  1. PC端串口助手收到相同的回传数据
  2. 开发板上的LED灯稳定闪烁
  3. 无数据丢失现象(可连续发送大量数据测试)

六、常见问题解决

  1. 无数据回传

    • 检查TX/RX接线是否反接
    • 确认波特率设置一致(115200)
    • 检查串口助手是否打开正确COM口
  2. 数据乱码

    • 检查系统时钟配置
    • 验证USART时钟源是否使能
    • 降低波特率测试(如改为9600)
  3. LED不闪烁

    • 确认LED引脚定义是否正确
    • 检查LED限流电阻是否合适
    • 测试GPIO输出是否正常

七、项目扩展方向

  1. 协议解析:在buf_read处理中添加自定义协议解析
  2. 多串口支持:扩展USART2/3实现多通道通信
  3. DMA传输:结合DMA实现高速数据传输
  4. 状态指示:不同LED闪烁模式表示不同状态
  5. 数据存储:添加SD卡存储接收到的数据

八、总结

本文实现了基于STM32中断机制的串口通信系统,具有以下特点:

  • 🚀 高效中断处理:及时响应串口数据
  • 🔁 可靠数据缓冲:环形缓冲区防止数据丢失
  • 💡 直观状态指示:LED闪烁显示系统运行
  • ⚙️ 模块化设计:便于功能扩展

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值