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

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

相关推荐
up向上up3 小时前
【普中】基于普中51开发板单片机的8_8点阵滚动显示设计
单片机·51单片机·proteus
Bona Sun4 小时前
单片机手搓掌上游戏机(十二)—esp8266运行gameboy模拟器之编译上传
c语言·c++·单片机·游戏机
Molesidy4 小时前
【VSCode】使用 VSCode + EIDE插件 的开发STM32的超详细教程
ide·vscode·stm32·编辑器·eide
恒锐丰小吕5 小时前
晶准 RB302B 内置MOSFET锂电池保护芯片技术解析
嵌入式硬件·硬件工程
TangDuoduo00056 小时前
【电感基础与特性】
stm32·单片机·嵌入式硬件
许商6 小时前
【stm32】【SD】SDIO fatfs
stm32·单片机·嵌入式硬件
就是蠢啊6 小时前
51单片机——独立按钮、矩阵按键
单片机·嵌入式硬件·51单片机
云山工作室7 小时前
多传感器融合的办公室智能门禁系统(论文+源码)
stm32·单片机·嵌入式硬件·物联网·毕业设计·课程设计
天天爱吃肉82188 小时前
智能网联汽车信息安全深度解析:从UN-R155与GB44495标准到OBD/UDS技术实践
网络·嵌入式硬件·汽车