mothercup/docs/数码管显示设计说明书.md
evan.liu f34efe9070 apptest 删除, 功能合入 disptest (APP V1.00.41)
- disptest 合并两段: 快速位检查(0-9/多位数/999.9/36.5F-C) + 全量程扫测(0.1-999.0 C+F)
- 删除 apptest 命令与 CmdAppTest
- 说明书 §8 同步(删除 apptest, 更新 disptest), 补 §4.1 三态驱动防鬼影说明
- 仅 APP 改动, Boot 不动 (仍 V1.00.07)
- docs/开发日志.md: 新增 §70
2026-09-13 13:47:12 +08:00

182 lines
8.9 KiB
Markdown
Raw Permalink 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.

# YF30137 数码管显示设计说明书
> 版本:V1.1(2026-09-06,融合当日数码管联调的位序修正与 GPIOA 时钟修复)
> 关联文档:`docs/YF30137_驱动真值表.md`(完整段→脚真值表)、`docs/开发日志.md` §58~§68
> 固件:`mcm-ddc-ble/src/app_display.c/h`(驱动)、`mcm-ddc-ble/src/cli_core.c`(CLI 命令)
---
## 1. 概述
数码屏为 **YF30137 七脚 Charlieplexing 温度显示模块**:7 个 IO 脚两两复用电极,点亮 5 个数字位 + 2 个指示段。驱动由独立的 FreeRTOS 任务 `display_task` 逐段扫描完成。
温度显示格式:**`[百][十][个][F/C][小数]` + `°F` + 小数点**,量程 **0.0 ~ 999.9**(1 位小数)。
---
## 2. 硬件连接(脚号 → MCU 引脚)
数码管脚 1~7(网络 `LED_1`~`LED_7`)与 MCU 引脚一一对应:
| 数码管脚 | 网络 | MCU 引脚 | | 数码管脚 | 网络 | MCU 引脚 |
|---|---|---|---|---|---|---|
| pin1 | LED_1 | **PB0** | | pin5 | LED_5 | **PB11** |
| pin2 | LED_2 | **PB1** | | pin6 | LED_6 | **PB13** |
| pin3 | LED_3 | **PA0** | | pin7 | LED_7 | **PA6** |
| pin4 | LED_4 | **PA1** | | | | |
- 7 个脚分布在 **GPIOA**(PA0/PA1/PA6)与 **GPIOB**(PB0/PB1/PB11/PB13)两个端口。
- ⚠️ **两个端口时钟都必须使能**(`RCC_APB2_PERIPH_GPIOA` / `RCC_APB2_PERIPH_GPIOB`),否则 PA0/PA1/PA6 无输出(见 §9 踩坑 1)。
---
## 3. 显示位序定义(重要:当日修正)
| 位 | 含义 | 说明 |
|---|---|---|
| **DIG1** | 百位 | 数字 0~9,前导零消隐 |
| **DIG2** | 十位 | 数字 0~9,前导零消隐 |
| **DIG3** | 个位 | 数字 0~9,恒显示 |
| **DIG4** | 单位字母 | **华氏显 `F`、摄氏显 `C`**(非数字位、非固定 F)|
| **DIG5** | 小数位(十分位) | 数字 0~9,恒显示 |
| **DIG6-A** | 华氏标志 °F | 华氏点亮、摄氏熄灭 |
| **DIG6-B** | 小数点 | 恒点亮(小数位恒显示) |
> 旧代码曾把 DIG1~5 当作 5 个全功能数字位、DIG4 当普通数字位——**已修正**。
> 注意 DIG6-A/DIG6-B 是**两个独立的单指示段**,不是逐位小数点(硬件特性)。
---
## 4. Charlieplexing 驱动原理
**段 S(A=0…G=6)在位 D(DIG1=1…DIG5=5)点亮**,由一对脚 `高→低` 驱动,其余 5 脚高阻:
```
高脚索引 h = (S + D) % 7 → 脚号 = h + 1
低脚索引 l = (D - 1) + (S + D) / 7 → 脚号 = l + 1
```
**DIG6 两个固定脚对**:
| 段 | 功能 | 点亮方式 |
|---|---|---|
| A6 | 华氏 °F | 脚7 高、脚6 低(`PA6 高 → PB13 低`)|
| B6 | 小数点 | 脚1 高、脚7 低(`PB0 高 → PA6 低`)|
**扫描要点**:逐段点亮(每段 250µs)→ 点完立即把两脚切回高阻(输入)→ 点下一段;同一数字的多段不能同时点(脚共用,否则鬼影)。一个完整扫描帧约 20ms。
### 4.1 三态驱动与防鬼影(核心)
点亮某一段时,7 个脚里**只有 2 个是输出(一高一低),其余 5 个脚必须全部「高阻」(输入浮空,`GPIO_MODE_INPUT` + `GPIO_NO_PULL`)**——既不是置高、也不是置低。
**为什么其它脚不能置高/置低(鬼影机理)**:以「脚6 高、脚1 低」点亮段 `6→1` 为例:
| 其它脚状态 | 后果 |
|---|---|
| 脚3 也**置低** | 6 高 + 3 低 → 段 `6→3` 也被点亮(多余段)|
| 脚2 也**置高** | 2 高 + 1 低 → 段 `2→1` 也被点亮(多余段)|
| 脚7 置高、脚5 置低 | 段 `7→5` 亮,甚至形成 `6→5`、`7→1` 等一串串扰 |
即:任一其它脚为高就会变成「电流源」,为低就会变成「电流汇」,都会和当前高低脚对构成寄生回路点亮别的段。**唯一安全状态是浮空高阻**(既不供流也不吸流)。
**代码实现(`app_display.c`)**:
```c
pin_input(idx) → GPIO_MODE_INPUT + GPIO_NO_PULL /* 高阻(浮空输入)*/
pin_high(idx) → GPIO_MODE_OUTPUT_PP + GPIO_SetBits /* 推挽输出高 */
pin_low(idx) → GPIO_MODE_OUTPUT_PP + GPIO_ResetBits/* 推挽输出低 */
static void seg_pair_on(uint8_t h, uint8_t l)
{
pin_high(h); /* 1. 只把高脚切输出高 */
pin_low(l); /* 2. 只把低脚切输出低 —— 其余 5 脚保持高阻不动 */
delay_n_10us(25); /* 3. 点亮 250µs */
pin_input(h); /* 4. 点完立刻把两脚放回高阻 */
pin_input(l);
}
```
支撑前提:`display_task` 每帧先 `all_pins_input()` 把 7 脚全部清成高阻,再逐段 `seg_pair_on`——因此任意时刻**最多 2 个脚是输出,其余恒为高阻**,杜绝串段。
**为什么必须逐段点(时间复用)**:7 脚复用,同一数字的多段脚对互相牵连、**不能同时点亮**。数字 8(7 段)就是 7×250µs 依次点亮,20ms 一帧内扫完,靠人眼视觉暂留看起来是"整字同时亮"。
---
## 5. 字符段码表(bit0=A … bit6=G)
| 字符 | 段码 | 字符 | 段码 | 字符 | 段码 |
|---|---|---|---|---|---|
| 0 | 0x3F | 1 | 0x06 | 2 | 0x5B |
| 3 | 0x4F | 4 | 0x66 | 5 | 0x6D |
| 6 | 0x7D | 7 | 0x07 | 8 | 0x7F |
| 9 | 0x6F | A | 0x77 | b | 0x7C |
| **C** | **0x39** | d | 0x5E | E | 0x79 |
| **F** | **0x71** | — | 负号 G 段 | 0x40 | |
- `F`(单位字母)= **0x71**(AEFG)、`C`(单位字母)= **0x39**(ADEF),用于 DIG4。
- 完整每个数字位的段→脚真值表见 `docs/YF30137_驱动真值表.md`(段→脚公式不变,只是位语义按 §3 修正)。
---
## 6. 温度解码(`display_decode`)
输入温度 `value`(float),输出 5 个位字符码:
1. 钳位:`value < 0 → 0`;`value > 999.9 → 999.9`;
2. `scaled = (int)(value × 10 + 0.5)`(×10 转 0.1℃ 分辨率);
3. 落位:`DIG5(小数)=scaled%10` → `DIG3(个)=(scaled/10)%10` → `DIG2(十)=(scaled/100)%10` → `DIG1(百)=(scaled/1000)%10`;
4. 前导零消隐:百位为 0 消隐,百位已消隐且十位为 0 再消隐十位;个位与小数位恒显示;
5. **DIG4 = 华氏 `0x0F`(F) / 摄氏 `0x0C`(C)**;
6. 小数点(DIG6-B)恒亮;华氏标志(DIG6-A)随华氏/摄氏开关。
> 驱动**不做 F/C 数值换算**:华氏/摄氏只切换 DIG4 字母与 DIG6-A 指示,数值原样显示(单位换算由上层完成)。
---
## 7. 软件架构与接口(`app_display.c/h`)
| 接口 | 说明 |
|---|---|
| `void display_set(float value, uint8_t type, uint8_t base)` | 设温度值 0.0~999.9;`type` 华氏/摄氏;`base` 已废弃(兼容保留)|
| `void display_set_raw(const uint8_t digits[5], uint8_t type)` | 直接写 5 个位字符码(绕过温度解码,用于 `Err`/`Lo`/`Hi` 等状态字)|
| `void display_auto_set(uint8_t on)` / `uint8_t display_auto_get(void)` | 自动扫描开关(关后 7 脚置高阻,交出手动控制)|
| `int display_pin_map(uint8_t pin_no, GPIO_Module**, uint16_t*)` | 数码管脚号 1~7 → GPIO 端口+掩码 |
| `void display_task(void*)` | 扫描任务:优先级 1、栈 256 字、20ms/帧、每段 250µs,循环喂狗 |
内部状态:`g_disp_value/g_disp_type/g_disp_base`(数值)、`g_disp_raw/g_disp_raw_digits`(裸码模式)、`g_disp_auto`(自动开关)。
---
## 8. CLI 命令(`cli_core.c`)
| 命令 | 说明 |
|---|---|
| `disp <value> [f]` | 设温度显示;`f` = 华氏(DIG4 显 F + DIG6-A 亮),默认摄氏 |
| `dispauto [on|off]` | 自动扫描开关(查询/设置)|
| `dispset <pin1-7\|all> [0\|1\|z]` | 手动驱动数码管脚:`0` 低 / `1` 高 / `z` 高阻;`all` 一键全脚 |
| `disptest` | 显示自检:① 0.0~9.0 → 12.3/456.7/999.9 → 36.5F/36.5C;② 全量程扫测 0.1~9.9(步0.1)→10~99(步1)→100~990(步10)→999.0,摄氏+华氏各一轮 |
| `pinset <pxN> [0\|1]` | 通用 GPIO 读写(非数码管专用)|
---
## 9. 关键踩坑与修正记录(当日)
1. **GPIOA 时钟未使能 → PA0/PA1/PA6 无输出**:数码管驱动删掉 `LedInit` 后 GPIOA 时钟失去使能点(GPIOB 因 USART 仍在使能)。修复:`display_task` 开头显式使能 GPIOA+GPIOB,`dispset` 内再防御性使能一次。
2. **位序理解错误**:旧代码把 DIG1~5 当 5 个全功能数字位、DIG4 当数字位。修正:DIG4 是单位字母、DIG5 是小数位。
3. **DIG4 从"固定 F"改为"F/C"**:华氏显 F、摄氏显 C。
4. **量程**:0.0~999.9(百十个小·数共 4 位数字 + 1 位单位),非 9999.9。
5. **裸码模式**:`display_set_raw` 用于显示 0~9/A~F 之外的状态字符(如 Err),`display_set` 会清掉裸码回到数值解码。
---
## 10. 温度显示示例
| 温度 | DIG1(百) | DIG2(十) | DIG3(个) | DIG4 | DIG5(小数) | 小数点 | °F |
|---|---|---|---|---|---|---|---|
| 0.0 ℃ | (空) | (空) | 0 | C | 0 | 亮 | 灭 |
| 8.5 ℃ | (空) | (空) | 8 | C | 5 | 亮 | 灭 |
| 36.5 ℃ | (空) | 3 | 6 | C | 5 | 亮 | 灭 |
| 36.5 ℉ | (空) | 3 | 6 | **F** | 5 | 亮 | **亮** |
| 100.0 ℃ | 1 | 0 | 0 | C | 0 | 亮 | 灭 |
| 999.9 ℉ | 9 | 9 | 9 | **F** | 9 | 亮 | **亮** |