![]() |
你的代码中,rowkey是通过((~KEYP) & 0x0f)获取的,这意味着你默认键盘的4行对应P2口的低4位(P2.0~P2.3) ,但行判断逻辑却写反了: - 代码中认为 rowkey=0x01(P2.0为低)对应第0行,但实际硬件中,按下不同行的按键,rowkey的“1”所在位是从高位到低位排列(比如第0行对应P2.3,rowkey=0x08;第3行对应P2.0,rowkey=0x01)。 - 这就导致只有第0行(rowkey=0x08)的按键能被错误识别为row=0,其余行的rowkey(0x04、0x02、0x01)无法匹配任何row,最终只能显示第0行的4个按键(0、4、8、C)。 |
从你提供的代码和现象(仅显示0、4、8、C)来看,问题核心在于行检测逻辑与键盘硬件接线的匹配错误,导致只能识别第0行的4个按键(对应0、4、8、C),其余行按键无法被检测。 |
skilldog 发表于 2025-8-15 21:34 明天看看这个办法ok不 |
WL0123 发表于 2025-8-16 07:30 包含的那个补丁?也用的8.17 sP5版本的. |
suiwinder 发表于 2025-8-15 16:42 用楼主的程序不做任何修改在Proteus 8.9 仿真,没有发现任何异常。加电显示“.”,按矩阵键盘依次显示0~F无误。可能是14楼所言的Proteus版本有Bug。 ![]() ![]() |
如果试过明明代码是正确的,别人可以成功仿真 但在你的电脑上就是怎么弄都不行 就代表Proteus有Bughttp://www.51hei.com/bbs/dpj-236577-1.html |
或試試比較簡單的改法 void scanner( void ) { u8 col, row; u8 rowkey, kcode; for( col = 0; col < 4 ; col ++ ) { KEYP = scan[col]; // 輸出到 P2.0 ~ P2.3 SEG7P = disp; if( KEYP != scan[ col ] ) { debouncer( ); if( KEYP != scan[ col ] ) { rowkey = ((~KEYP) & 0xf0); if( 0x10 == rowkey ) row = 0; else if( 0x20 == rowkey ) row = 1; else if( 0x40 == rowkey ) row = 2; else if( 0x80 == rowkey ) row = 3; kcode = (4* col + row); disp = TAB[ kcode ]; SEG7P = disp; } } } delay1ms(4); } |
試試看 #include <reg51.h> #define SEG7P P0 #define KEYP P2 #define u8 unsigned char u8 code TAB[] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0xa0, 0x83, 0xa7, 0xa1, 0x84, 0x8e, 0xbf, 0x7f }; u8 disp = 0x7f; // 高 4 位掃描碼,低 4 位全為 1(輸入高阻) u8 scan[] = { 0xE0 | 0x0F, 0xD0 | 0x0F, 0xB0 | 0x0F, 0x70 | 0x0F }; void debouncer(void) { u8 i; for (i = 2000; i > 0; i--); } void delay1ms(u8 x) { u8 i, k; for (i = x; i > 0; i--) for (k = 128; k > 0; k--); } void scanner(void) { u8 col, row; u8 rowkey, kcode; for (col = 0; col < 4; col++) { // 輸出掃描信號,高 4 位決定列,低 4 位保持輸入(全 1) KEYP = scan[col]; SEG7P = disp; // 讀取低 4 位(行)狀態 rowkey = KEYP & 0x0F; if (rowkey != 0x0F) // 有按鍵被壓下 { debouncer(); rowkey = KEYP & 0x0F; // 再讀一次確認 if (rowkey != 0x0F) { // 根據哪一位為 0 判斷行號 if (rowkey == 0x0E) row = 0; else if (rowkey == 0x0D) row = 1; else if (rowkey == 0x0B) row = 2; else if (rowkey == 0x07) row = 3; kcode = (4 * col + row); disp = TAB[kcode]; SEG7P = disp; } } } delay1ms(4); } void main(void) { while (1) { scanner(); } } |
人中狼 发表于 2025-8-15 19:59 没用,看来不对。 |
应该是rowkey = ((~KEYP) & 0x0f);有问题,用一个变量保存KEYP,然后在运算试试 |
joyb 发表于 2025-8-15 09:18 串口调试怎么调?还没接触到这部分内容。 |
WL0123 发表于 2025-8-15 09:54 其他算法很多,就是想知道这个算法为啥不行。 感觉应该是for循环里面列扫描那段,但是感觉也没问题,就是很奇怪为啥只能识别这几个。 |
zch5200 发表于 2025-8-15 10:18 约5年前我还真有客户要求用这种4x4的键盘。 |
zch5200 发表于 2025-8-15 10:18 有道理 |
学习单片机 以我做项目的经验。我个人建议学习I串口通讯,软硬件IIC,SPI,PWM,单口按键等等的功能实现,中断也很重要。最不要学的就是矩阵键盘,这个根本用不上,真正要用到很多按键的时候有现成的芯片比如TM1668数码管驱动和矩阵键盘。不会有IO口给你做矩阵。 |
void debouncer( void ) { u8 i; for( i = 2000; i > 0; i -- ); } u8 i; i最大只能到255,不可能=2000,应该是i = 200; |
你这写法不但不易理解,更容易发生逻辑错误。改如下写法易懂。![]()
|
(1) 单独测试数码管 // 测试数码管是否能显示0-F void test_display() { u8 i; for (i = 0; i < 16; i++) { SEG7P = TAB[i]; delay1ms(500); } } 如果数码管能正常显示0-F,说明问题在键盘扫描部分。 (2) 串口调试键值 // 通过串口打印键值(需初始化UART) void send_keycode(u8 kcode) { SBUF = kcode + '0'; // 发送ASCII码 while (!TI); TI = 0; } 这样可以确认键盘扫描是否正确检测到所有按键。 |
去掉上拉电阻试试 |