前阵子做一台智能温控器的显示面板,核心需求很朴素:一块小尺寸段码LCD要实时显示温度、湿度和工作状态,再加上一个4x3的矩阵键盘用于设定参数。按我以前的做法,LCD驱动用一颗通用驱动芯片,键盘扫描再靠MCU自己轮询,运气不好时还得加一颗IO扩展芯片,BOM成本、PCB面积、固件复杂度全都不划算。后来换了FZH1643这颗集成了LCD驱动和键盘扫描的芯片,整个方案一下清爽了不少。
这颗芯片最吸引我的地方,就是把段码LCD驱动、矩阵键盘扫描、以及I2C通信接口全部整合在一起,还支持双模式切换,既能由主控主动配置和控制显示内容,也能让芯片自己维护显示、自动扫描键盘并上报结果。这篇文章我会从方案选型、硬件接线、软件驱动流程、双模式切换的具体实现,再到调试中真正踩过的坑,一步步把FZH1643的用法写透。不管你是刚开始接触LCD驱动芯片的新手,还是在做小家电人机交互面板的老工程师,这篇内容都值得花几分钟看完,能帮你少走不少弯路。
1. 为什么要把LCD驱动和键盘扫描塞进一颗芯片
1.1 传统方案到底麻烦在哪
做小家电或者仪器仪表的显示面板,最经典的需求就是“显示数字 + 用户按键输入”。段码LCD本身功耗低、成本低,而且在强光下看得清楚,所以至今在温控器、电饭煲、血压计、充电桩这些产品里依然是主力显示器件。
但段码LCD有个天生的麻烦:它不能像点阵屏那样用串口直接丢数据,必须由驱动电路持续输出COM和SEG扫描波形,而且扫描频率、偏压配置、占空比都要精确控制。早期很多方案直接用MCU的GPIO加RC电路去“强驱”LCD,不仅占用大量引脚,而且软件刷新一碰上中断就容易闪屏、鬼影。后来大家学乖了,用HT1621、PCF8562这类专用驱动芯片,把显示部分独立出来,MCU只负责往芯片里写显示RAM就行。
键盘扫描这边又是另一套逻辑。矩阵键盘本质上是一组行列交叉的开关,扫描时需要对每一行输出电平,再读每一列的状态。如果用MCU直接扫,行多了以后不仅要占用IO,还避不开按键消抖、组合键、低功耗唤醒这一堆事情。于是常见的做法是再加一颗专用的键盘扫描芯片,或者用带键盘扫描矩阵功能的MCU。
麻烦就麻烦在这里:LCD一片、键盘一片、MCU还要管理两片芯片的交互协议。PCB上多两颗器件、多一截走线、固件里多两套驱动代码,调试时还得分别排查显示问题和按键问题。量大的产品对BOM成本非常敏感,少一颗芯片就能省不少钱,少一套驱动代码就能省几周的开发时间。
1.2 FZH1643能扛下哪些活
FZH1643这颗芯片的定位非常明确:它就是把上面两件事合成一件。它内部集成了LCD驱动器和键盘扫描器,两者通过一组寄存器统一管理,对外只留一个I2C从机接口,主控MCU通过I2C就能同时控制显示和读取按键状态。
我理解的“双模式切换”在这里有两层含义。第一层是芯片自身的运行模式,你可以把它配置成“受控模式”:所有LCD段码的亮灭完全由主控通过I2C写入显示RAM决定,键盘扫描结果也需要主控主动读取;也可以切换成“自动模式”:芯片按照事先配置好的显示内容和刷新节奏自主运行,键盘扫描到有效按键后主动通过INT引脚通知主控,主控只需在中断里读一下键值寄存器即可。第二层是在低功耗场景下,主控休眠时关闭显示刷新但保留键盘扫描唤醒功能,这本质上也是一种模式切换。
从硬件资源上看,FZH1643提供了足够的COM/SEG引脚来驱动常见的段码LCD屏,4×4、5×4这类矩阵键盘也在它的扫描能力范围内。因为所有功能都挂在I2C寄存器层面上,所以主控这边的软件代码量可以压缩到非常小,几段基础的I2C读写函数加一个状态机,就能把显示和按键全部管起来。
对中小型电子产品的研发团队来说,这种一体化的意义不只是省一颗芯片。更关键的是它让硬件架构变得简单:一个I2C总线、一个INT中断脚、一套寄存器接口,工程师不需要同时熟悉两种芯片的数据手册,维护成本也低了很多。
2. 硬件设计:接线之前先把逻辑理清楚
2.1 典型应用电路与引脚分配
拿到FZH1643之后,不要急着画板子,先把器件手册里的引脚定义看明白。我手头这颗芯片的典型应用电路大概是这样的:VDD接3.3V或者5V电源,GND接地,SDA和SCL各接一颗上拉电阻到VDD,INT作为开漏输出接到MCU的外部中断输入引脚,然后所有按键的行线、列线分别接到芯片的键盘扫描引脚,LCD的COM和SEG走线直接连到液晶屏。
我一般习惯在SDA和SCL上各放一颗4.7kΩ的上拉电阻。如果I2C总线上还挂了其他设备,阻值要根据总线上拉电容统一算一下,走线比较长的场景可以用2.2kΩ增强驱动能力。INT引脚确认是开漏输出后,多半也要加一颗上拉电阻,否则MCU检测不到正确的高电平状态。
电源去耦这块不能图省事,FZH1643的电源引脚旁边至少要放一颗100nF的陶瓷电容,如果在比较嘈杂的电源环境下工作,建议再并一颗1μF~10μF的电容。键盘扫描瞬间会产生电流跳变,显示刷新也有周期性负载,电源纹波过大容易让I2C通信出错,甚至让段码显示亮度不均。
芯片上的A0、A1之类的地址配置引脚,是用来设置I2C从机地址的。我在一个项目里同时用过两颗FZH1643,分别驱动主屏和副屏,靠这两脚把地址区分开就行,不然两颗芯片抢在同一个地址上,I2C总线直接没法用。
2.2 段码驱动的COM/SEG映射逻辑
段码LCD的显示原理可以这么理解:LCD上的每一位数字,是由若干段笔划组成的,比如一个“8”字形数字,总共七段,再加上小数点就是八段;COM和SEG的交叉点就是每一段的电极。FZH1643输出COM扫描信号和SEG数据信号,在某一时刻选中一组COM,同时在SEG线上施加对应电平,这个交叉点的液晶分子就在电场作用下偏转,形成可见的笔划。
实际接线时,LCD屏的COM脚要对应接到FZH1643的COM0~COM3,SEG脚按屏的管脚顺序接到SEG0~SEGn。建议在原理图阶段就把每根SEG线对应到哪个段位拉一张表记录下来,例如“SEG0 = 温度十位 a段,SEG1 = 温度十位 b段……”。这张表后面写驱动代码、做显示数据位映射的时候就是黄金字典,省去反复翻屏厂规格书的痛苦。
有一种常见错误是COM和SEG接反。有些初学者会想当然地以为COM只接公共端,其实COM线如果错位,最典型的症状就是显示内容错乱、多个数字糊成一团。通讯和按键接口的逻辑电路并不难,真正费心思的就是这些与LCD物理引脚一一对应的映射关系,一定在量产出图前仔细核对几次。
2.3 键盘矩阵扫描的连接与防冲突
键盘矩阵的连接方式相对简单。以4x4矩阵为例,行线接R0~R3,列线接C0~C3,按键放在每个行列交叉点上。FZH1643内部有行扫描驱动电路,扫描时轮流将一行拉低,同时读取各列的状态,有键按下时对应的列会被拉低,芯片就能通过行列组合判断是哪个键被触发。
这里要注意一个细节:如果面板上还同时接了其他外部上拉或者下拉电阻,要和芯片内部的按键扫描电路匹配好,否则可能出现某一行、某一列的检测电平永远不对的问题。我在早期调试时遇到过按键一直显示被按下的情况,查到最后发现是那根列线被一个不必要的100kΩ下拉电阻钳到了低电平,芯片自然读什么都像是按键闭合。
硬件设计阶段还有一个容易忽略的点,就是键盘走线和LCD段码走线之间的干扰。LCD扫描波形是周期性变化的交流信号,如果键盘扫描线跟长距离的SEG线贴着走,寄生电容会把LCD的扫描信号耦合到键盘线上,轻则导致按键阈值偏移,重则出现“按一个键触发两个键”的幻象按键。我的建议是键盘线之间留出间距,并且尽量和LCD驱动线保持一定距离,必要时加地线隔离。
3. 软件驱动:双模式切换与I2C通信是核心
3.1 I2C通信基础与从机地址配置
FZH1643对外只提供了一个I2C接口,所有操作都是通过读写寄存器来完成的。I2C这套协议咱们都很熟了:主机先发起START,发送从机地址加读写位,然后等待从机ACK,接着收发数据,最后STOP结束通信。
从机地址由硬件引脚A0、A1决定,每颗芯片可以在几个固定地址之间选择。我习惯在固件里用宏定义把从机地址写清楚,例如:
#define FZH1643_ADDR_BASE 0x70 // 由A0、A1决定的具体值需要查手册 #define FZH1643_WRITE (FZH1643_ADDR_BASE << 1) #define FZH1643_READ ((FZH1643_ADDR_BASE << 1) | 0x01)注意这里的左移一位是因为I2C地址字节的低位是读写标志。实际地址值以你手里那批芯片的丝印和手册为准,不同封装批次的默认地址也可能存在差异,贴片前最好确认一下。
通信时序方面,FZH1643支持标准模式和快速模式,常用的I2C时钟在100kHz到400kHz之间。裸机驱动时我一般写一个基础的I2C主机函数,不需要依赖MCU的硬件I2C外设,用GPIO模拟也可以用。重点是要保证时序正确,尤其是时序紧张时要加一点延时,否则从机容易丢掉数据。
3.2 寄存器框架与工作模式定义
FZH1643的寄存器并不多,大致可以分为控制寄存器、显示数据寄存器、键盘状态寄存器这几类。控制寄存器主要负责系统使能、模式切换、LCD偏压与帧率配置、按键扫描参数配置,显示数据寄存器则用来存放每一段位对应是亮是灭,键盘状态寄存器保存最近一次扫描到的键值。
具体寄存器位定义得按数据手册来,我在这里给出的是逻辑框架。比如一个MODE位,设置成0就是受控模式,置成1就是自动模式;还有显示使能位、扫描使能位、INT使能位等。配置这些控制位的时候,我的建议是“先写配置,再开使能”,避免芯片在配置还没写完的时候就开始执行扫描和刷新动作,输出一堆不可预知的状态。
关于“双模式切换”,我的做法是在驱动层封装两个入口:
fzh1643_set_mode_normal():切到受控模式,主控主动写入显示RAM,主动读取按键状态。fzh1643_set_mode_auto():切到自动模式,芯片自动扫描键盘并输出显示,只有按键事件触发INT中断通知主控。
实际产品里,正常工作时用自动模式能减轻MCU负担,而做产测、单步调试的时候切回受控模式,可以精确控制每一位段码的状态,排查显示问题非常方便。
3.3 初始化与模式切换的完整流程
FZH1643的上电初始化建议按下面的顺序走:
- 拉高SDA、SCL,等电源稳定至少10ms。
- 通过I2C写入软件复位命令(如果芯片支持)。
- 配置LCD偏压、占空比、帧率等显示参数。
- 配置键盘扫描行列数、消抖时长、INT触发条件。
- 清除显示RAM和键盘状态寄存器,确保上电不出现乱码。
- 使能显示输出,切换到目标工作模式。
一段典型的裸机初始化代码可以长这样:
void fzh1643_init(void) { i2c_start(); i2c_write_byte(FZH1643_WRITE); i2c_write_byte(REG_SYS_WAKEUP); // 示例寄存器地址 i2c_write_byte(0x01); i2c_stop(); i2c_start(); i2c_write_byte(FZH1643_WRITE); i2c_write_byte(REG_LCD_CFG); i2c_write_byte(0x1A); // 偏压、占空比配置,具体数值查手册 i2c_stop(); i2c_start(); i2c_write_byte(FZH1643_WRITE); i2c_write_byte(REG_KEY_CFG); i2c_write_byte(0x43); // 4行4列、消抖周期配置 i2c_stop(); i2c_start(); i2c_write_byte(FZH1643_WRITE); i2c_write_byte(REG_MODE); i2c_write_byte(0x03); // 使能LCD + 键盘扫描,同时启用INT i2c_stop(); }这段代码展示的是先发寄存器地址、再发数据的常见写寄存器流程。不同芯片对“连续写多个数据字节”的支持程度不一样,稳妥起见我每次操作只处理单个寄存器,速度慢点但可靠,适合产品固件。
模式切换函数也很直接:
void fzh1643_switch_mode(uint8_t mode) { uint8_t reg_val; reg_val = fzh1643_read_reg(REG_MODE); if (mode == MODE_AUTO) { reg_val |= 0x02; // 置位自动模式 } else { reg_val &= ~0x02; // 清掉自动模式位 } fzh1643_write_reg(REG_MODE, reg_val); }切换模式前后最好把显示缓冲区和键盘键值寄存器清一遍,否则旧数据会在新模式下继续生效,表现成“切换后按键反应迟钝”或者“屏幕残留内容”。
3.4 LCD显示数据如何写入显示RAM
在受控模式下,主控需要把待显示的段码映射数据写入芯片的显示RAM。这里的核心是理解“每一位显示段对应RAM里的一比特”。你需要在代码里维护一个显存数组,数组每个bit代表一个段,然后再把这个数组通过I2C整体发送给芯片。
显示一个温度数字的示例逻辑:
static const uint8_t seg_code[10] = { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F, // 9 }; void display_temperature(int temp) { uint8_t tens = temp / 10; uint8_t ones = temp % 10; display_buffer[0] = seg_code[tens]; display_buffer[1] = seg_code[ones]; fzh1643_write_display_ram(display_buffer, sizeof(display_buffer)); }实际项目中显示缓冲区的内容不可能这么简单,可能还有小数点位、状态图标、特殊符号,但原理是一样的:先组好显存数组,再一次性推给芯片。把整个显存数组连续写过去的好处是,芯片内部显示RAM是连贯的地址空间,一次I2C写突发就能更新完整屏,可以有效避免逐段写入时出现闪烁。
还有一个容易踩的坑:显示RAM的数据格式不一定和你的数字段码表一致。有些芯片要求段位按SEG引脚顺序排列,有些则按段码地址排列,所以同一个0x3F在不同芯片上显示出的数字可能完全不同。第一次点亮屏的时候,建议逐段点亮来验证映射关系,再决定最终使用的段码表。
3.5 键盘扫描结果读取与INT中断协作
键盘扫描这部分,FZH1643的优势在于它把扫描时序完全接管了。主控不需要像轮询矩阵那样频繁翻转IO,只需要在INT引脚触发中断时读取键值寄存器即可。
我的推荐流程是:
- MCU外部中断配置成下降沿触发,因为INT引脚在检测到有效按键时会拉低。
- 中断服务程序里标记一个“按键事件”标志位,不做复杂处理。
- 主循环检测到标志位后,调用
fzh1643_read_key()读取键值,然后清除中断标志位。
读键值示例:
uint8_t fzh1643_read_key(void) { uint8_t key; key = fzh1643_read_reg(REG_KEY_STATUS); fzh1643_write_reg(REG_KEY_INT_FLAG, 0x01); // 清除INT标志 return key; }这里的关键点是“先读数据、再清标志”,顺序反了可能会导致一次按键事件被漏掉。还有,芯片的INT触发时机可能不止“按下”,还可能在“松开”时再触发一次。具体要看寄存器里有没有边沿选择位,如果松开也会触发中断,那业务层就需要对键值做去重处理。
芯片内部一般还有去抖逻辑,所以固件里不一定要再做一次完整的软件消抖。但为了稳妥,建议在读取到有效按键后加一个短延时,再读一次寄存器确认键值一致,防止在信号临界状态下误触发。
4. 调试实录:我踩过的坑和排查套路
4.1 I2C偶发无ACK或数据错乱
I2C的ACK问题是我在调试FZH1643时遇到最多的现象。明明上电后第一次初始化一切正常,跑一段时间后偶尔会出现某个寄存器读操作返回NACK,再往后显示开始乱跳、键盘也失灵。
排查这种问题我一般按以下顺序来:
- 量SDA、SCL波形,看边沿是否陡峭。如果边沿太缓,多半是上拉电阻阻值太大或者总线电容太大,换成2.2kΩ试试。
- 看电源引脚纹波。键盘扫描瞬间电流大,电源跌落会导致芯片数字逻辑异常。
- 检查I2C时序是否满足芯片的最小保持时间要求。用GPIO模拟I2C时,尤其要注意SCL低电平时SDA必须保持稳定。
- 在写寄存器后加一个极短的延时,让芯片内部完成处理,太频繁的命令流会造成芯片来不及响应。
如果I2C总线上还挂了其他设备,建议给FZH1643分配独立片选逻辑(如果没有片选引脚,就靠地址区分),至少确认地址设置没有冲突。
4.2 按键误触发、重复触发怎么解决
按键误触发最常见的原因有几个:一是键盘矩阵和LCD段码线之间的串扰,这在硬件层面要处理好;二是芯片消抖时间配置太短,手指接触瞬间的不稳定状态被当成有效键值;三是INT中断标志清理不及时,导致主控反复读到同一个键值。
软件层面的对策主要有三个:
- 适当调大芯片的消抖窗口。
- 主控读取键值后做一次“状态锁存”,同一个键值只有状态变化时才交给业务逻辑处理。
- 在键值处理完成后清理INT标志,避免中断堆积。
还有一个容易被忽略的点:如果用户按住按键不松手,芯片可能在按住期间重复触发INT。如果产品需求是“长按连续生效”,这没问题;如果只需要“单击一次生效”,业务层必须判断按住期间是否已经处理过该键值。
4.3 LCD显示乱码、段码异常发亮
显示乱码的问题,十有八九出在显存数据格式和硬件映射不一致上。我的调试技巧是写一个“全段扫描循环”:把显示RAM每一位依次点亮,再依次熄灭,观察屏上哪些段跟着亮,从而画出一张完整的SEG/COM到视觉段位的对照表。
如果某一根SEG上的所有段都异常,先量这根SEG引脚到屏之间的连接有没有断路、虚焊;如果某一个COM对应的整行段都不亮,问题往往出在COM信号上。还有那种“不该亮的段微微发亮”的问题,一般跟LCD偏压配置有关,也可能是刷新频率太低导致直流分量偏大,长时间使用会损伤液晶屏。
把芯片的帧率和偏压参数调成和LCD屏规格书一致,是解决这类显示质量问题的根本办法。屏厂会在规格书里写明推荐的工作电压和占空比,照着配就行,别自己瞎试。
4.4 模式切换后芯片“工作异常”怎么办
有几次我在从自动模式切回受控模式时,发现LCD显示内容变得不可控,按键也好像没反应了。排查下来的原因是我切换模式前没有把自动模式下保留在显示RAM里的旧数据清掉,也没有把芯片内部可能的扫描状态机复位回来。
现在我在切换模式时固定执行三步操作:第一步停掉LCD和键盘扫描使能;第二步清显示RAM和键值寄存器;第三步写新的模式配置并重新使能。这样切换过程干净稳定,不会再出现状态残留的问题。
另外,自动模式下芯片内部显示刷新时,主控写显示RAM可能发生冲突。如果芯片手册里没有提供“忙状态查询”,建议在切换回受控模式后再修改显示内容,避免在自动模式下频繁写显存导致界面跳动。
提示:所有寄存器地址和位定义以FZH1643芯片官方数据手册为准,上文代码里的寄存器名和数值只是为了展示编程思路,直接照抄不一定能跑通,建议对照手册逐个确认。
最后说点实战感受。FZH1643这类“LCD驱动+键盘扫描+I2C”三合一芯片,最值钱的地方并不是单颗芯片有多强,而是它把产品开发里最琐碎的两块外设管理打包成了标准接口。显示和按键之间天然存在协作关系,比如调温时显示内容要跟着按键实时变化,一体化芯片的INT+寄存器机制正好能让这种联动变得非常自然。我在实际项目中用这颗芯片做温控器面板,从画原理图到调通显示和键盘,前后只用了不到两周时间,而且后期量产没有出现一起显示或按键相关的客诉。如果你也正在做类似的人机交互显示方案,可以考虑拿它替代传统的“驱动芯片+键盘芯片”组合,应该能省下不少事。