🎯 题目要求
设计一个基于串口通信的LED控制系统,通过特定格式的指令控制三色LED的开关状态。
📋 功能需求
核心功能
-
串口协议解析
-
指令格式:
[命令字符][状态字符] -
命令字符:
A(红),B(黄),C(绿) -
状态字符:
1(开),0(关)
-
-
LED控制
-
支持独立控制每个LED
-
示例指令:
-
A1- 开启红灯 -
B0- 关闭黄灯 -
C1- 开启绿灯
-
-
-
状态显示
-
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嵌入式系统开发的完整流程,涵盖了外设驱动、通信协议、用户界面等关键技术。通过模块化设计和健壮的错误处理,构建了一个稳定可靠的嵌入式应用框架,为更复杂的物联网设备开发奠定了基础。
项目源码已开源,欢迎交流学习!