1、I2C扩展矩阵键盘
使用的是I2C接口的PCF8574扩展的4X4矩阵键盘,可以使用I2C和中断引脚扩展,这里使用的是I2C轮询方式去扩展。
2、判断芯片的地址
# i2cdetect -l #查看系统使能的i2c总线,这里只有i2c0一个
i2c-0 i2c mv64xxx_i2c adapter I2C adapter
# i2cdetect -r -y 0 //检测总线上的设备。-y表示省去交互式
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- 38 -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
这里显示I2C上挂了两个设备,0x50是存储芯片AT24C256,0x38应该就是PCF8574T的地址。
通过PCF8574的芯片手册和硬件原理图确认一下确实是0x38
按住不同的按键通过指令i2cdump的不同日志,可以进一步确定地址和硬件连接情况。
# i2cdump -f -y 0 0x38
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f .???????????????
10: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ????????????????
20: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./
30: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
40: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
50: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_
60: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno
70: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~?
80: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ????????????????
90: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ????????????????
a0: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ????????????????
b0: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ????????????????
c0: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ????????????????
d0: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ????????????????
e0: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ????????????????
f0: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ???????????????.
# i2cdump -f -y 0 0x38
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 00 01 02 03 04 05 06 07 00 01 02 03 04 05 06 07 .???????.???????
10: 10 11 12 13 14 15 16 17 10 11 12 13 14 15 16 17 ????????????????
20: 20 21 22 23 24 25 26 27 20 21 22 23 24 25 26 27 !"#$%&' !"#$%&'
30: 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 0123456701234567
40: 40 41 42 43 44 45 46 47 40 41 42 43 44 45 46 47 @ABCDEFG@ABCDEFG
50: 50 51 52 53 54 55 56 57 50 51 52 53 54 55 56 57 PQRSTUVWPQRSTUVW
60: 60 61 62 63 64 65 66 67 60 61 62 63 64 65 66 67 `abcdefg`abcdefg
70: 70 71 72 73 74 75 76 77 70 71 72 73 74 75 76 77 pqrstuvwpqrstuvw
80: 00 01 02 03 04 05 06 07 88 89 8a 8b 8c 8d 8e 8f .???????????????
90: 10 11 12 13 14 15 16 17 98 99 9a 9b 9c 9d 9e 9f ????????????????
a0: 20 21 22 23 24 25 26 27 a8 a9 aa ab ac ad ae af !"#$%&'????????
b0: 30 31 32 33 34 35 36 37 b8 b9 ba bb bc bd be bf 01234567????????
c0: 40 41 42 43 44 45 46 47 c8 c9 ca cb cc cd ce cf @ABCDEFG????????
d0: 50 51 52 53 54 55 56 57 d8 d9 da db dc dd de df PQRSTUVW????????
e0: 60 61 62 63 64 65 66 67 e8 e9 ea eb ec ed ee ef `abcdefg????????
f0: 70 71 72 73 74 75 76 77 f8 f9 fa fb fc fd fe ff pqrstuvw???????.
3、修改dts文件
&i2c0 {
status = "okay";
pcf8574t: pcf8574t@38 {
compatible = "pcf8574_keypad";
reg = <0x38>;
};
};
4、修改内核源码
1)I2C加中断方式:4.13内核源码中自带
文件路径:drivers/input/misc/pcf8574_keypad.c
2)I2C轮询方式
这里参考触摸屏代码:drivers/input/touchscreen/ns2009.c进行的修改。
5、验证
1)指令验证
# cat /proc/bus/input/devices #查看输入设备,event0是矩阵按键设备
I: Bus=0018 Vendor=0001 Product=0001 Version=0100
N: Name="pcf8574_keypad"
P: Phys=kp_data/input0
S: Sysfs=/devices/platform/soc/1c2ac00.i2c/i2c-0/0-0038/input/input1
U: Uniq=
H: Handlers=kbd event0
B: PROP=0
B: EV=3
B: KEY=14801 48000ffc
# cat /dev/input/event0 //按下不同的按键,会有不同的日志信息
# hexdump /dev/input/event0
2)应用程序验证
#include <stdio.h>
#include <linux/input.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int keys_fd;
char ret[2];
struct input_event t;
keys_fd = open("/dev/input/event0", O_RDONLY);
if(keys_fd<=0)
{
printf("open /dev/event0 device error!\n");
return 0;
}else
{
printf("open /dev/event0 device ok!\n");
}
while(1)
{
if(read(keys_fd,&t,sizeof(t))==sizeof(t)) {
//Type为EV_KEY时,value: 0表示按键抬起。1表示按键按下
if(t.type==EV_KEY && (t.value==0||t.value==1))
{
// printf("%d \n", t.code);
switch(t.code)
{
case KEY_1:
printf("KEY_1 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_2:
printf("KEY_2 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_3:
printf("KEY_3 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_4:
printf("KEY_4 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_5:
printf("KEY_5 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_6:
printf("KEY_6 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_7:
printf("KEY_7 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_8:
printf("KEY_8 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_9:
printf("KEY_9 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_0:
printf("KEY_0 %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_A:
printf("KEY_A %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_B:
printf("KEY_B %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_C:
printf("KEY_C %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_D:
printf("KEY_D %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_BACKSLASH:
printf("KEY_# %s\n",(t.value)?"Pressed":"Released");
break;
case KEY_RIGHTBRACE:
printf("KEY_* %s\n",(t.value)?"Pressed":"Released");
break;
default:
printf("Other KEY:%d %s\n",t.code,(t.value)?"Pressed":"Released");
break;
}
}
}
}
close(keys_fd);
return 0;
}
日志信息
# ./keypad_test
open /dev/event0 device ok!
KEY_1 Pressed
KEY_1 Released
KEY_2 Pressed
KEY_2 Released
KEY_3 Pressed
KEY_3 Released
KEY_4 Pressed
KEY_4 Released
KEY_5 Pressed
KEY_5 Released
KEY_6 Pressed
KEY_6 Released
KEY_7 Pressed
KEY_7 Released
KEY_8 Pressed
KEY_8 Released
KEY_9 Pressed
KEY_9 Released
KEY_0 Pressed
KEY_0 Released
KEY_* Pressed
KEY_* Released
KEY_# Pressed
KEY_# Released
KEY_A Pressed
KEY_A Released
KEY_B Pressed
KEY_B Released
KEY_C Pressed
KEY_C Released
KEY_D Pressed
KEY_D Released