Files
DTU-LCD/readme.md
2026-01-25 15:46:30 +08:00

554 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DTU LED 项目
基于 STM32F103ZE 的数据传输单元DTU项目集成了 LCD 显示、按键控制、RS485 Modbus 通信等功能。
## 📋 项目简介
本项目是一个完整的 DTU 设备固件,实现了屏幕显示、按键交互、远程通信等核心功能。设备通过 RS485 接口与上位机进行 Modbus RTU 协议通信,支持图片传输、按键上报、状态监控等功能。
## 🎯 主要功能
- **LCD 显示**160×160 像素黑白 LCDUC1698U 控制器,支持图形和文本显示
- **按键控制**:基于 MultiButton 库的按键检测,支持多种按键事件
- **RS485 通信**Modbus RTU 协议DMA 接收模式,波特率 700000
- **LED 指示**:系统运行状态指示灯
- **看门狗保护**独立看门狗IWDG防止系统死机
- **Flash 存储**:支持 BMP 图片数据存储到 Flash扇区 126地址 0x0803F000
- **定时器管理**5ms 周期定时器,用于系统任务调度
## 🔧 硬件平台
- **MCU**STM32F103ZECortex-M3512KB Flash64KB RAM
- **系统时钟**72MHzPLL 倍频)
- **LCD**160×160 像素UC1698U 控制器
- **通信接口**RS485USART2TX=PA2RX=PA3DE=PA1
- **按键**:支持多按键输入(具体引脚见 `Drivers/BSP/KEY/key.c`
- **LED**:系统运行指示灯
## 📁 项目结构
```
LED/
├── Drivers/ # 驱动层
│ ├── BSP/ # 板级支持包
│ │ ├── 160160D/ # LCD 显示驱动
│ │ ├── KEY/ # 按键驱动MultiButton
│ │ ├── LED/ # LED 驱动
│ │ ├── RS485/ # RS485 通信驱动
│ │ ├── WDOG/ # 看门狗驱动
│ │ └── TIM/ # 定时器驱动
│ ├── CMSIS/ # CMSIS 核心文件
│ ├── STM32F1xx_HAL_Driver/ # STM32 HAL 库
│ └── SYSTEM/ # 系统核心驱动
│ ├── sys/ # 系统配置(时钟、中断等)
│ ├── delay/ # 延时函数
│ └── usart/ # 串口驱动(调试用)
├── Middlewares/ # 中间件层
│ └── Modbus/ # Modbus RTU 协议实现
│ ├── MODBUS.c/h # Modbus 主处理
│ └── CRC16.c/h # CRC16 校验
├── Users/ # 用户应用层
│ ├── main.c # 主程序入口
│ ├── File_Handle.c # Flash 文件处理
│ └── config.h # 配置文件
├── Projects/ # 工程文件
│ └── MDK-ARM/ # Keil MDK-ARM 工程
├── Output/ # 编译输出(仅保留 .hex
└── readme.md # 本文件
```
## 🚀 快速开始
### 开发环境要求
- **IDE**Keil MDK-ARM V5.06 或更高版本
- **编译器**ARM Compiler 5/6
- **调试器**ST-Link、J-Link 等
- **Pack**Keil.STM32F1xx_DFP.2.4.1 或更高版本
### 编译步骤
1. 打开 `Projects/MDK-ARM/atk_f103.uvprojx` 工程文件
2. 选择目标设备:`STM32F103ZE`
3. 编译工程F7 或 Project → Build Target
4. 编译成功后,`Output/` 目录下会生成 `DTU.hex` 文件
### 烧录程序
1. 连接 ST-Link 或其他调试器到目标板
2. 在 Keil 中点击 DownloadF8或使用外部烧录工具
3. 烧录 `Output/DTU.hex` 文件到 MCU
## 📡 通信协议
### Modbus RTU 配置
- **协议**Modbus RTU
- **主站地址**0x01
- **波特率**700000
- **数据位**8
- **停止位**1
- **校验位**:无
- **接收模式**DMA ReceiveToIdle不定长帧接收
### 通信功能
- **实时数据上报**:定时上报系统状态
- **按键事件上报**:按键按下时上报按键值
- **图片传输**:接收并显示远程发送的 BMP 图片数据
- **屏幕刷新**:支持远程刷新屏幕显示内容
## 🔄 工作流程
本项目核心功能是**按键检测上报**和**图像接收显示**,主要逻辑在 `MODBUS.c` 文件中实现。
### 系统整体架构
![image-20260125153417020](https://lsky.bitnasdaq.vip/D0gBg8.png)
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 定时器 │ 5ms中断 │ 按键驱动 │ 检测按键 │ 主循环 │
│ (5ms周期) │────────>│ (MultiButton)│────────>│ (main.c) │
└─────────────┘ └──────────────┘ └──────┬──────┘
│──────────────────────│
│ RS485_Process
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ RS485 │ DMA接收 │ MODBUS.c │ 处理数据 │ LCD显示 │
│ (USART2) │────────>│ (主处理) │────────>│ (160160D) │
└─────────────┘ └──────┬───────┘ └─────────────┘
┌─────────────┼─────────────┐
│ 发送命令 │ │ 解析数据控制
▼ │ ▼
┌─────────────┐ │ ┌─────────────┐
│ 上位机 │ │ │ LED │
│ (138端) │ │ │ (状态指示) │
└─────────────┘ │ └─────────────┘
```
**说明**`MODBUS.c` 接收 RS485 数据后解析;普通图片帧中的 `info[0..3]` 为 LED 状态,经 `LED_Printf()` 更新灯状态LOGO 图片不含 LED 控制。
### 按键检测与上报流程
#### 1. 按键检测流程
```
定时器中断 (5ms)
├─> Button_Ticks() // MultiButton 库扫描按键
└─> 检测到按键按下
├─> Key_ProcessCallback() // 按键回调函数
│ │
│ ├─> BackLight_ON() // 打开背光
│ ├─> KeyRun_Disp(1) // 显示按键指示
│ └─> keyStatus = key_type // 更新按键状态
└─> 主循环检测 keyStatus
└─> RS485_Process(keyStatus, ConnectFlg)
```
#### 2. 按键上报流程
```
RS485_Process() 函数
├─> 检测到按键 (key != KEY_NONE)
│ │
│ └─> 保存到 key_bk静态变量保持状态
├─> 检查发送条件
│ │
│ ├─> CMD_ACK == SET // 上次命令已应答
│ └─> ACK_OverTime == SET // 或应答超时
└─> 满足条件时发送按键命令
├─> RefreshScreen(KEY_CMD, key_bk)
│ │
│ ├─> RS485_RefreshScreenCMD(0x03, KEY_CMD, key)
│ │ │
│ │ ├─> 构建命令帧6字节
│ │ │ [0] = 0x01 (从站地址)
│ │ │ [1] = 0x03 (功能码)
│ │ │ [2] = 0x00 (KEY_CMD)
│ │ │ [3] = key (按键值)
│ │ │ [4-5] = CRC16校验
│ │ │
│ │ └─> RS485_SendBuff() 发送
│ │
│ └─> 重置轮询状态
└─> key_bk = KEY_NONE // 清除按键备份
```
**按键命令帧格式**6字节
```
┌──────┬──────┬──────┬──────┬──────┬──────┐
│ 0x01 │ 0x03 │ 0x00 │ key │ CRC │ CRC │
│地址 │功能码 │按键 │按键值 │ 高 │ 低 │
└──────┴──────┴──────┴──────┴──────┴──────┘
```
### 图像接收与显示流程
#### 1. 数据接收流程
```
RS485 DMA 接收 (ReceiveToIdle)
├─> 接收到一帧数据3208字节
│ │
│ └─> HAL_UARTEx_RxEventCallback()
│ │
│ ├─> RS485REG.NewMessageFlag = SET
│ └─> 重新启动 DMA 接收
└─> 主循环检测 NewMessageFlag
└─> RS485_Process() 处理新消息
```
#### 2. 数据解析与显示流程
```
RS485_Process() 检测到新消息
├─> NewMessageFlag == SET
│ │
│ ├─> ConnectFlg = 1 // 设置连接标志
│ │
│ ├─> CRC 校验
│ │ │
│ │ ├─> 校验通过
│ │ │ │
│ │ │ ├─> 提取数据:
│ │ │ │ Picture[3200] = DR[0:3199] // 图片数据
│ │ │ │ info[8] = DR[3200:3207] // 命令信息
│ │ │ │
│ │ │ ├─> 解析 info
│ │ │ │
│ │ │ │ info[4-5] = 图片类型标识
│ │ │ │
│ │ │ └─> 判断图片类型
│ │ │ │
│ │ │ ├─> LOGO 图片 (info[4]==0x89 && info[5]==0x45)
│ │ │ │ │─>info[0-1] = 图片宽度 (16位)
│ │ │ │ │─>info[2-3] = 图片高度 (16位)
│ │ │ │ ├─> 复制到 logo 结构体
│ │ │ │ ├─> BMP_SAVE2False() // 保存到 Flash
│ │ │ │ ├─> ClearScreen() // 清屏
│ │ │ │ ├─> LOGO_Printf() // 显示 LOGO
│ │ │ │ └─> delay_ms(2000) // 延时 2 秒
│ │ │ │
│ │ │ └─> 普通图片
│ │ │ │─>info[0-3] = LED 状态
│ │ │ ├─> LED_Printf(LED_BUFF) // 更新 LED 状态
│ │ │ └─> ScreenPrintf(Picture) // 显示图片
│ │ │
│ │ └─> 校验失败
│ │ │
│ │ ├─> CRC_ERR_COUNT++
│ │ └─> 连续 3 次错误 → RS485_DMA_init() 重新初始化
│ │
│ └─> 清除标志并设置 CMD_ACK = SET
└─> 继续处理其他任务
```
**接收数据帧格式**3208字节
```
┌─────────────────────┬──────────────────┐
│ Picture[3200] │ info[8] │
│ 图片点阵数据 │ 命令信息 │
└─────────────────────┴──────────────────┘
│ │
│ ├─> info[0-1]: 宽度
│ ├─> info[2-3]: 高度
│ ├─> info[4-5]: 类型标识
│ └─> info[6-7]: LED状态(普通图片)
└─> 3200 字节 BMP 点阵数据
```
### 实时数据轮询流程
```
定时器中断 (5ms)
└─> Process_Count()
├─> RT_count++ // 实时轮询计数递增
└─> ACK_count++ (如果 ACK_COUNT_ABLE == SET)
└─> 主循环检查
├─> RT_count > 55 (约 275ms)
│ │
│ └─> RefreshScreen(RT_CMD, 0) // 发送实时刷新命令
└─> ACK_count > 40 (约 200ms)
└─> ACK_OverTime = SET // 应答超时
└─> 连续 5 次超时 → 重新初始化 RS485
```
### 完整工作流程图
```
┌─────────────────────────────────────────────────────────────┐
│ 系统初始化 │
│ - HAL_Init() │
│ - RS485_DMA_init() // 启动 DMA 接收 │
│ - Process_Init() // 初始化轮询状态 │
│ - NL_LOGO_Printf() // 显示 Flash 中的 LOGO │
└──────────────────────┬──────────────────────────────────────┘
┌──────────────────────────────┐
│ 主循环 (while(1)) │
└──────────────┬───────────────┘
┌──────────────┴───────────────┐
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ 定时器中断 │ │ RS485_Process│
│ (5ms周期) │ │ (主处理) │
└───────┬───────┘ └───────┬───────┘
│ │
├─> Button_Ticks() ├─> 检查新消息
├─> Process_Count() │ (NewMessageFlag)
└─> 其他任务 │
├─> CRC 校验
├─> 解析数据
│ ├─> LOGO 图片 → 保存 Flash + 显示
│ └─> 普通图片 → 显示图片 + LED
├─> 检查按键上报
│ └─> 发送按键命令 (KEY_CMD)
└─> 检查定时刷新
└─> 发送实时命令 (RT_CMD)
```
### 关键数据结构
#### RS485_POLL_TYPE轮询状态
```c
typedef struct {
volatile uint8_t RT_count; // 实时命令计数0-55约275ms
volatile uint16_t CMD_ACK; // 命令应答标志SET=可发送)
volatile uint8_t ACK_COUNT_ABLE; // 应答计时使能
volatile uint8_t ACK_count; // 应答等待计数0-40约200ms
volatile uint8_t ACK_OverTime; // 本次应答超时标志
volatile uint8_t ACK_OverTimeCnt; // 连续超时次数0-5
} RS485_POLL_TYPE;
```
#### logo_typeLOGO 图片数据)
```c
typedef struct {
uint8_t bmpdata[3200]; // BMP 点阵数据
uint32_t biWidth; // 图片宽度(像素)
uint32_t biHeight; // 图片高度(像素)
} logo_type;
```
### 关键时间参数
| 参数 | 值 | 说明 |
|------|-----|------|
| 定时器周期 | 5ms | 系统基础时钟周期 |
| 实时轮询周期 | 55×5ms = 275ms | 定时发送实时刷新命令 |
| 应答超时时间 | 40×5ms = 200ms | 等待应答的最大时间 |
| 连续超时上限 | 5 次 | 超过则重新初始化 RS485 |
| CRC 错误上限 | 3 次 | 连续错误则重新初始化 RS485 |
| LOGO 显示时间 | 2000ms | LOGO 图片显示持续时间 |
### 错误处理机制
1. **CRC 校验失败**
- 累计错误计数 `CRC_ERR_COUNT`
- 连续 3 次错误 → 重新初始化 RS485 DMA 接收
2. **应答超时**
- 发送命令后启动应答计时(`ACK_COUNT_ABLE = SET`
- 200ms 内未收到应答 → 设置超时标志
- 连续 5 次超时 → 清除连接标志,重新初始化 RS485
3. **通信恢复**
- 重新初始化后,`CMD_ACK = SET`,允许重新发送命令
- 系统自动恢复通信流程
## 🔌 引脚分配
以下引脚定义与 `led.c``key.c``rs485.c``160160D.C` 中的配置一致。
### LED 灯(共 20 个)
所有 LED 均为**低电平有效**(输出低电平点亮,高电平熄灭)。推挽输出,上拉,高速。
| LED ID | 宏/用途 | 端口 | 引脚 | 说明 |
|--------|-------------|------|-------|--------------|
| 0 | `LED_POW` | PC | PC8 | 电源指示灯 |
| 1 | `LED_RUN` | PC | PC9 | 运行指示灯 |
| 2 | — | PA | PA9 | 通用 LED |
| 3 | — | PA | PA11 | 通用 LED |
| 4 | — | PA | PA15 | 通用 LED |
| 5 | — | PC | PC11 | 通用 LED |
| 6 | — | PD | PD0 | 通用 LED |
| 7 | — | PD | PD2 | 通用 LED |
| 8 | — | PD | PD4 | 通用 LED |
| 9 | — | PD | PD6 | 通用 LED |
| 10 | — | PC | PC7 | 通用 LED |
| 11 | — | PA | PA8 | 通用 LED |
| 12 | — | PA | PA10 | 通用 LED |
| 13 | — | PA | PA12 | 通用 LED |
| 14 | — | PC | PC10 | 通用 LED |
| 15 | — | PC | PC12 | 通用 LED |
| 16 | — | PD | PD1 | 通用 LED |
| 17 | — | PD | PD3 | 通用 LED |
| 18 | — | PD | PD5 | 通用 LED |
| 19 | — | PD | PD7 | 通用 LED |
- **代码位置**`Drivers/BSP/LED/led.c``led_config[]` 数组。
- **API**`LED_On(id)` / `LED_Off(id)` / `LED_Toggle(id)`;电源灯 `LED_POW(x)`,运行灯 `LED_Toggle(LED_RUN)`
### 按键(共 8 个)
按键为**输入**,无上拉/下拉(由外部电路决定)。按下为低电平,释放为高电平。
| 按键类型 | 端口 | 引脚 | 说明 |
|-------------|------|-------|------------------------------|
| `KEY_ENTER` | PD | PD12 | 确认键 |
| `KEY_UP` | PD | PD11 | 上键 |
| `KEY_DOWN` | PD | PD10 | 下键 |
| `KEY_LEFT` | PD | PD13 | 左键 |
| `KEY_RIGHT` | PD | PD8 | 右键 |
| `KEY_ESC` | PB | PB15 | 取消键 |
| `KEY_ADD` | PB | PB3 | 加键(需禁用 JTAG见下 |
| `KEY_RESET` | PD | PD15 | 复位键 |
- **代码位置**`Drivers/BSP/KEY/key.c``key_configs[]` 数组。
- **JTAG 说明**:使用 PB3 时,`Key_Init()` 中会调用 `__HAL_AFIO_REMAP_SWJ_NOJTAG()` 禁用 JTAG、保留 SWD以释放 PA15、PB3、PB4 作 GPIO。调试请使用 SWDPA13/PA14
### RS485 通信
| 信号 | 端口 | 引脚 | 说明 |
|------|------|-------|-------------------------------------|
| TX | PA | PA2 | USART2_TX |
| RX | PA | PA3 | USART2_RX |
| DE | PA | PA1 | 收发使能,低电平发送、高电平接收 |
### LCD 显示160160D / UC1698U
| 信号 | 端口 | 引脚 | 说明 |
|----------|------|---------|---------------------|
| 背光 | PB | PB0 | 背光控制 |
| RST | PB | PB10 | 复位 |
| CS | PB | PB11 | 片选 |
| RD | PB | PB12 | 读使能 |
| WR | PB | PB13 | 写使能 |
| CD | PB | PB14 | 命令/数据选择 |
| D0D7 | PE | PE8PE15 | 8 位并行数据总线 |
## ⚙️ 系统配置
### 时钟配置
- **系统时钟**72MHz
- **AHB 时钟**72MHz
- **APB1 时钟**36MHz
- **APB2 时钟**72MHz
### 定时器配置
- **定时器周期**5ms
- **中断优先级**:组 2抢占优先级 1子优先级 0
### 看门狗配置
- **类型**独立看门狗IWDG
- **喂狗周期**5ms在定时器中断中喂狗
### 系统保护
- **自动复位**:系统运行时间超过 5000 秒(约 83 分钟)自动复位,防止长时间运行异常
## 📝 代码规范
本项目遵循以下代码规范:
- **注释风格**Doxygen 风格注释(`@file``@brief``@param``@retval` 等)
- **命名规范**:驼峰命名法(函数、变量),宏定义全大写
- **文件组织**:按功能模块划分,驱动层、中间件层、应用层分离
## 🔍 主要模块说明
### LCD 显示模块160160D
- 驱动 UC1698U 控制器
- 支持 4K 色RGB444和 64K 色RGB565
- 提供字符显示、图形显示、LOGO 显示等功能
### 按键模块KEY
- 基于 MultiButton 库
- 支持单击、长按、双击等事件
- 按键事件通过回调函数处理
### RS485 通信模块
- DMA 接收模式(主工作模式)
- 中断接收模式(错误恢复)
- 支持不定长帧接收ReceiveToIdle
### Modbus 模块
- Modbus RTU 协议实现
- 支持实时数据上报、按键上报
- 支持图片数据传输和屏幕刷新
### Flash 存储模块
- BMP 图片数据存储地址0x0803F000
- 扇区大小2KB
- 支持读取和写入操作
## 🐛 调试说明
### 调试接口
- **SWD 接口**SWDIO、SWCLK标准 STM32 SWD 接口)
- **串口调试**:可通过 USART1 进行调试输出(如需要)
### 常见问题
1. **编译错误**:检查 Pack 是否安装正确,设备型号是否为 STM32F103ZE
2. **烧录失败**:检查调试器连接,确认目标板供电正常
3. **通信异常**:检查 RS485 接线,确认波特率配置正确
4. **显示异常**:检查 LCD 接线,确认背光控制正常
## 📄 许可证
本项目由阜阳师范大学物电学院开发。
## 👥 作者
- **开发单位**:阜阳师范大学物电学院
- **版本**V0.1
- **日期**2026.1.19
## 📚 参考资料
- [STM32F103 参考手册](https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf)
- [Modbus RTU 协议规范](https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf)
- [UC1698U 数据手册](https://www.ultrachip.com.cn/)
## 🔄 版本历史
- **V0.1**2026.1.19
- 初始版本
- 实现 LCD 显示、按键控制、RS485 Modbus 通信等基础功能
- 添加看门狗保护和系统自动复位功能
---
**注意**:本项目仅供学习和研究使用。使用前请仔细阅读代码注释,确保硬件连接正确。