首页 / 资讯中心 / 文章详情

HT1621段码屏驱动实战:从硬件接线、时序代码到段码映射与排错

HT1621段码屏驱动实战:从硬件接线、时序代码到段码映射与排错 ★ FEATURED ARTICLE
我最早接触段码屏项目是因为要做一台便携仪器的显示面板需求很朴素显示数字、小数点和几个固定图标要求阳光下可视、功耗低、单价可控。当时在点阵屏和段码屏之间犹豫了很久最后基于成本和显示可靠性选了HT1621这颗经典的LCD段码驱动芯片。HT1621是一颗带串行接口的LCD段码驱动器最多能驱动32×4共128个段基本上覆盖了大多数家电、仪器、仪表、电动工具面板的显示需求。芯片本身非常“皮实”价格便宜市场上模块也很多无论是用51、STM32还是ESP32都能很容易驱动起来。这篇文章我想把从硬件接线、命令时序、驱动代码到段码映射、问题排查的完整过程过一次适合正在做段码屏选型的开发者也适合想把手头屏点亮但还在啃手册的新手。1. 选型思路与原理拆解为什么是HT16211.1 段码屏和点阵屏到底怎么选很多刚接触显示的人会有疑问能显示的东西这么多为什么还要用段码屏这种“看起来啥都显示不了”的方案。这个问题的答案在于产品需求。带背光的点阵屏能在室内显示复杂界面但功耗高、阳光下可视性差、驱动成本高而要做一个只显示“温度单位运转状态”的面板用点阵屏属于杀鸡用牛刀。段码屏的本质是预先在玻璃上蚀刻出固定笔画每一位数字、每一个图标都是一段独立的LCD电极。它不像点阵屏那样每个像素都能任意控制但正因为固定所以驱动简单、功耗极低、在强光下对比度好。用在血糖仪、体温计、咖啡机、电动车仪表这类固定UI产品上非常合适。选择HT1621而不是自己用MCU直接驱动LCD是因为LCD需要交流波形驱动直流驱动会造成电解和永久损坏。HT1621内部已经集成了振荡器、偏压产生电路和显示RAMMCU只需要通过三根线把显示数据“填”进去剩下的扫描波形它全包了软件负担极轻。1.2 HT1621能干什么干不了什么HT1621的核心指标是128点显示32个SEG段输出乘4个COM公共端输出。很多人把它理解成“最多驱动32个段”这是误区。正确理解是屏幕上所有可显示的笔画都要分配到某个SEG与某个COM的组合上每位7段数字加小数点占8段也就是两个SEG就能驱动一位完整数字。它也支持更少公共端的配置比如1/2 duty、1/3 duty、1/4 duty偏压也有1/2、1/3等选择。这些配置会通过命令字告诉芯片。需要特别明确的是HT1621不能显示任意ASCII字符和非预设图形它只负责把RAM里的位置1/置0进而点亮对应段。所以前期必须把屏的段位图和RAM地址的对应关系摸清楚。这是整个项目里最容易被忽视、后续最容易出问题的环节。1.3 COM/SEG扫描点亮一段的底层逻辑LCD段码屏的点亮原理可以类比成老式霓虹灯某个笔画要亮只需要在这个笔画的电极两端施加一个大于阈值的小电压。由于液晶不能长时间承受直流电压所以必须用交流波形驱动让同一段在正半周和负半周都能被“激活”平均直流分量为零。HT1621内部实际做的事就是把画面的COM端按1/4 duty的方式轮流扫描同时每个SEG端根据RAM内容输出对应的波形。某个段如果RAM位为1SEG波形就和当前COM波形的相位差变大液晶两端等效电压足够高视觉上就“亮了”如果RAM位为0两端的等效电压小于阈值段就保持透明也就是不亮。这就是为什么段码屏的功耗很低每一段在任一时刻只有很小的寄生电容充放电没有背光没有持续灌电流。了解这一层原理之后再去看命令和数据格式就不会觉得那一串串0和1是玄学了。2. 硬件连接与电路设计把外围一次做对2.1 管脚速览与供电设计HT1621常见封装有SOP/TSSOP引脚不算多但有几个引脚决定了系统能不能正常显示。首先是VDD芯片工作电压范围一般可以覆盖2.4V~5.2V3.3V系统直接供电没问题5V系统也能兼容。其次是VLCD它决定LCD的偏压幅度。对多数小尺寸段码屏VLCD直接接VDD就能得到正常对比度如果屏幕偏淡或过深就需要用电阻分压或外部电源调整。OSC引脚也很关键。HT1621内部带RC振荡器多数应用直接把OSC接VDD或悬空用内部时钟扫描即可省掉一颗晶振。需要注意的是内部RC振荡器的频率受温度和电压影响如果听到屏的闪烁感比较明显可以尝试通过命令选择外接晶振或调整系统时钟源。还有一个容易踩坑的点是复位。芯片有复位引脚通常用一个10kΩ电阻上拉到VDD再接0.1µF电容到地形成上电延迟复位。如果复位引脚悬空或受干扰上电时芯片可能进入异常状态屏就会花。这个RC电路虽然不起眼实测对可靠性提升很大。2.2 三线串行接线的连接方法HT1621与MCU的通信接口是三根线CS、WR、DATA本质上是一种简化的SPI接口没有时钟线用WR的上升沿锁存DATA线上的电平。连接方式非常简单MCU任意三个GPIO分别接过去即可。建议在DATA、WR、CS线上各串一个几百欧姆的串联电阻减小信号过冲。这个做法在低速系统里看似多余但当显示刷新和中断同频发生时能明显减少偶发乱码。PCB走线方面不要让这三根线贴着高压或大电流走线市售模块很多为了省成本没做保护自己打板时就别省这一步。另外一个很多教程没强调的点如果MCU和HT1621供电电压不同比如MCU用3.3V、HT1621的VDD用5V来得到更高偏压那么GPIO输出的3.3V高电平对于5V供电的HT1621来说可能不够可靠。最好加电平转换或者直接把芯片也跑3.3V。段码屏在3.3V偏压下的对比度一般已经可接受。2.3 偏压、背光、复位电路取值思路段码屏大多没有背光如果确实需要夜视功能一般使用EL背光片或加LED导光板。这里只说LED背光LED的串联限流电阻要根据工作电流反推。比如背光LED阵列额定20mA、压降约3.0V接在5V电源上限流电阻就是(5-3)/0.02100Ω功率余量按0.1W起步选1206封装。偏压电路则需要根据屏的规格书来定。1/3 bias的评价是当VLCD3.3V时非选择段的电压是1.1V左右选择段的电压约2.2V。如果你的屏幕阈值电压偏高就会出现全屏都亮或者显示极淡的现象解决路径不是去改命令而是调整VLCD电压。另外电源去耦电容是段码屏硬件最容易忽视的细节。HT1621虽然功耗低但COM/SEG输出在大面积切换时会有瞬间电流跳变如果VDD缺少电容波形会被拉出毛刺轻则显示轻微闪烁重则干扰数据线导致乱码。我的习惯是VDD和VLCD各放一个1µF电容靠近芯片引脚再在电源入口放一个10µF钽电容或电解电容。3. 驱动代码实战从时序到刷新3.1 通信时序的底层逻辑WR上升沿锁存软件驱动HT1621不需要硬件SPI用GPIO模拟时序反而更灵活。理解时序的关键在于HT1621是在WR上升沿采样的也就是说MCU要先把DATA引脚的电平调整到目标值然后再让WR产生一个由低到高的跳变芯片才把这个电平读进去。对应的底层发送函数非常简单一次发送若干个比特从高位开始。下面这段代码是核心static void HT1621_SendBits(uint16_t data, uint8_t cnt) { uint8_t i; for (i 0; i cnt; i) { DATA_GPIO (data (0x8000 (12 - (cnt - i - 1)))) ? 1 : 0; WR_GPIO 1; WR_GPIO 0; data 1; } }这里有一个看起来不起眼但很关键的问题每次置位之后要不要延时在低速MCU上GPIO翻转本身就有几百纳秒的时间通常够用。但在高速MCU上比如主频几十兆以上的M4GPIO翻转极快WR高电平时间可能短到不满足芯片的数据建立时间。稳妥做法是每发送一位后加几个空循环。我曾经在调试时把延时全去了结果显示随机花屏问题就在这里。3.2 初始化顺序错了会白屏HT1621初始化不是简单“上电就能显示”必须先配置系统时钟源、设置占空比和偏压、打开系统振荡器、最后打开显示。如果顺序不对尤其是一上来就发LCD ON命令RAM里是随机值屏会闪一下花屏之后维持空白。我习惯用下面这个序列#define HT1621_CMD_SYS_DIS 0x0000 #define HT1621_CMD_SYS_EN 0x0001 #define HT1621_CMD_RC_256K 0x0030 #define HT1621_CMD_BIAS_3 0x0029 // 1/3 bias, 1/4 duty #define HT1621_CMD_LCD_ON 0x0003 void HT1621_Init(void) { HT1621_WriteCmd(HT1621_CMD_SYS_DIS); HT1621_WriteCmd(HT1621_CMD_SYS_EN); HT1621_WriteCmd(HT1621_CMD_RC_256K); HT1621_WriteCmd(HT1621_CMD_BIAS_3); HT1621_WriteCmd(HT1621_CMD_LCD_ON); }几个命令的具体值以及位数不同厂商的兼容型号可能略有差异市面上常见的显示屏模块和芯片型号不一样我们收到的数据手册定义也不完全统一。最稳妥的做法是在初始化前把“写命令”这个函数的位宽和数据手册逐位核对一遍而不是直接照搬。这个习惯能帮你省掉很多“为什么别人的代码能亮我的不能亮”的排查时间。3.3 写命令与写数据的代码封装HT1621通信格式大致分为三种写命令以101开头写数据以110开头。写命令用于配置系统写数据用于向显示RAM填入内容。封装好这两个函数业务层就可以专心处理显示内容不用再管时序。写命令的封装void HT1621_WriteCmd(uint16_t cmd) { CS_GPIO 0; HT1621_SendBits(0x05, 3); // 101 HT1621_SendBits(cmd, 9); // 9位命令 CS_GPIO 1; }写数据的封装需要带地址。HT1621的显示RAM一共有32个地址每个地址对应4个COM固定组合也就是低4位void HT1621_WriteData(uint8_t addr, uint8_t data) { if (addr 31) return; CS_GPIO 0; HT1621_SendBits(0x06, 3); // 110 HT1621_SendBits(addr, 6); // 6位地址 HT1621_SendBits(data, 4); // 4位数据对应COM0~COM3 CS_GPIO 1; }这里要特别提一下片选信号的使用。很多人习惯全程拉低CS不管对简单显示没问题但在多设备总线或需要掉电低功耗的场合CS不仅是片选还承担着防止误写入的作用。建议每次通信开始拉低、结束拉高。3.4 刷新策略定时刷新还是变化时刷新HT1621内部有RAM锁存只要MCU把数据写进去芯片就会持续不断地扫描输出不需要外部反复刷新。所以业务层不用开一个1ms定时器疯狂刷屏。推荐的做法是程序维护一份显示缓冲只有数据发生变化时才把对应地址写进芯片。如果显示的数值会频繁变化比如每秒刷新十几次那做一个简单的“脏标记”机制就够了。每帧业务逻辑完成后比较当前显示缓冲和上一帧缓冲有变化的地址才写。这样既省MCU时间也降低数据线翻转频率减少EMI。在低功耗产品里还要注意一点进入休眠前要让芯片进入SYS DIS状态关掉LCD输出并把CS固定在有效电平防止误唤醒。否则裸奔系统的功耗很难做到微安级别。4. 显示缓冲区与段码映射设计让代码可维护4.1 把显示内容组织成RAM缓冲我见过很多入门代码是直接用离散的变量来控制某个段比如“开小数点位就写0x01”看起来简单项目一复杂就乱了。更好的做法是模拟芯片的RAM结构建一个32字节的数组每个字节对应一个RAM地址低4位对应COM0~COM3uint8_t display_ram[32];任何要显示的图标、数字都先改这个数组然后统一调用提交函数把所有数据写进芯片void HT1621_DisplayCommit(void) { uint8_t i; for (i 0; i 32; i) { HT1621_WriteData(i, display_ram[i]); } }这个做法的好处是业务逻辑只关心“显示层”硬件通信被隔离在后面。如果以后换芯片比如换同样RAM结构的兼容型号只需要改底层的WriteData函数和命令序列显示逻辑几乎不用动。4.2 数字字母段码表这样做数字段码表没法直接给一个万能数组因为每个屏的COM/SEG走线不同、段的编号不同。直接抄网上数字表经常导致显示出来的字符错乱。正确做法是先拿到屏幕的电极图确认每位数字的7段分别挂在哪个COM和哪个SEG上再映射到RAM地址。为了说清楚过程假设我们处理一位7段数字它的段分别对应某个RAM地址的低4位中的某些位。最常见的7段编码如下段位顺序按a,b,c,d,e,f,g排const uint8_t digit_map[10] { 0x3F, // 0: a b c d e f 0x06, // 1: b c 0x5B, // 2: a b d e g 0x4F, // 3: a b c d g 0x66, // 4: b c f g 0x6D, // 5: a c d f g 0x7D, // 6: a c d e f g 0x07, // 7: a b c 0x7F, // 8: a b c d e f g 0x6F, // 9: a b c d f g };这段代码的前提条件是位0~6恰好依次对应a~g段而且屏幕的COM/SEG布线正好和RAM地址对齐。现实中经常需要重排。我的经验是先用“全段点亮”模式把每一段的RAM位找出来再手工整理成表而不是直接假设。4.3 小数点与固定图标的处理小数点和固定图标本质也是某个RAM位。比如显示缓冲区第0字节低4位已用于数字的a~d段小数点如果挂在同一个地址的高位或另一个地址就要单独用宏定义来管理避免魔法数字散落在代码里#define RAM_ADDR_DIGIT1 0 #define BIT_DP1 (1 3)当需要点亮小数点位时就执行类似于这样的操作display_ram[RAM_ADDR_DIGIT1] | BIT_DP1;固定图标比如电池、Wi-Fi、无线符号也建议用宏或枚举定义位号。有人会觉得几十个图标定义起来很啰嗦但项目到后期要改UI时这套“命名位映射”的清单就是你的设计文档。没有这套清单改一个图标位置要对着屏图一个个数非常容易改错。5. 常见问题与排查记录踩过的坑一次说清5.1 上电白屏或花屏的排查白屏或花屏最直接的原因是初始化没成功漏发SYS EN、漏发LCD ON或者复位引脚没处理好。排查顺序是从电源开始确认VDD电压、VLCD电压是否正常然后是复位引脚的上电电平最后是CS、WR、DATA三根线的静态电平是否正常。还有一种很隐蔽的情况是初始化顺序不对。如果先打开LCD ON再发系统配置屏幕会以错误的占空比扫描出现的不是正常显示而是“全部变透明”或“全部变黑”。遇到花屏时不要急着改代码先恢复初始化为彻底掉电再重新上电很多情况下重新上电就正常了说明软件缺了延迟或命令顺序有误。5.2 显示偏淡、亮度不均的调校显示偏淡涉及的因素主要是VLCD电压和偏压配置。VLCD越高LCD两端压差越大显示越深但是超过液晶阈值太多会造成拖影、残留。亮度不均则多半来自偏压配置和屏幕不匹配比如屏规格是1/4 duty 1/3 bias代码却配置成1/2 duty。这时不同位置段的有效电压不一致就会出现某些段特深、某些段特别浅。我的调校顺序是先固定VLCDVDD把偏压配置按屏规格书设置好全段点亮看整体效果如果整体太深或太浅再去微调VLCD。不要一边改偏压配置一边改VLCD两个变量同时动很难定位问题。5.3 显示错乱、缺划、串位的定位显示错乱基本是段码映射问题。常见的有两类一类是COM和SEG没有对上导致想显示“1”却亮了“2”另一类是地址处理越界写数据时地址超过了31芯片只接受了低6位或低4位RAM数据被覆盖。定位手段最有效的是“全段扫描”。写一个自检函数把32个地址依次写0xF先让所有段全亮再用肉眼或拍照记录屏上哪些笔画对应RAM的哪个地址、哪个位逐一绘制映射表。这个过程虽然琐碎但能一劳永逸解决所有映射错乱问题。5.4 偶发乱码与干扰问题的处理系统运行过程中偶发乱码尤其是电机启动、继电器切换时出现90%是电源干扰或CS受干扰。处理手段从上到下依次是芯片VDD加强去耦、数据线串电阻、缩短通信线长度、在CS上拉高电平、必要时软件降低刷新频率避开干扰窗口。软件层面还有一个很实用的小技巧在Commit函数前后各读回一次芯片状态或者做奇偶校验。对于HT1621这类简单驱动芯片没有回读功能所以必须依靠“数据线抗干扰可靠的片选时序”来保证正确性。一次写入失败不可怕可怕的是失败后没有检测、没有重发用户看到的就是偶发乱码。我在实际项目里最常用的兜底方案是在每次主要状态切换后强制Complete刷新一次全部RAM而不是只发变化的地址。多花几十个微秒换来的是界面自愈能力。这个芯片至今仍然大量应用在各种小家电和仪器面板上核心原因就是稳定、便宜、驱动简单。如果你正在做类似项目我强烈建议第一步不要急着写业务逻辑先把这块屏的映射表完整做出来存成头文件。以后无论改UI、换屏幕还是排查故障这张表和清晰的初始化代码会比任何“聪明”的算法都更管用。
阅读完成 · 觉得有帮助?
咨询建站