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

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

相关推荐
LaoZhangGong1234 分钟前
学习TCP/IP的第1步:ARP数据包
网络·stm32·学习·tcp/ip·以太网·arp·uip
三佛科技-187366133971 小时前
KP521405LGA低功耗5V1A易用高性能BUCK同步降压转换器芯片解析
单片机·嵌入式硬件
Joshua-a1 小时前
FPGA基于计数器的分频器时序违例的解决方法
嵌入式硬件·fpga开发·fpga
Dillon Dong1 小时前
STM32嵌入式:如何使用keil 来获取flash块数据并转换成可视化的数据 来判断源头数据是否错误
stm32·单片机·嵌入式硬件
雨疏风骤12403 小时前
ROM与RAM,储存地址、链接地址以及运行地址
linux·stm32·嵌入式·linux嵌入式
深耕AI3 小时前
【恍然大悟】8位单片机如何处理大数与二进制乘法?
单片机·嵌入式硬件
z20348315204 小时前
智能台灯控制面板
单片机·嵌入式硬件
钿驰科技4 小时前
TC-BL3650驱动板在无刷减速电机的应用
单片机·嵌入式硬件
深耕AI4 小时前
【单片机】解密STC89C52
单片机·嵌入式硬件
三佛科技-134163842124 小时前
FT32F072xx、FT32F072xB、FT32F072x6/x8基于ARM Cortex-M0内核32位单片机分析
arm开发·单片机·嵌入式硬件·智能家居·pcb工艺