STM32嵌入式系统开发实战1:OLED显示、串口通信与GPIO控制

🎯 题目要求

设计一个基于串口通信的LED控制系统,通过特定格式的指令控制三色LED的开关状态。

📋 功能需求

核心功能

  1. 串口协议解析

    • 指令格式:[命令字符][状态字符]

    • 命令字符:A(红), B(黄), C(绿)

    • 状态字符:1(开), 0(关)

  2. LED控制

    • 支持独立控制每个LED

    • 示例指令:

      • A1 - 开启红灯

      • B0 - 关闭黄灯

      • C1 - 开启绿灯

  3. 状态显示

    • OLED实时显示接收的指令

    • 显示各LED当前状态(0/1)

    • 串口返回系统状态信息

硬件组成

  • 主控芯片:STM32F103RCT6

  • 显示模块:0.96寸OLED屏幕(I2C接口)

  • 通信接口:USART2串口

  • 外设控制:三个GPIO控制的LED(红、绿、黄),PB1,PB2,PB3

  • 调试接口:ST-Link调试器

软件架构

核心功能模块

1. 系统初始化
复制代码
// 硬件初始化序列
HAL_Init();                          // HAL库初始化
SystemClock_Config();               // 系统时钟配置
MX_GPIO_Init();                     // GPIO初始化
MX_DMA_Init();                      // DMA初始化
MX_I2C2_Init();                     // I2C初始化(OLED)
MX_USART2_UART_Init();              // 串口初始化
OLED_Init();                        // OLED屏幕初始化
2. 串口通信实现

DMA不定长数据接收

复制代码
// 启动DMA接收
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rx_data, sizeof(rx_data));
__HAL_DMA_DISABLE_IT(huart2.hdmarx, DMA_IT_HT);

// 接收完成回调函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if (huart->Instance == USART2)
    {
        // 重新启动接收
        HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rx_data, sizeof(rx_data));
        __HAL_DMA_DISABLE_IT(huart2.hdmarx, DMA_IT_HT);
        
        // 数据回显
        HAL_UART_Transmit_DMA(&huart2, rx_data, Size);
    }
}

通信协议设计

  • 数据格式:[命令字符][状态字符]

  • 示例指令:

    • A1 - 开启红色LED

    • B1 - 开启黄色LED

    • C1 - 开启绿色LED

    • A0 - 关闭红色LED

    • B0 - 关闭黄色LED

    • C0 - 关闭绿色LED

3. OLED显示系统

显示框架

复制代码
void OLED_DisplayTask(void)
{
    OLED_NewFrame();                    // 新建显示缓冲区
    
    // 显示接收到的数据
    if(strlen((char*)rx_data) > 0) {
        OLED_PrintString(0, 22, (char*)rx_data, &font16x16, OLED_COLOR_NORMAL);
    } else {
        OLED_PrintString(0, 22, "No data", &font16x16, OLED_COLOR_NORMAL);
    }
    
    // 显示LED状态
    GPIO_PinState RED_state = HAL_GPIO_ReadPin(RED_GPIO_Port, RED_Pin);
    GPIO_PinState GREEN_state = HAL_GPIO_ReadPin(GREEN_GPIO_Port, GREEN_Pin);
    GPIO_PinState YELLO_state = HAL_GPIO_ReadPin(YELLO_GPIO_Port, YELLO_Pin);
    
    OLED_PrintString(40, 0, (RED_state == GPIO_PIN_SET) ? "1" : "0", &font16x16, OLED_COLOR_NORMAL);
    OLED_PrintString(40, 20, (YELLO_state == GPIO_PIN_SET) ? "1" : "0", &font16x16, OLED_COLOR_NORMAL);
    OLED_PrintString(40, 40, (GREEN_state == GPIO_PIN_SET) ? "1" : "0", &font16x16, OLED_COLOR_NORMAL);
    
    OLED_ShowFrame();                   // 刷新显示
}
4. LED控制逻辑
复制代码
void LED_ControlLogic(void)
{
    if(strlen((char*)rx_data) >= 2)
    {
        if(rx_data[1] == '0')
        {
            // 关闭所有LED
            HAL_GPIO_WritePin(RED_GPIO_Port, RED_Pin, 0);
            HAL_GPIO_WritePin(GREEN_GPIO_Port, GREEN_Pin, 0);
            HAL_GPIO_WritePin(YELLO_GPIO_Port, YELLO_Pin, 0);
        }
        else if(rx_data[1] == '1')
        {
            // 先关闭所有LED
            HAL_GPIO_WritePin(RED_GPIO_Port, RED_Pin, 0);
            HAL_GPIO_WritePin(GREEN_GPIO_Port, GREEN_Pin, 0);
            HAL_GPIO_WritePin(YELLO_GPIO_Port, YELLO_Pin, 0);
            
            // 根据命令开启指定LED
            if(rx_data[0] == 'A') {
                HAL_GPIO_WritePin(RED_GPIO_Port, RED_Pin, 1);
            }
            else if(rx_data[0] == 'B') {
                HAL_GPIO_WritePin(YELLO_GPIO_Port, YELLO_Pin, 1);
            }
            else if(rx_data[0] == 'C') {
                HAL_GPIO_WritePin(GREEN_GPIO_Port, GREEN_Pin, 1);
            }
        }
    }
}
5. 系统状态监控

串口状态输出

复制代码
void SystemStatus_Report(void)
{
    GPIO_PinState RED_state = HAL_GPIO_ReadPin(RED_GPIO_Port, RED_Pin);
    GPIO_PinState GREEN_state = HAL_GPIO_ReadPin(GREEN_GPIO_Port, GREEN_Pin);
    GPIO_PinState YELLO_state = HAL_GPIO_ReadPin(YELLO_GPIO_Port, YELLO_Pin);
    
    // 格式化状态信息
    sprintf(uart_msg, "RED: %d, GREEN: %d, YELLOW: %d\r\n",
            (RED_state == GPIO_PIN_SET) ? 1 : 0,
            (GREEN_state == GPIO_PIN_SET) ? 1 : 0,
            (YELLO_state == GPIO_PIN_SET) ? 1 : 0);
    
    // 发送状态信息
    HAL_UART_Transmit(&huart2, (uint8_t*)uart_msg, strlen(uart_msg), HAL_MAX_DELAY);
}

关键技术点

1. DMA不定长接收技术

  • 使用HAL_UARTEx_ReceiveToIdle_DMA实现高效数据接收

  • 关闭半传输中断,优化性能

  • 自动重新启动接收机制

2. 实时显示更新

  • 双缓冲显示机制避免闪烁

  • 状态信息实时刷新

  • 异常状态提示

性能优化

内存管理

  • DMA传输减少CPU占用

功耗控制

  • 主循环中添加适当延时

总结

本项目展示了STM32嵌入式系统开发的完整流程,涵盖了外设驱动、通信协议、用户界面等关键技术。通过模块化设计和健壮的错误处理,构建了一个稳定可靠的嵌入式应用框架,为更复杂的物联网设备开发奠定了基础。

项目源码已开源,欢迎交流学习!

相关推荐
Jason_zhao_MR10 小时前
RK3576 MIPI Camera ISP调试:主观调优与工程实战(下)
stm32·嵌入式硬件·安全·系统架构·嵌入式
ACP广源盛1392462567313 小时前
iOS 27 开放 AI 生态@ACP#小型化扩展黄金风口,IX8008全面超越 ASM2806,铸就嵌入式 AI 扩展核心
人工智能·嵌入式硬件·macos·ios·计算机外设·objective-c·cocoa
smartpi_ai13 小时前
玩具产品从按键控制升级为语音控制:语音模块与MCU串口通信实战
单片机·嵌入式硬件
BreezeJuvenile15 小时前
【STM32】时钟摘取法
stm32·单片机·嵌入式硬件
崇山峻岭之间15 小时前
单片机GPIO配置
单片机·嵌入式硬件
不会武功的火柴15 小时前
SystemVerilog语法(7)-接口(interface)
嵌入式硬件·fpga开发·仿真·ic验证·rtl
深圳英康仕16 小时前
五网口六USB:一台龙芯2K3000工控机的接口配置解读
嵌入式硬件·信创·工控机·工业计算机·龙芯2k3000
lllllllccccc17 小时前
FReeRtos中断管理、临界段保护和任务调度器挂起和恢复学习
单片机·嵌入式硬件
ACP广源盛1392462567317 小时前
IX8024 对标 ASM2824 @ACP#搭配昆仑芯 P800 构建 AI 服务器 PCIe4.0 高速互联架构
网络·人工智能·嵌入式硬件·电脑
踏着七彩祥云的小丑17 小时前
嵌入式测试学习第 15 天:逻辑门基础:与或非、简单逻辑电路
单片机·嵌入式硬件