1. 为什么需要IO扩展做单片机开发的朋友应该都遇到过这样的烦恼项目需要的按键越来越多但单片机的IO口根本不够用。比如做一个8x8的矩阵键盘理论上需要16个IO口8行8列但很多低成本单片机根本没有这么多可用引脚。这时候就需要用到IO扩展芯片了。我最早接触这个问题是在做一个音乐控制器的时候需要64个按键但单片机只有20个IO口。当时试过用74HC138译码器发现灵活性太差。后来改用74HC595和74HC165组合方案只用6个IO口就实现了64键的扫描效果非常稳定。下面我就把这个实战经验分享给大家。2. 认识我们的核心器件2.1 74HC595串入并出移位寄存器74HC595可以说是IO扩展的瑞士军刀。它通过3根线数据、时钟、锁存就能控制8个输出引脚还能级联扩展更多输出。我把它比作一个快递分拣中心串行数据像快递包裹一样一个个进来SER引脚在时钟信号SCK的指挥下被分配到不同仓位内部移位寄存器最后统一出货RCK信号触发并行输出。实际使用时要注意几个关键点第10脚MR主复位通常接高电平第13脚OE输出使能建议直接接地级联时前一片的Q7接后一片的SER数据在SCK上升沿移入RCK上升沿锁存输出2.2 74HC165并入串出移位寄存器74HC165的功能正好与595相反它把8个并行输入转换成串行输出。想象成一个多车道合并成单车道的过程当PL引脚拉低时8个并行输入的状态被拍照保存然后在CP时钟上升沿时这些状态像车队一样一个个从Q7输出。使用技巧CLK_INH第15脚建议接地级联时前一片的Q7接后一片的DS数据采样在PL的下降沿输出在CP上升沿典型工作频率可达50MHz3. 硬件电路设计详解3.1 8x8矩阵键盘电路搭建用一片595控制行线一片165读取列线配合64个按键和二极管电路连接如下595的Q0-Q7接8条行线每条行线串联1kΩ电阻165的A-H接8条列线每个按键跨接在行线和列线之间每个按键并联一个1N4148二极管防鬼键关键这里有个容易踩坑的地方二极管方向要一致。我建议所有二极管的阴极接行线这样当行线输出低电平时按下按键的列线会被拉低。3.2 防鬼键设计原理鬼键问题就像三人成虎当三个特定位置的按键按下时会误判第四个按键也被按下。比如同时按下(1,1)、(1,2)、(2,1)时系统会误认为(2,2)也按下了。解决方法就是加入二极管让电流只能从行流向列。这样即使三个按键按下也不会形成第四条电流路径。实测发现用1N4148二极管效果很好正向压降约0.7V完全不影响检测。4. 软件实现与优化技巧4.1 扫描算法核心逻辑扫描流程可以概括为逐行激活读取列值595输出使能一行低电平165读取8位列线状态记录按键位置切换到下一行具体代码实现时我推荐用状态机方式管理按键状态。定义三个关键状态0未按下初始状态1稳定按下2释放过渡期enum KeyState { KEY_UP 0, KEY_DOWN 1, KEY_RELEASING 2 };4.2 软件消抖的工程实践机械按键抖动是躲不开的问题。我的解决方案是用计数比较法设置两个8x8数组KeyScan和KeyCount每次扫描检测到按下时KeyScan对应位置1每次扫描周期KeyCount所有位置1当KeyScan[h][l] - KeyCount[h][l] 阈值时判定为真实按下经过多次实测推荐阈值设为5约50ms。太短可能误触太长影响响应速度。对于CH552这类低速单片机可以在扫描间隔加入10μs的延时。5. 常见问题排查指南5.1 按键无反应的检查步骤先用万用表测量595输出是否正常检查165的PL信号是否正常跳变确认二极管方向是否正确测试单个按键短路时能否检测到检查软件扫描周期是否过快建议5-10ms5.2 鬼键现象复现怎么办如果还是出现误触发可以加大行线驱动电流减小限流电阻改用压降更小的肖特基二极管检查PCB走线是否有短路在165输入端加上拉电阻我在一个量产项目中就遇到过PCB漏电导致鬼键的问题后来在行线和列线之间加了1MΩ电阻才解决。6. 性能优化与扩展思路6.1 扫描速度优化技巧对于需要快速响应的场景如电子乐器改用SPI硬件接口驱动595/165减少消抖判定次数使用中断代替轮询对关键按键单独处理实测用硬件SPI可以将扫描周期缩短到1ms以内但要注意电磁兼容问题。6.2 更大规模的扩展方案如果需要16x16矩阵用两片595级联控制16行用两片165级联读取16列二极管数量增至256个扫描算法改为分组处理我曾经用4片5954片165做过32x32的LED点阵控制原理是相通的。关键是要处理好级联时的时序问题。
单片机IO扩展实战:用74HC595与74HC165构建8x8矩阵键盘的硬件设计与软件消抖
1. 为什么需要IO扩展做单片机开发的朋友应该都遇到过这样的烦恼项目需要的按键越来越多但单片机的IO口根本不够用。比如做一个8x8的矩阵键盘理论上需要16个IO口8行8列但很多低成本单片机根本没有这么多可用引脚。这时候就需要用到IO扩展芯片了。我最早接触这个问题是在做一个音乐控制器的时候需要64个按键但单片机只有20个IO口。当时试过用74HC138译码器发现灵活性太差。后来改用74HC595和74HC165组合方案只用6个IO口就实现了64键的扫描效果非常稳定。下面我就把这个实战经验分享给大家。2. 认识我们的核心器件2.1 74HC595串入并出移位寄存器74HC595可以说是IO扩展的瑞士军刀。它通过3根线数据、时钟、锁存就能控制8个输出引脚还能级联扩展更多输出。我把它比作一个快递分拣中心串行数据像快递包裹一样一个个进来SER引脚在时钟信号SCK的指挥下被分配到不同仓位内部移位寄存器最后统一出货RCK信号触发并行输出。实际使用时要注意几个关键点第10脚MR主复位通常接高电平第13脚OE输出使能建议直接接地级联时前一片的Q7接后一片的SER数据在SCK上升沿移入RCK上升沿锁存输出2.2 74HC165并入串出移位寄存器74HC165的功能正好与595相反它把8个并行输入转换成串行输出。想象成一个多车道合并成单车道的过程当PL引脚拉低时8个并行输入的状态被拍照保存然后在CP时钟上升沿时这些状态像车队一样一个个从Q7输出。使用技巧CLK_INH第15脚建议接地级联时前一片的Q7接后一片的DS数据采样在PL的下降沿输出在CP上升沿典型工作频率可达50MHz3. 硬件电路设计详解3.1 8x8矩阵键盘电路搭建用一片595控制行线一片165读取列线配合64个按键和二极管电路连接如下595的Q0-Q7接8条行线每条行线串联1kΩ电阻165的A-H接8条列线每个按键跨接在行线和列线之间每个按键并联一个1N4148二极管防鬼键关键这里有个容易踩坑的地方二极管方向要一致。我建议所有二极管的阴极接行线这样当行线输出低电平时按下按键的列线会被拉低。3.2 防鬼键设计原理鬼键问题就像三人成虎当三个特定位置的按键按下时会误判第四个按键也被按下。比如同时按下(1,1)、(1,2)、(2,1)时系统会误认为(2,2)也按下了。解决方法就是加入二极管让电流只能从行流向列。这样即使三个按键按下也不会形成第四条电流路径。实测发现用1N4148二极管效果很好正向压降约0.7V完全不影响检测。4. 软件实现与优化技巧4.1 扫描算法核心逻辑扫描流程可以概括为逐行激活读取列值595输出使能一行低电平165读取8位列线状态记录按键位置切换到下一行具体代码实现时我推荐用状态机方式管理按键状态。定义三个关键状态0未按下初始状态1稳定按下2释放过渡期enum KeyState { KEY_UP 0, KEY_DOWN 1, KEY_RELEASING 2 };4.2 软件消抖的工程实践机械按键抖动是躲不开的问题。我的解决方案是用计数比较法设置两个8x8数组KeyScan和KeyCount每次扫描检测到按下时KeyScan对应位置1每次扫描周期KeyCount所有位置1当KeyScan[h][l] - KeyCount[h][l] 阈值时判定为真实按下经过多次实测推荐阈值设为5约50ms。太短可能误触太长影响响应速度。对于CH552这类低速单片机可以在扫描间隔加入10μs的延时。5. 常见问题排查指南5.1 按键无反应的检查步骤先用万用表测量595输出是否正常检查165的PL信号是否正常跳变确认二极管方向是否正确测试单个按键短路时能否检测到检查软件扫描周期是否过快建议5-10ms5.2 鬼键现象复现怎么办如果还是出现误触发可以加大行线驱动电流减小限流电阻改用压降更小的肖特基二极管检查PCB走线是否有短路在165输入端加上拉电阻我在一个量产项目中就遇到过PCB漏电导致鬼键的问题后来在行线和列线之间加了1MΩ电阻才解决。6. 性能优化与扩展思路6.1 扫描速度优化技巧对于需要快速响应的场景如电子乐器改用SPI硬件接口驱动595/165减少消抖判定次数使用中断代替轮询对关键按键单独处理实测用硬件SPI可以将扫描周期缩短到1ms以内但要注意电磁兼容问题。6.2 更大规模的扩展方案如果需要16x16矩阵用两片595级联控制16行用两片165级联读取16列二极管数量增至256个扫描算法改为分组处理我曾经用4片5954片165做过32x32的LED点阵控制原理是相通的。关键是要处理好级联时的时序问题。