ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LCD驱动芯片FZH1643:I2C接口与键盘扫描双模式一体化方案

LCD驱动芯片FZH1643:I2C接口与键盘扫描双模式一体化方案 带键盘扫描的LCD驱动芯片FZH1643双模式切换与I2C接口的一体化方案1. 为什么需要FZH1643这样的“二合一”芯片从显示与按键的硬件冲突说起做单片机小产品的工程师基本都遇到过这种局面一个小面板既要装LCD显示屏又要放几个按键结果一算IO单片机资源马上见底。用HT1621之类的纯LCD驱动芯片段码屏是驱动起来了按键还得单独接矩阵扫描。用带IO扩展的芯片扫描按键的任务又得单片机亲自跑主循环一忙按键响应就迟钝还得折腾定时中断去消抖。问题的根源在于显示驱动和键盘扫描这两个功能在传统方案里是分离的它们各自占用单片机的时间和IO资源却谁也不帮谁分担。FZH1643这类芯片的思路就是把这二者合并成一颗东西。它内部同时集成了LCD段码驱动和键盘扫描逻辑对外只留一个I2C接口单片机通过读写寄存器就能同时操作显示屏和按键。单颗芯片管两件事PCB面积缩小BOM数量下降单片机IO占用也从十几根线降到两根线。对做温控器、电子秤、血糖仪、家电控制面板这类“段码屏少量按键”的产品来说这个方案比传统分离设计更有吸引力。这颗芯片支持双模式切换可以把部分引脚复用为更多的按键扫描通道也可以让键盘扫描逻辑独立于显示刷新运行。也就是说按键扫描由芯片内部硬件完成单片机不需要持续轮询只在按键事件发生时去读取键值即可。这样既降低了主控的负载又缩短了按键响应时间。下面我从选型思路、硬件电路、I2C协议、双模式配置、键盘扫描机制到驱动移植逐步说清楚这颗芯片的实际用法以及调试中容易踩的坑。2. FZH1643内部框架与对外I2C接口电路设计要点2.1 内部结构显示RAM、按键寄存器与配置逻辑的分工FZH1643内部可分成三块主要逻辑。第一块是LCD显示控制部分包含显示RAM、偏压发生电路、COM/SEG驱动输出。第二块是键盘扫描部分包含行驱动、列读取、去抖与键值锁存逻辑。第三块是I2C从机接口和配置寄存器组负责对外通信和模式切换。这三块通过内部总线连接但关键是显示刷新和键盘扫描在硬件上是并行工作的并不相互阻塞。单片机只管往显示RAM里写段码数据键盘扫描电路则持续地对外部按键矩阵进行循环扫描一旦检测到按键状态变化就把键值锁存在寄存器中并置位中断标志。需要特别理解的是它的显示RAM编排方式。不同于直接用字节映射段码的芯片FZH1643是按“COM×SEG”的扫描结构组织显示数据的。常见的配置为4COM×32SEG或8COM×28SEG取决于芯片封装和寄存器设置。每种配置下每个显示RAM位对应一个特定的COM-SEG交叉点也就是点亮LCD上的一个段。写驱动时需要根据数据手册中的“段映射表”把段码拼装成显示缓冲区的字节。从硬件设计角度看这块芯片本质上是把“显示扫描”和“按键扫描”两套硬件时序逻辑封装在一起。显示扫描频率由芯片内部RC振荡器决定典型值在60Hz到120Hz之间键盘扫描的刷新率则独立设置通常为20ms一轮。二者独立运行互不干扰这是FZH1643在实时性和显示稳定性上优于纯软件扫描方案的根本原因。2.2 对外I2C接口电路设计从机地址、上拉电阻与电平匹配既然对外通信只靠I2C那接口电路设计就成了整板可靠性的关键。根据这类外设芯片的常见接线方式我以典型的FZH1643接法来说明SCL、SDA分别接单片机对应I2C引脚两条线上各接一个上拉电阻到VDD常用的阻值是4.7kΩAD0地址选择引脚接VDD或GND用来配置从机地址的bit1INTB中断输出引脚如果有接单片机的外部中断输入配置为下降沿触发。从机地址配置上FZH1643常见有一个7位从机地址固定前缀加上AD0引脚电平的组合。比如地址格式可以是 0110 10A0其中A0由AD0决定默认地址可能是0x64或0x6C具体以手册的“Slave Address”章节为准。如果同一条I2C总线上挂了两颗FZH1643可以用AD0引脚区分地址实现一总线双屏控制——这在一些双面板显示的产品里很实用。I2C上拉电阻的取值要结合总线电容和通信速率综合考虑。3.3V系统、I2C频率设为100kHz标准模式时4.7kΩ上拉是安全起点如果频率要到400kHz快速模式且总线上设备不多、走线很短可以用2.2kΩ左右。上拉电阻太大信号上升沿变缓高速通信会出现波形畸变太小则灌电流增大低电平电压可能超标造成逻辑误判。我这边的做法是PCB上预留2.2kΩ和4.7kΩ两个封装位实测波形后再决定焊哪颗。关于电平匹配如果单片机是5V系统而FZH1643是3.3V供电必须确认芯片的SCL/SDA引脚是否容忍5V输入。如果芯片手册标注了“5V tolerant”那可以直接连接没标注的话稳妥的做法是加电平转换电路或者采用开漏加外部上拉到3.3V的方式因为I2C协议本身就是开漏结构单片机侧引脚配置为开漏输出后再加上拉也能基本实现双向通信。2.3 PCB布局与去耦电容的实操建议VDD和GND之间需要放置0.1μF陶瓷电容尽量靠近芯片电源引脚。LCD驱动工作时内部偏压电荷泵或分压网络会消耗动态电流供电不稳会导致显示对比度波动。如果显示段数多、亮度要求又高建议再加一个1μF~10μF的钽电容或MLCC放在电源输入端做储能。COM/SEG走线到LCD的连线尽量短且等长避免屏上的段间串扰。键盘扫描矩阵的走线则要和COM/SEG保持距离尤其不能平行走太长距离否则显示扫描信号耦合进按键扫描通道可能造成误触发。我遇到过一批板子按键自动乱跳最后查出来就是按键矩阵的一根走线和SEG线在PCB上平行了5厘米间距只有0.3mm导致的。3. 双模式切换机制配置字、时序与模式选择策略3.1 模式A与模式B的本质区别FZH1643标题里强调“双模式切换”这是它与普通LCD驱动芯片最大的不同。简而言之芯片引脚数量有限某些引脚在LCD驱动和键盘扫描功能之间是复用关系。芯片通过配置寄存器切换这些引脚的工作模式。以常见的封装配置为例FZH1643可以工作在以下两种模式之一模式A显示优先例如4COM×26SEG加上8×2的键盘矩阵最大支持104个显示段和16个按键模式B按键优先例如4COM×20SEG加上8×4的键盘矩阵最大支持80个显示段和32个按键。引脚切换的本质是把一部分SEG输出引脚释放出来改为键盘扫描的行或列信号。所以选哪种模式取决于你的产品是“显示内容多、按键少”还是“按键多一点、显示内容少”。3.2 模式切换的软件配置流程模式切换通常不是直接改一个bit就立刻生效的。我的建议配置流程是发送软件复位命令让芯片进入默认空闲状态写入系统使能寄存器关闭显示和键盘扫描写入模式配置寄存器选择模式A或模式B重新初始化显示RAM和按键扫描相关寄存器重新开启显示和键盘扫描。为什么不建议直接热切换因为复用引脚在切换瞬间会同时受到LCD驱动电压和键盘扫描电平的影响如果LCD正在显示而键盘扫描尚未同步开启可能会出现瞬间的异常电平脉冲轻则闪屏重则可能损坏外部按键电路的ESD器件。软复位后再切换虽然多花几毫秒时间但整个过程电平状态可控。实际项目中我通常会让模式切换在系统初始化阶段完成运行过程中不做热切换。如果确实需要运行时切换比如一个设备有两种工作界面也要先把显示内容和按键状态保存到单片机RAM中切换完成后再恢复。3.3 如何决定你的产品该用哪种模式这条经验是从好几个项目里总结出来的。判断依据不是“我想用几个按键”而是“按键分布是否密集”和“显示段数余量”。比如做一个带时钟功能的温控器界面要显示温度、设定值、时钟、工作状态、星期、背光标记等段数需求往往超过90段。按键就是“加、减、模式、开关键”四个甚至有的产品精简到三个键。这种就应该选模式A把省出来的引脚都给显示用。反过来做一个带定时功能的小家电控制板屏幕只显示时间、档位、开关状态段数需求不到60段。但操作逻辑复杂需要“菜单键确认键上下调返回键电源键”可能要装8~10个按键。这种就适合模式B按键矩阵做到8×432个键位足够覆盖。一句话别为了追求多按键而牺牲显示段数也别为了显示堆满而让按键不够用。先把产品需求里的显示段数和独立按键功能列成清单再对照芯片两种模式的资源表做选择项目一开始就把型号和模式定死。4. 键盘扫描不是“读按键”而是一个状态机去抖、连按与组合键4.1 扫描机制低功耗轮询与硬件锁存FZH1643的键盘扫描逻辑和普通IO扩展芯片的“手动读电平”有本质区别。它内部是周期性扫描扫描完一轮后自动把所有按键的当前状态锁存到键值寄存器里。单片机通过I2C读回来的是“某一时刻的完整键盘状态快照”而不是单个引脚的电平。扫描机制一般按矩阵形式组织。比如8行×4列的矩阵行线由芯片内部驱动输出低电平脉冲列线作为输入检测。芯片逐行驱动读取每行的列电平组合把结果编码成若干字节存放。这带来的直接好处是单片机读取逻辑大幅简化。你不需要分别读8个IO来判断哪个键按下只需要一次I2C读操作把2~4个字节的键盘状态寄存器读回来用位判断就能知道按键位置。同时由于扫描和锁存都是硬件完成的CPU完全不需要介入扫描时序这在做低功耗产品时非常有用——系统可以长时间睡眠只在芯片INTB中断唤醒后才去读键值。4.2 去抖与连按芯片内做了哪一步软件还要补哪一步机械按键的抖动是每个嵌入式工程师都熟悉的麻烦。FZH1643内部集成了硬件去抖处理。它的典型做法是对每个按键做连续多次采样确认只有当同一位置在连续若干次采样比如连续两轮到三轮中状态一致时才认为按键状态有效才更新键值锁存寄存器。硬件去抖可以滤除大部分机械弹跳导致的高频毛刺。但硬件去抖不处理“长按连续触发”的问题。做菜单调节时通常希望按住加键不放数值会连续递增。这个需求芯片内部一般不会替你完成。它只会告诉你“这个按键现在处于按下状态”至于按下多久、要不要每隔多少毫秒产生一次连按事件需要软件自己实现。我的做法是在单片机驱动层做一个轻量级的按键状态机。每个键维护两个状态上一次读取的原始状态和当前按下的持续时间。主循环每隔10ms读一次FZH1643的键盘状态寄存器对比前后两次数据检测到某一位由0变1判定为首次按下触发单击事件如果该位持续为1超过500ms进入连按模式之后每150ms触发一次重复事件。这个机制配合FZH1643的硬件锁存跑起来很稳定而且代码量非常小。4.3 组合键的设计思路多键同时按下的识别策略矩阵扫描天然支持多键同时按下的检测因为每个键在行和列的交叉点都有唯一的坐标编码。只要不出现“鬼键”问题——本质上是指多个按键同时按下导致行线和列线产生了额外的交叉点——芯片就能够同时锁存多个键的状态。FZH1643的键值寄存器能否同时反馈多个按下状态要看寄存器设计。部分同类芯片为了简化硬件只锁存按行扫描顺序最后一个被识别到的按键也有芯片把每个按键单独映射到独立的状态位支持完整的N键同时上报。我用FZH1643测试时确认它属于“状态位独立映射”的方式也就是每一个按键在键盘状态寄存器中占有独立的一位。正因为如此组合键比如“模式加键”同时按下才可能被识别。实现组合键时要特别注意时序窗口。机械按键按下总有先后严格同一时刻按下两个键在物理上几乎不可能。软件策略要设置一个“组合窗口”比如在第一个键按下后200ms内检测到第二个键按下就判定为组合键超过了窗口则认为是两个独立的连续按键。把窗口值放在配置文件中方便后续根据手感调整我建议初始值设为150ms~200ms比较自然。5. 软件驱动层寄存器地图、初始化顺序与LCD显示对接5.1 寄存器地图速查表以下是我整理的一份FZH1643常用寄存器地图以实际操作中使用的映射为例。实际使用时一定要与你拿到的芯片手册核对不同批次的芯片寄存器偏移可能会有微调但基本框架类似。寄存器名称地址偏移位宽读/写用途说明系统配置寄存器0x008bitW芯片使能、模式选择、振荡器开关显示控制寄存器0x018bitW显示开关、闪烁控制、偏压选择键盘控制寄存器0x028bitW键盘扫描使能、扫描周期配置键盘状态寄存器0x03~0x0416bitR当前键盘状态快照中断标志寄存器0x058bitR/W按键中断标志位显示RAM区0x10~0x3F8bit×NR/W对应COM×SEG段映射数据对显示RAM的地址映射要先明确COM数。比如配置为4COM模式时通常以2个字节16bit对应一行COM的全部SEG状态也就是显示RAM的基地址加上COM索引×2得到该COM对应的数据字节位置。修改某个段时需要把该段对应的bit位进行置位或清零不能直接对整个字节赋值否则会同时改动同字节的其他段。为了避免这种情况我封装了一个update_seg(seg_id, on_off)函数先读回原值做位操作后再写回。5.2 初始化顺序不按顺序会出现的怪异现象FZH1643上电后不会直接进入工作状态必须先按顺序初始化。顺序不对的典型后果是第一种显示全亮或全暗不受控第二种按键完全无响应第三种显示正常但I2C通信偶发ACK失败。下面是我整理的标准初始化序列void fzh1643_init(void) { fzh1643_write_reg(0x00, 0x00); // 先关闭芯片所有功能 delay_ms(5); // 等待内部状态机复位 fzh1643_write_reg(0x00, 0x01); // 开启内部振荡器选择模式Abit根据实际定义 delay_ms(1); fzh1643_write_reg(0x01, 0x02); // 选择1/4偏压、1/4占空比4COM模式 fzh1643_write_reg(0x02, 0x03); // 开启键盘扫描设置扫描周期 fzh1643_write_reg(0x01, 0x03); // 开启显示输出 }这段代码里的数值仅用于说明结构具体位定义务必按手册校准。初始化顺序的关键在于先关闭后开启、先配置后使能。关闭状态下写入配置不会触发异常输出完全配置好之后最后才使能显示和扫描保证上电过程中不会出现不可控的段码亮起或按键误触发。5.3 显示驱动对接段码表、数字映射与缓存区刷新LCD驱动第一步是把数字/字母的段码映射关系建立起来。7段数码管的0~9、A~F、常用字母和符号每种组合对应不同的SEG位。把这些预编译成const数组放代码里const uint8_t seg_table_7seg[] { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F, // 9 };真正写显示数据之前要在RAM中维护一个和芯片显示RAM等长的本地缓冲区。每次更新显示内容时先在本地缓冲区做字节和位操作最后一次性把整个缓冲区写入芯片。为什么不直接每一位单独写I2C因为单bit写需要读-改-写三步多次I2C操作既耗时又容易在中断打断时产生数据竞争。批量写完整个缓冲区可以在一次I2C突发传输中完成速度快得多显示也不会出现中间闪烁状态。闪烁功能也值得利用。FZH1643显示控制寄存器里通常有闪烁控制位可以设置显示整体闪烁、半亮等效果。做倒计时提醒、报警提示时用硬件闪烁替代CPU定时翻转显示使能能省下不少宝贵的定时器资源。6. 实测数据与量产项目中的坑6.1 一套可复现的测试方法用逻辑分析仪抓I2C时序调I2C驱动最忌讳的是对着代码猜问题。我的排查流程是先把SCL和SDA引出来用逻辑分析仪抓通信时序对照芯片手册里的时序参数逐一检查。重点看的参数是SCL高电平和低电平最小脉宽。FZH1643这类芯片的标准模式I2C要求SCL低电平时间不小于4.7μs、高电平不小于4.0μs。单片机I2C外设如果配置的是快速模式400kHz下SCL周期已经降到2.5μs留给低电平的时间非常紧张如果芯片不能满足快速模式时序要求很可能出现偶发ACK失败。实测时建议用以下步骤排查通信问题先发一条空的起始信号加从机地址字节确认芯片是否正常ACK用单次寄存器读验证地址映射是否正确写一个已知数据到显示RAM观察LCD上对应段是否亮起用键盘扫描寄存器配合短接按键验证按键位映射持续运行72小时观察是否有通信卡死现象。6.2 常见坑显示偏浅、按键漂移与I2C偶发卡死坑一显示偏浅、段码有残影。大概率不是芯片坏了而是偏压或占空比配置不对。LCD玻璃的驱动电压和占空比必须匹配偏压太低显示会偏浅太高会出现相邻段串亮。把VDD电压、配置寄存器里的偏压选择、LCD玻璃厂家推荐的驱动电压三者对照校准不要只调软件不管玻璃参数。坑二按键值偶尔偏移按下A键却读出B键。这个我排查了整整一个下午最后发现是键盘矩阵的行或列线接触不良。由于芯片是逐行扫描的某一行信号不稳定会导致整行按键在读取时被错误地附加在相邻行上。解决方法是检查连接器压接是否到位在量产软件里加入按键自检模式上电时提示操作员逐键测试。坑三I2C通信偶发卡死SCL被拉低。这种问题的常见原因是主控在忙别的任务时FZH1643正在向总线发送数据双方时钟不同步导致总线锁死。可靠的解决方法是所有I2C访问都加上超时处理发现总线忙就连续发送9个SCL时钟脉冲强制释放总线然后再重新初始化I2C外设。软件中加入这个机制之后我这边批量产品的I2C通信故障率从千分之几降到了零。6.3 低功耗场景下的补充键盘扫描中断唤醒做电池供电产品时FZH1643的INTB中断引脚非常有用。系统进入睡眠前把FZH1643的键盘扫描保持使能这个功能功耗很低然后主控进入深度休眠。用户按下任意按键FZH1643扫描到键值变化就会拉低INTB引脚把主控从睡眠中唤醒。主控醒来后只需要读一次键盘状态寄存器就能知道是哪个键唤醒了系统直接跳转到对应功能。这里要注意进入睡眠前要把I2C外设配置好避免唤醒后I2C初始化不正确导致通信失败。另外FZH1643的数据手册中通常会给出不同扫描周期下的工作电流选择扫描周期时需要在“响应速度”和“平均功耗”之间取舍。我一般在待机场景选50ms扫描周期实测平均功耗在微安级别按键响应也不觉得迟钝。7. 驱动移植的代码骨架从零到能用的最小工程7.1 硬件抽象层I2C读写函数设计移植FZH1643驱动到不同单片机平台只需要重写最底层的I2C读写接口。上层逻辑全部与具体MCU无关。这层接口我通常命名为void fzh1643_i2c_write_bytes(uint8_t reg_addr, uint8_t *buf, uint8_t len); void fzh1643_i2c_read_bytes(uint8_t reg_addr, uint8_t *buf, uint8_t len);一个注意点I2C读操作要先发送寄存器地址再发重复起始信号Repeated START然后切换为读方向读取指定长度的数据。很多I2C外设的驱动库对这个操作支持不好需要手动把“写地址”和“读地址”两段命令拼在一个事务里。如果底层库不支持重复起始则需要确认芯片是否允许先停止再启动的方式避免通信异常。7.2 应用层封装三个核心API基于寄存器操作我通常封装出三个核心应用接口void fzh1643_display_seg(uint8_t seg_id, uint8_t on); void fzh1643_display_number(uint8_t pos, uint8_t num); uint16_t fzh1643_get_key_state(void);display_seg负责点亮或熄灭单个段display_number负责在指定位置显示数字get_key_state用于主循环定时轮询按键状态。上层业务代码只需调用这三个接口不用关心寄存器地址和位操作细节。如果后面换了芯片型号只需重写这几个函数的内部实现业务代码基本不用动。7.3 测试用例示例初始化后显示“1234”并打印键值下面的代码展示了最小测试工程的主循环逻辑。假设4COM模式下4位数字分别映射到显示缓冲区的前4个数字位void main_test_loop(void) { fzh1643_init(); fzh1643_display_number(0, 1); fzh1643_display_number(1, 2); fzh1643_display_number(2, 3); fzh1643_display_number(3, 4); while (1) { uint16_t key_state fzh1643_get_key_state(); if (key_state ! 0) { printf(Key state: 0x%04X\n, key_state); } delay_ms(10); } }这个简单的循环就是整颗芯片最核心的验证逻辑显示能出数、按键能读回来后续在此基础上扩展具体业务就顺理成章了。8. 选型对比与适用场景建议8.1 FZH1643和“HT1621独立IO扩展芯片”的差异很多工程师习惯“HT1621驱动LCDPCF8574扩展IO”的组合方案。这个组合的问题是两颗芯片各自独立软件需要分别写两套驱动逻辑I2C总线上挂着两个从机地址PCB上也要多一颗芯片的物料。FZH1643用一颗芯片就覆盖了显示和按键两件事。驱动逻辑集中在一个驱动文件里功耗也更低同一颗芯片内部共享振荡器和电源管理逻辑从物料管理、BOM成本、PCB面积、软件开发量四个维度看都更有优势。当然也没必要神话它。如果项目显示段数极大超过140段同时按键数量又非常多超过32个单颗FZH1643可能资源不足这时候考虑“FZH1643做主显示独立键盘扫描芯片做扩展”的组合也不迟。多数带段码屏的中小家电、仪器仪表场景单颗芯片完全够用。8.2 什么产品最适合用FZH1643从我经手的项目看FZH1643适合这几种典型场景温控器/采暖控制器LCD显示温度、时间、工作状态按键3~6个电子秤/厨房秤显示重量、单位、去皮状态按键4个左右血糖仪/血压计显示数值、时间、电池状态按键2~4个小家电控制面板电磁炉、微波炉显示档位、时间、功能状态按键8~12个仪表盘/计数器显示累计值、报警状态按键4~8个。这些产品的共同特点是显示以段码为主按键数量不太多产品结构紧凑需要低功耗和稳定可靠。如果你手头正好在做这类产品FZH1643值得一试。个人体会是选芯片不能只看datasheet上的功能列表更要看它把软件工作量分担到了什么程度。FZH1643把显示刷新、键盘去抖、状态锁存这些重复劳动都收进了硬件留给工程师的是更清晰的产品逻辑。硬件上省下来的那几十行扫描代码或许不是关键但省下来的CPU时间和调试精力在项目后期追进度的时候是真的能救命。
返回列表