
第一次接到恒温碗项目时我心里想的是找个SPI接口的小屏两个钟头就能点亮。等采购把屏幕定下来递过来一块定制的段码玻璃LCD我整个人是懵的——没有驱动芯片、没有RGB数据线、甚至没有明确分辨率只有一串COM和SEG引脚。最后方案落到了中微SC8F6790这颗自带LCD驱动模块的8位机身上才算把这块屏幕真正驯服。本文就从这颗芯片怎么驱动恒温碗LCD屏讲起把寄存器配置、段码映射思路、可参考的完整代码以及量产中遇到的显示问题一并整理出来给做同类产品的人少走点弯路。这个项目里恒温碗的屏幕显示的是实时温度、电量、加热状态这类固定信息正好是段码LCD最擅长的场景。SC8F6790是中微半导体的一款8051内核MCU内置了LCD驱动电路和电荷泵偏压电路可以直接把玻璃屏的COM、SEG引脚挂上去省掉一颗外置LCD驱动芯片也省掉一堆偏压电阻。如果你的产品还在用MCU加HT1621方案看完这篇应该会有换方案的冲动。1. 这个方案成立的底层逻辑为什么选SC8F6790来点恒温碗的屏1.1 恒温碗显示屏的真实规格段码LCD为主而不是TFT先说结论恒温碗这类小家电的屏幕绝大多数不是TFT彩屏而是定制的段码玻璃LCD。这也是为什么产品图上温度数字看起来“很死板”只有固定形状的8字和几个图标。这种屏没有传统意义上的像素和分辨率本质是很多个可以独立通电的液晶段拼在一起点亮不同段的组合就能拼出数字和符号。和TFT、OLED相比段码玻璃屏有不可替代的优势。第一是反射式显示户外或者强光下越看越清楚婴儿辅食碗经常要在餐桌上用环境光杂七杂八这点很重要。第二是功耗极低整块屏工作电流能控制在微安级对锂电池产品非常友好。第三是成本一块定制的段码玻璃屏几块钱就能搞定而最小尺寸的TFT也要十几块还要配背光、触摸、驱动IC。劣势当然也有显示内容必须开模定制改一个图标就要改一次玻璃所以方案定型前一定要把显示内容和厂家反复确认清楚。一个恒温碗上常见的显示内容大概是两位或三位温度数字、一位小数、摄氏度符号、低电量图标、加热/保温图标有的还带一个冒号用来做待机状态闪烁。这些内容对段数要求不高一般四五十段足够SC8F6790内置的LCD驱动模块完全绰绰有余。1.2 内置LCD驱动模块省掉HT1621之后到底省了什么传统方案里驱动段码屏最常见的方法是MCU加一颗HT1621外置LCD驱动芯片。HT1621本身不贵也就几毛钱但代价远不止芯片本身。你需要给它留SPI或三线接口的GPIO软件里要模拟写命令、写数据的时序硬件上要额外布置LCD供电和偏压电阻PCB面积也白白多出一块。SC8F6790内置LCD驱动模块之后COM和SEG引脚可以直连玻璃屏MCU内部自己产生扫描波形内部电荷泵产生LCD需要的偏压外部只需要按数据手册放几个小电容。省掉的不只是芯片成本还有PCB布线的复杂度、软件时序调试的工作量以及一条可能出问题的新故障点。对小家电这种成本敏感、空间受限的产品每一颗多余的物料都值得怀疑而把显示驱动吞进MCU内部是相当务实的做法。1.3 一颗芯片画完整块板ADC测温、PWM加热、按键蜂鸣器都能管恒温碗不是只点个屏就完了它的核心功能是测温、控温、显示、交互。NTC热敏电阻采集温度需要ADC加热片需要PWM或者MOS开关控制用户按键需要输入检测提示音需要蜂鸣器驱动。这些外设SC8F6790基本都集成了。更关键的是恒温碗这类产品对成本和量产稳定性非常敏感。一颗8位机把主控和显示驱动全部搞定外围只有阻容、传感器和功率器件整板BOM看着都清爽。固件用C写调试用Keil C51或者SDCC都行开发门槛也不高。所以当时我把屏幕规格确认完之后几乎没有犹豫就锁定了这颗芯片。2. LCD驱动前必须搞清的三个概念COM、SEG和显示RAM2.1 段码屏怎么点亮一个“8”看段码屏之前先忘掉LED点阵那套逻辑。LCD段不是靠电流点亮而是靠电压驱动液晶分子翻转。你可以把每一段想象成一片微型百叶窗两片玻璃中间夹着液晶材料当COM电极和SEG电极之间施加的交流电压有效值超过阈值时液晶分子偏转光线透过或者被遮挡这一“段”就显示出来。一个标准数字由a、b、c、d、e、f、g七段加一个小数点dp组成共8个液晶段。玻璃屏内部已经用透明导电层把这些段的电极走线引到引脚上引出的就是一组COM引脚和一组SEG引脚。COM和SEG的交叉点决定一段能否被点亮交叉矩阵越复杂能控制的段数越多。这里有个特别重要的点LCD不能加直流电压。长时间直流驱动会造成液晶材料极化轻则残影重则永久损坏屏幕。所以必须用交流波形驱动这也是为什么LCD驱动模块内部会自动生成扫描和交流翻转波形而不是像LED那样直接给高电平就完事。2.2 扫描与占空比1/4 duty是怎么工作的段码屏的COM引脚通常不止一根常见的有1/2、1/3、1/4 duty。duty这个词来自动态扫描MCU内部以一定速率轮流选通COM0、COM1、COM2、COM3在选通某一根COM的同时其他SEG引脚根据显示RAM内容输出对应的电平。因为扫描速度足够快人眼看到的是所有COM同时点亮就像霓虹灯交替闪烁太快之后看起来一直是亮着的。1/4 duty意味着每一根COM在完整一帧里只有四分之一的时间被选通其他时间处于非选通状态。非选通时SEG引脚不能简单输出0V否则不该亮的段也会达到点亮阈值因此芯片会输出中间电压偏压让非选通段的电压差低于阈值。这个“偏压法”是段码LCD驱动的核心细节很多新手第一次接触时会忽略。SC8F6790的LCD模块会自动完成COM扫描和SEG输出不需要软件去模拟这是内置驱动和外置驱动器最大的区别。软件要做的事情只是把显示数据写到指定的显示RAM地址里硬件会自动把RAM内容变成屏幕上的亮暗变化。2.3 显示RAM地址和引脚映射的关系显示RAM是整个驱动过程中最容易让人懵的地方。SC8F6790的LCD模块会有一片专用RAM地址和数据位与屏幕上的COM、SEG存在固定映射关系。通常某一个RAM地址对应若干根SEG而每一个bit位对应一根COM线上的某一SEG状态。往RAM里写1或0就相当于控制某个交叉点要不要点亮。但这里有个坑不同厂家的玻璃屏COM和SEG的排列定义不一样。有的屏COM0在左边有的在右边有的屏a段挂在SEG0上有的挂在SEG7上。RAM地址和引脚的对应关系只能以芯片数据手册和屏幕厂家的真值表为准。很多工程师第一次点亮后发现数字乱跳、图标乱亮就是因为没有建立正确的映射关系而不是代码逻辑问题。拿到一块屏幕后第一步永远是找厂家要屏幕规格书里的COM/SEG真值表然后对照芯片的显示RAM映射表把两套关系对齐。这个准备工作做好后面写驱动就是体力活。3. SC8F6790 LCD模块的寄存器配置细节含完整代码3.1 引脚复用LCD引脚和GPIO怎么切换SC8F6790的引脚数量有限LCD的SEG引脚和普通GPIO往往是复用关系。初始化LCD之前必须先把相关引脚从GPIO模式切到LCD模式否则引脚的高低电平由GPIO数据寄存器控制LCD模块根本驱动不了它们。这个步骤通常会配置一个引脚功能选择寄存器把对应位设置成LCD功能。还有一个容易被忽略的细节切到LCD模式后最好把引脚的普通数字输入缓冲关掉否则引脚长期处于中间电平数字输入电路会漏电。对电池供电的恒温碗来说漏电虽然不大但在待机模式下会被无限放大。3.2 时钟分频和帧频为什么不要一上来就调最高LCD模块需要一个时钟来产生COM扫描和电压泵切换。这个时钟一般由系统时钟分频得到频率太快也不是好事。帧频太低会看到明显闪烁帧频太高则电荷泵来不及建立电压反而导致LCD偏压不稳显示亮度忽明忽暗。帧频的计算公式可以简化成LCD扫描时钟频率除以分频系数再除以COM个数。假设内部LCD时钟源是75kHz分频系数设为127那么扫描时钟大约是75k/128约586Hz再在4个COM之间轮转帧频就是586/4约146Hz这个值比较合适。我一般把帧频控制在120到160Hz之间低于80Hz会闪高于200Hz意义不大而且费电。配置代码里通常需要设定LCD时钟的分频值。不要直接抄Demo里最大分频或者最小分频手里有示波器最好实测一下帧频没有的话就按数据手册推荐区间取中值。3.3 偏压设置电压选不对屏就是不亮或者太淡LCD偏压直接决定显示对比度。SC8F6790内部有电荷泵和电阻分压网络可以从VDD升出VLCD并分出VLCD、2/3VLCD、1/3VLCD多层电平。1/4 duty的屏一般配1/3 bias也就是非选通段处于1/3VLCD选通段在剩下的2/3VLCD以上这样既保证点亮清晰又不会出现串扰。VLCD电压不是越大越好。电压过低段与段之间对比度不足数字很淡电压过高非选通段也会接近点亮阈值整屏看起来发灰发黑。以常见的3.3V玻璃屏为例VLCD取3.0V到3.3V之间比较合适具体以屏规格书为准。如果电池电压波动大最好采集VDD并做档位切换否则满电和低电量时显示效果会明显不同。3.4 初始化函数完整代码下面这段初始化代码按SC8F6790的典型寄存器布局编写。有一点要提前说明具体寄存器的命名和地址映射请以官方头文件和芯片数据手册为准不同批次或封装如果控制位有差异按手册修改对应位定义即可。// lcd_hw.h #ifndef __LCD_HW_H__ #define __LCD_HW_H__ #include stdint.h // 寄存器定义示例请以官方头文件为准 sfr LCDCR 0xB0; // LCD控制使能、占空比、偏压 sfr LCDCLK 0xB1; // LCD时钟分频 sfr LCDBIAS 0xB2; // VLCD和偏压模式选择 #define LCD_PIN_SEL_REG 0xB3 // 引脚功能选择寄存器示例 // 常用位定义 #define LCD_CR_ENABLE 0x80 #define LCD_CR_DUTY_1_4 0x20 #define LCD_CR_BIAS_1_3 0x08 #endif// lcd_hw.c #include lcd_hw.h void LCD_Init(void) { // 1. 将LCD相关引脚从GPIO模式切到LCD功能 // 这一步必须在开启LCD模块之前完成具体掩码看引脚定义 LCD_PIN_SEL_REG | 0x0F; // 2. 设置LCD时钟分频使帧频落在120~160Hz区间 // 这里取分频系数127配合75kHz LCD时钟得到约146Hz帧频 LCDCLK 127; // 3. 设置偏压模式为1/3 bias占空比1/4 duty // 同时先不要使能LCD等RAM清完再打开 LCDCR LCD_CR_DUTY_1_4 | LCD_CR_BIAS_1_3; // 4. 选择VLCD电压档位 // 根据当前VDD电压选择一个稳定的档位 LCDBIAS LCD_BIAS_LEVEL_3V3; // 举例常数 // 5. 清空显示RAM避免上电乱码 LCD_RAM_Clear(); // 6. 使能LCD模块 LCDCR | LCD_CR_ENABLE; }初始化顺序建议固定成“先引脚、再时钟、后偏压、清RAM、再使能”。如果先开LCD再切引脚会出现瞬间的异常段点亮虽然不影响硬件但视觉上很吓人测试时容易被误判成故障。4. 把“温度”变成屏幕上的数字段码映射与显示驱动代码4.1 数码段编码表怎么建立段码屏显示数字最终是控制7段加小数点的亮暗组合。在程序里最自然的做法是给每个数字定义一个八位编码每一位对应a、b、c、d、e、f、g、dp这8个段。例如数字0点亮a、b、c、d、e、f这6段熄灭g和dp编码就是0b0111111也就是0x3F具体位序随你定义。但实际工程里没那么简单因为屏的玻璃布线不会恰好把a、b、c、d、e、f、g对应到连续引脚上。有的段挂在SEG0有的挂在SEG5还有的段甚至分散在不同的COM线上。所以我推荐先建一张“逻辑位”到“物理段”的映射表定义每个数字的每个段在显示RAM里的地址和位掩码。这里举个例子。假设屏幕上某个温度数字的a段对应RAM地址0x10的bit0b段对应同一个RAM地址的bit3那么代码里的映射结构就应该记录这个位置。建立好映射表后显示数字只需要把七段码的每一位对应到映射表里刷新一遍。这张表是屏幕相关的换屏只改表不动算法。4.2 温度整数、小数、符号的刷新逻辑恒温碗显示温度时一般保留一位小数比如“39.8℃”。程序里我习惯把温度统一乘以10保存为整数避免浮点运算。来自ADC的NTC温度数据经过查表或者公式转换后会得到一个以0.1℃为单位的整数值比如398表示39.8℃。刷新逻辑大概是先判断正负如果是负温就把负号段点亮然后把绝对值拆成整数和小数两部分最后把各位数字写入显示缓冲再调用一次刷屏函数。显示缓冲的作用是避免直接改显示RAM时出现半刷新状态因为温度值可能在主循环中被更新而LCD模块的扫描是硬件自动的如果直接改RAM扫描到一半时数据变了人眼虽然不明显但会有轻微撕裂感。温度刷新不需要太频繁。NTC本身有热惯性100ms刷新一次绰绰有余刷新太快反而让数字跳来跳去观感很差。我一般会把温度显示更新放到一个100ms的软定时器里10Hz足够。4.3 冒号、电量、加热图标闪烁控制恒温碗屏幕上的图标不止常亮一种状态。加热图标可以在加热时常亮达到目标温度后以0.5Hz闪烁低电量图标只该在电量低时亮有的产品还用冒号做待机呼吸效果。闪烁本质上就是一个定时翻转RAM位的操作。建议用系统tick实现不要用delay。一个1ms递增的全局计数在显示刷新函数里判断当前时刻处于闪烁周期的前半段还是后半段然后决定图标段的亮灭。这样即使加热PWM占用了主循环时间图标闪烁频率也不会漂移太多。void Disp_IconUpdate(uint16_t tick_ms) { static uint8_t blink_state 0; // 500ms翻转一次产生1Hz闪烁效果 if ((tick_ms / 500) % 2 ! blink_state) { blink_state (tick_ms / 500) % 2; SetIcon(ICON_HEAT, blink_state); } }这段逻辑看似简单但要注意一点图标位在显示RAM里可能和某个数字位在同一个字节里更新图标时不要把其他位盖掉。最安全的做法是先读出原RAM值再只修改目标bit最后写回。如果RAM是可读写的直接在原值上做位运算就行。5. 完整工程代码可以直接当模板用的LCD驱动工程结构5.1 文件组织与寄存器定义把代码拆成底层驱动、段码映射、应用层三块是换屏和调试最舒服的结构。底层驱动只负责初始化LCD模块和读写显示RAM不关心屏幕内容段码映射层保存数字、图标的物理位置应用层关心温度、电量这些业务数据怎么显示。下面是一个可以套用的文件划分。这样的分层还有个好处如果你是量产项目一块屏幕从样品到量产的批次差异很大但底层驱动可以完全不动只改映射表。之前我换过一次屏幕供应商实际工作量只有更新映射表和校准VLCD两天就验证完了。5.2 LCD底层驱动寄存器读写与RAM操作// lcd_drv.h #ifndef __LCD_DRV_H__ #define __LCD_DRV_H__ #include stdint.h void LCD_Init(void); void LCD_RAM_Clear(void); void LCD_SetRamBit(uint8_t ram_addr, uint8_t bit_mask, uint8_t on); #endif// lcd_drv.c #include lcd_drv.h // 寄存器名称以官方头文件为准下面的定义是适配示例 #define LCD_DRV_CR (*(volatile uint8_t xdata *)0xFF00) #define LCD_DRV_CLK (*(volatile uint8_t xdata *)0xFF01) #define LCD_DRV_BIAS (*(volatile uint8_t xdata *)0xFF02) #define LCD_DRV_RAM_BASE ((volatile uint8_t xdata *)0xFF10) void LCD_RAM_Clear(void) { for (uint8_t i 0; i 16; i) { LCD_DRV_RAM_BASE[i] 0x00; } } void LCD_SetRamBit(uint8_t ram_addr, uint8_t bit_mask, uint8_t on) { uint8_t reg LCD_DRV_RAM_BASE[ram_addr]; if (on) reg | bit_mask; else reg (uint8_t)~bit_mask; LCD_DRV_RAM_BASE[ram_addr] reg; }这个底层实现了最核心的“RAM某一位写1或写0”操作。ram_addr代表显示RAM地址bit_mask代表该地址里的一个bit位。上层所有段码、图标显示最终都落在这个函数上。5.3 段码映射和显示缓冲// seg_map.h #ifndef __SEG_MAP_H__ #define __SEG_MAP_H__ #include stdint.h #define DIGIT_COUNT 3 // 整数两位 小数一位 #define SEG_PER_DIGIT 8 // a b c d e f g dp typedef struct { uint8_t ram_addr; uint8_t bit_mask; } LcdPoint; // 每个数字单元的8个段在RAM中的位置 extern const LcdPoint digit_layout[DIGIT_COUNT][SEG_PER_DIGIT]; // 显示缓冲先写缓冲再一次刷到LCD RAM extern uint8_t disp_buf[DIGIT_COUNT]; // 七段码编码表索引为数字0~9 extern const uint8_t code_7seg[10]; void SegBuf_Flush(void); void SetIcon(uint8_t icon_id, uint8_t on); #endif// seg_map.c #include seg_map.h // 本表仅为示例结构真实参数必须按屏幕真值表填写 const LcdPoint digit_layout[DIGIT_COUNT][SEG_PER_DIGIT] { { // 个位单元 {0x00, 0x01}, {0x00, 0x02}, {0x00, 0x04}, {0x00, 0x08}, {0x00, 0x10}, {0x00, 0x20}, {0x00, 0x40}, {0x00, 0x80} }, { // 十位单元 {0x01, 0x01}, {0x01, 0x02}, {0x01, 0x04}, {0x01, 0x08}, {0x01, 0x10}, {0x01, 0x20}, {0x01, 0x40}, {0x01, 0x80} }, { // 小数位单元 {0x02, 0x01}, {0x02, 0x02}, {0x02, 0x04}, {0x02, 0x08}, {0x02, 0x10}, {0x02, 0x20}, {0x02, 0x40}, {0x02, 0x80} } }; uint8_t disp_buf[DIGIT_COUNT] {0, 0, 0}; const uint8_t code_7seg[10] { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F // 9 }; void SegBuf_Flush(void) { for (uint8_t i 0; i DIGIT_COUNT; i) { uint8_t seg_code code_7seg[disp_buf[i] 0x0F]; for (uint8_t s 0; s 8; s) { uint8_t on (seg_code s) 0x01; LCD_SetRamBit(digit_layout[i][s].ram_addr, digit_layout[i][s].bit_mask, on); } } } void SetIcon(uint8_t icon_id, uint8_t on) { // 图标映射表根据实际屏幕定义 const LcdPoint icon_pos[2] { {0x03, 0x10}, // 加热图标 {0x03, 0x20} // 低电量图标 }; LCD_SetRamBit(icon_pos[icon_id].ram_addr, icon_pos[icon_id].bit_mask, on); }再次强调这张digit_layout表是示例结构实际数字单元在哪几个RAM地址、哪几个bit位必须对照你手里屏幕的真值表填写。种写法的好处是屏幕换了只改这张表七段码表、刷新逻辑都不用动。5.4 主循环集成示例NTC测温 显示 加热控制// main.c #include stdint.h #include lcd_drv.h #include seg_map.h volatile uint16_t sys_tick 0; // 定时器0中断服务里执行 sys_tick void Timer0_ISR(void) __interrupt 1 { sys_tick; } int16_t Read_Temperature_X10(void) { // 读ADC查NTC表得到以0.1℃为单位的温度 // 这里省略查表返回一个测试值 return 398; // 39.8℃ } void Display_Temp_Handle(void) { int16_t temp Read_Temperature_X10(); uint16_t abs_temp; uint8_t disp3; // 判断负温度 if (temp 0) { abs_temp (uint16_t)(-temp); // 点亮负号图标 } else { abs_temp (uint16_t)temp; // 熄灭负号图标 } // 整数部分十位、个位小数部分一位 disp3 (abs_temp / 10) % 10; // 十位 disp_buf[1] disp3; disp3 abs_temp % 10; // 个位 disp_buf[0] disp3; disp3 (abs_temp % 100) % 10; // 小数位通常取的是快速小数计算 disp_buf[2] disp3; // 刷屏 SegBuf_Flush(); } void main(void) { LCD_Init(); Timer0_Init(); // 1ms中断 while (1) { // 100ms刷新一次温度 if (sys_tick % 100 0) { Display_Temp_Handle(); } // 加热控制逻辑PWM输出等 // HeatControl(); } }主循环里这100ms刷新判断用取模做不算精确实际项目建议用“当前时刻减去上次刷新时刻”做差值判断更符合嵌入式实时逻辑。这里的简写只是演示主体结构。6. 实测中的坑亮度不够、残影、加热PWM干扰、引脚定义翻车6.1 对比度不是越大越好VLCD调高之后屏幕反而“糊”了第一次点亮样品屏的时候我先把VLCD寄存器调到最大档想着电压越高对比度越强结果屏幕所有段一起发黑整个显示区域灰蒙蒙一片完全看不清数字。当时还以为是屏坏了后来查了屏幕规格书才反应过来VLCD高过一定值之后非选通段两端的RMS电压也超过了液晶点亮阈值于是不该亮的段也跟着亮整屏出现“黑雾”。正确的调试方法是写一个全段测试程序让屏幕固定显示“88.8”或者全部图标然后从最低VLCD档开始往上扫每一档拍照记录显示效果选对比度最清晰、无串扰、无残影的那一档。这个档位在不同批次玻璃屏之间可能略有差异量产时最好把VLCD档位设计成可校准值比如存到EEPROM里产线测试时逐台校准一遍。6.2 残影和直流偏置长时间显示同一图案后屏幕“记住”了画面恒温碗在使用过程中温度数字变化其实很慢可能好几分钟就固定显示一个温度。时间长了以后断电或者切换界面时屏幕上会残留之前的数字轮廓像“烧屏”但又不是真正的烧屏。这是因为液晶如果长期承受同一方向的直流偏置会被极化撤掉电场后分子恢复不到原始位置。排除这个问题的路线是确认LCD驱动波形是否为纯交流确认偏压比是否正确确认有没有误用了GPIO直驱模式。另外可以在软件上优化一下显示内容比如每隔几分钟做一次全段翻转刷新所有段先全部点亮一帧再恢复相当于给液晶分子做一次“归位运动”。这个方法不能完全替代硬件设计但实测对残影缓解有一定帮助。低温环境下液晶响应慢看起来像残影的现象更明显那个属于物理特性不是驱动问题。6.3 加热PWM开启后屏幕变淡电源噪声和地弹的连锁反应恒温碗的加热片电流不小PWM开启瞬间电池电压会被拉低同时地线上产生噪声。LCD偏压是从VDD经过电荷泵升压得到的VDD一抖VLCD跟着抖最直观的表现就是屏幕亮度在PWM开启的瞬间变淡甚至闪一下。排查这个问题的链路很有代表性。先断开加热负载显示完全正常说明LCD驱动本身没问题然后用示波器同时抓VDD和VLCD发现两者都有跌落和毛刺接着在VDD处补了10uF加0.1uF的滤波电容在VLCD引脚加了100nF电容屏幕抖动明显改善。软件上也做了一个配合加热PWM开通的瞬间不执行温度刷新让显示RAM更新避开电源最不稳定的时刻。硬件和软件两手抓这个问题才算彻底解决。6.4 玻璃屏引脚定义不能想当然被COM顺序翻车坑过之后我学乖了有一次换了一款恒温碗屏COM和SEG数量没变我以为沿用旧映射表就能点亮结果上电后数字东倒西歪像是被拆散重组的七巧板。排查半天才发现新屏的COM0到COM3在电路板上的走线顺序和旧屏恰好相反。这不是软件逻辑问题纯粹是屏幕丝印和PCB布局的物理差异。从那以后我拿到一块新屏的第一件事就不是写显示函数而是写一个逐段点亮的测试程序一次只点亮一个COM-SEG交叉点然后拍照记录把整张真值表用实测方式建立起来。这个过程大概需要半个小时但能彻底避免后面几天对着乱码猜谜。屏幕厂家如果愿意提供真值表那就更省事了但实测验证依然值得做一遍因为厂家给的图纸和实物偶尔会不一致。我后来在量产版本里把LCD初始化、段码映射表、VLCD校准档位都封装成了一个独立显示模块换屏时只需要换一张映射表应用层代码一行不用动。如果这篇文章能让你第一次上电就正确显示出温度数字那我熬夜调显示的那几个晚上也算值了。最后再分享一个小技巧工程调试阶段写一个“88.8”的全段测试函数上电后自动点亮所有段一眼就能看出哪个COM/SEG接错线、哪一段有连锡比拿放大镜对丝印高效得多。