五 . 树莓派A20 I2C驱动程序


1 参考资料

1.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\input\touchscreen\Gt818_ts.c
2.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-core.c
3.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\include\linux\I2c.h
4.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-dev.c提供应用层接口
5.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-core.c提供核心层文件
6.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\busses\I2c-sunxi.c提供底层硬件驱动

1.1 I2C框架总图

I2C框架总图

2 I2C接口

2.1 函数接口

/*注册驱动*/
#define i2c_add_driver(driver) \
    i2c_register_driver(THIS_MODULE, driver)
/*注销驱动*/
void i2c_del_driver(struct i2c_driver *driver)
/*承载实际的数据传输*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

2.2 结构体

struct i2c_board_info {
    char        type[I2C_NAME_SIZE];
    unsigned short  flags;
    unsigned short  addr;
    void        *platform_data;
    struct dev_archdata *archdata;
    struct device_node *of_node;
    int     irq;
};
struct i2c_client {
    unsigned short flags;       /* div., see below      */
    unsigned short addr;        /* chip address - NOTE: 7bit    */
                    /* addresses are stored in the  */
                    /* _LOWER_ 7 bits       */
    char name[I2C_NAME_SIZE];
    struct i2c_adapter *adapter;    /* the adapter we sit on    */
    struct i2c_driver *driver;  /* and our access routines  */
    struct device dev;      /* the device structure     */
    int irq;            /* irq issued by device     */
    struct list_head detected;
};
struct i2c_driver {
    unsigned int class;

    /* Notifies the driver that a new bus has appeared or is about to be
     * removed. You should avoid using this, it will be removed in a
     * near future.
     */
    int (*attach_adapter)(struct i2c_adapter *) __deprecated;
    int (*detach_adapter)(struct i2c_adapter *) __deprecated;

    /* Standard driver model interfaces */
    int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    int (*remove)(struct i2c_client *);

    /* driver model interfaces that don't relate to enumeration  */
    void (*shutdown)(struct i2c_client *);
    int (*suspend)(struct i2c_client *, pm_message_t mesg);
    int (*resume)(struct i2c_client *);

    /* Alert callback, for example for the SMBus alert protocol.
     * The format and meaning of the data value depends on the protocol.
     * For the SMBus alert protocol, there is a single bit of data passed
     * as the alert response's low bit ("event flag").
     */
    void (*alert)(struct i2c_client *, unsigned int data);

    /* a ioctl like command that can be used to perform specific functions
     * with the device.
     */
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

    struct device_driver driver;
    const struct i2c_device_id *id_table;

    /* Device detection callback for automatic device creation */
    int (*detect)(struct i2c_client *, struct i2c_board_info *);
    const unsigned short *address_list;
    struct list_head clients;
};
struct i2c_device_id {
    char name[I2C_NAME_SIZE];
    kernel_ulong_t driver_data  /* Data private to the driver */
            __attribute__((aligned(sizeof(kernel_ulong_t))));
};

3 硬件原理图

使用风火轮出品的DVK521底板,其I2C硬件原理图如下所示:


I2C接口

找到数据手册中对应引脚描述:


I2C引脚描述

从这里可以看出,使用的是i2c1接口。

我在i2c1上外接的是FM24CL16芯片,该芯片容量为2KB。从机地址按照下图所示:


image.png

该模组链接地址为: 链接
原理图链接地址为: 链接

也就是如下图所示:

I2C模组图
原理图

按照上图,我们将短接帽设置在0上,也就是接地。那么,访问该芯片的地址就为0x50。

这里就直接给出一个测试例程:

#include <stdio.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <string.h>  
#include <linux/i2c.h>  
#include <linux/i2c-dev.h>   

#define SLAVE_ADDRESS 0x50 //FM24CL16芯片地址为0x50
#define I2C_DEV "/dev/i2c-1"//i2c_dev为i2c adapter创建的别名  
//读操作先发Slaveaddr_W+Regaddr_H+Regaddr_L 3个字节来告诉设备操作器件及两个byte参数  
//然后发送Slaveaddr_R读数据  
static int iic_read(int fd, char buff[], int addr, int count)  
{  
    int res;  
    char sendbuffer1[2];  
    //sendbuffer1[0]=addr>>8;  
    //sendbuffer1[1]=addr;  
    sendbuffer1[0]=addr;

    write(fd,sendbuffer1,1);        
    res=read(fd,buff,count);  
    //printf("read %d byte at 0x%x\n", res, addr);  
    return res;  
} 

//在写之前,在数据前加两个byte的参数,根据需要解析  
static int iic_write(int fd, char buff[], int addr, int count)  
{  
    int res;
    int i,n;
    char sendbuffer[2048+3];  
    memcpy(sendbuffer+1, buff, count);  
    sendbuffer[0]=addr;  
    res=write(fd,sendbuffer,count+1);  
    //printf("write %d byte at 0x%x\n", res, addr);  
}  

unsigned char wbuf1[2048];
unsigned char wbuf2[2048];
unsigned char wbuf3[2048];
unsigned char wbuf4[2048];
unsigned char wbuf5[2048];
unsigned char wbuf6[2048];
unsigned char wbuf7[2048];
unsigned char wbuf8[2048];

unsigned char rbuf[2048];

int main(void){  
    int fd;  
    int res;  
    char ch;  
 
    char buf[50];  
    int regaddr,i,slaveaddr;  
    fd = open(I2C_DEV, O_RDWR);// I2C_DEV /dev/i2c-0  
    if(fd < 0){  
        printf("####i2c test device open failed####\n");  
        return -1;  
    }

    if(ioctl(fd,I2C_TENBIT,0)<0)
    {
        printf("---set i2c bit error---\r\n");
        return -1;
    }

    if(ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS)<0)
    {
        printf("--set i2c address error---\r\n");
        return -1;
    }
    
    /*write data as 512Bytes once*/
    for(i = 0 ; i < 256 ; i ++)
    {
        wbuf1[i] = i;   
        wbuf2[i] = 255-i;   
        wbuf3[i] = i%256;   
        wbuf4[i] = 255-i;   
        wbuf5[i] = i%256;   
        wbuf6[i] = 255-i;   
        wbuf7[i] = i%256;   
        wbuf8[i] = 255-i;   
    }

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+0); 
    iic_write(fd,wbuf1,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+1);
    iic_write(fd,wbuf2,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+2);
    iic_write(fd,wbuf3,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+3);
    iic_write(fd,wbuf4,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+4);
    iic_write(fd,wbuf5,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+5);
    iic_write(fd,wbuf6,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+6);
    iic_write(fd,wbuf7,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+7);
    iic_write(fd,wbuf8,0,256); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS);
    iic_read(fd,rbuf,0,256); 
    printf("read page 0:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 


    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+1);
    iic_read(fd,rbuf,0,256); 
    printf("read page 1:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 


    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+2);
    iic_read(fd,rbuf,0,256); 
    printf("read page 2:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+3);
    iic_read(fd,rbuf,0,256); 
    printf("read page 3:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 


    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+4);
    iic_read(fd,rbuf,0,256); 
    printf("read page 4:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+5);
    iic_read(fd,rbuf,0,256); 
    printf("read page 5:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+6);
    iic_read(fd,rbuf,0,256); 
    printf("read page 6:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+7);
    iic_read(fd,rbuf,0,256); 
    printf("read page 7:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    return 0;  
}  

在程序编写上,需要着重注意的是访问的寄存器地址。由于我们的地址是8位的,所以,访问256B后面的数据,都是要两个以上的字节了,这个时候,我们就要用上内部的访问地址了。

简单的讲,就是要变换page。

4 通过I2C驱动ZLG7290前面板

4.1 sys_config.fex文件的配置

配置内容为:

[twi4_para]
twi4_used = 1
twi4_scl = port:PI02<3><default><default><default>
twi4_sda = port:PI03<3><default><default><default>
twi4配置

4.2 修改Kconfig和Makefile文件

在linux-sunxi/drivers/input/misc/目录下,修改Kconfig内容:

config INPUT_I2C7290
    tristate "I2C7290 Keyboard device"
    depends on I2C
    help
     Say Y here if you want to support a keypad connected via I2C
     with a ZLG7290(bad design by xxx).
     To compile this driver as a module, choose M here: the
     module will be called ZLG7290_keypad.

然后修改该目录下的Makefile文件:

obj-$(CONFIG_INPUT_I2C7290)     += keyboard_i2c7290.o

然后:

$ make menuconfig 
选中I2C7290

在linux-sunxi/drivers/input/misc/目录下,编写keyboard_i2c7290.c文件,内容如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/uaccess.h>

//#define KEYBOARD_I2C7290_DEBUG

#ifdef KEYBOARD_I2C7290_DEBUG
#define keyboard_i2c7290_debug(fmt, ...) printk(KERN_INFO "[KEYBOARD_I2C7290][BUG][%d]"fmt, __LINE__, ##__VA_ARGS__)
#else
#define keyboard_i2c7290_debug(fmt, ...)
#endif /* KEYBOARD_I2C7290_DEBUG */

#define keyboard_i2c7290_error(fmt, ...) printk(KERN_INFO "[KEYBOARD_I2C7290][ERR]"fmt"\n", ##__VA_ARGS__)

#define DRV_NAME "keyboard_i2c7290"

#define ZLG7290_SystemReg   0x00
#define ZLG7290_Key         0x01
#define ZLG7290_RepeatCnt   0x02
#define ZLG7290_FunctionKey 0x03
#define ZLG7290_CmdBuf      0x07
#define ZLG7290_CmdBuf0     0x07
#define ZLG7290_CmdBuf1     0x08
#define ZLG7290_FlashOnOff  0x0C
#define ZLG7290_ScanNum     0x0D
#define ZLG7290_DpRam       0x10
#define ZLG7290_DpRam0      0x10
#define ZLG7290_DpRam1      0x11
#define ZLG7290_DpRam2      0x12
#define ZLG7290_DpRam3      0x13
#define ZLG7290_DpRam4      0x14
#define ZLG7290_DpRam5      0x15
#define ZLG7290_DpRam6      0x16
#define ZLG7290_DpRam7      0x17

#define LED_ONOFF_CMD   0x01
#define LED_ON_MASK     0x80
#define LED_OFF_MASK        0x7F

#define LED_ON_CMD_U16(led_id)  (((((u16)(led_id | LED_ON_MASK)) << 8) | LED_ONOFF_CMD))
#define LED_OFF_CMD_U16(led_id) (((((u16)(led_id & LED_OFF_MASK)) << 8) | LED_ONOFF_CMD))

#define LED_IOCTL_ON        0
#define LED_IOCTL_OFF   1

#define I2C_DELAY_MS        2

struct UserKeyDataStru {
    unsigned int key_state : 8;     //按键状态[1:有键按下,0:没有按键按下(或功能键,此处不用)]
    unsigned int key : 8;           //按键键值
    unsigned int repeat : 8;        //连击计数器
    unsigned int reserved : 8;      //预留
};

struct KeyboardI2C7290DataStru {
    char *name;
    struct i2c_client *client;
    struct miscdevice misc;
};

//LED与按键的对应关系定义
typedef struct LedAndKeyInfoStru {
    unsigned char key;
    unsigned char led_id;
}LedAndKeyInfoStru_t;

struct KeyboardI2C7290DataStru kb = {.name = DRV_NAME};

const LedAndKeyInfoStru_t led_and_key[] = {
//  {.key = 1, .led_id = 0},
//  {.key = 2, .led_id = 8},
//  {.key = 3, .led_id = 16},
//  {.key = 4, .led_id = 24},
    {.key = 28, .led_id = 32},
    {.key = 27, .led_id = 40},
    {.key = 26, .led_id = 48},
    {.key = 25, .led_id = 56},
    {.key = 20, .led_id = 56},
    {.key = 19, .led_id = 4},
    {.key = 18, .led_id = 20},
    {.key = 5, .led_id = 24},
};

static int I2C_Gets(struct i2c_client *client, unsigned int SubAddr, char *dat)
{
    i2c_smbus_write_byte(client, SubAddr);

    *dat = (char)(0xFF & i2c_smbus_read_byte(client));

    return 0;
}

static int read_system_reg(struct KeyboardI2C7290DataStru *kb)
{
    char c = '\0';

    I2C_Gets(kb->client, ZLG7290_SystemReg, &c);

    return (int)(c & 0x01);
}

static int read_key(struct KeyboardI2C7290DataStru *kb)
{
    char c = '\0';

    I2C_Gets(kb->client, ZLG7290_Key, &c);

    return (int)c;
}

static int read_repeat_reg(struct KeyboardI2C7290DataStru *kb)
{
    char c = '\0';

    I2C_Gets(kb->client, ZLG7290_RepeatCnt, &c);

    return (int)c;
}

static void led_on(unsigned char key)
{
    int i = 0;
    u16 value = 0;

    for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
        if (led_and_key[i].key == key) {
            value = LED_ON_CMD_U16(led_and_key[i].led_id);
            i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
            keyboard_i2c7290_debug("value = 0x%04X\n", value);
        }
    }
}

static void led_off(unsigned char key)
{
    int i = 0;
    u16 value = 0;

    for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
        if (led_and_key[i].key == key) {
            value = LED_OFF_CMD_U16(led_and_key[i].led_id);
            i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
            keyboard_i2c7290_debug("value = 0x%04X\n", value);
        }
    }
}

static void led_off_all(void)
{
    int i = 0;
    u16 value = 0;

    for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
        value = LED_OFF_CMD_U16(led_and_key[i].led_id);
        i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
    //  keyboard_i2c7290_debug("value = 0x%04X\n", value);
        mdelay(I2C_DELAY_MS);
    }
}

static int keyboard_i2c7290_open(struct inode *inode, struct file *file)
{
    u16 value = 0;

    //关闭LED闪烁显示
    value = 0x0070;
    i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
    mdelay(I2C_DELAY_MS);

    led_off_all();

    return 0;
}

static int keyboard_i2c7290_close(struct inode *inode, struct file *file)
{
    led_off_all();

    return 0;
}

static ssize_t keyboard_i2c7290_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
    struct UserKeyDataStru user_data = {0};

    user_data.key_state = read_system_reg(&kb);
    if (user_data.key_state == 0) {
        //没有键按下
    } else {
        mdelay(I2C_DELAY_MS);

        user_data.key = (unsigned char)read_key(&kb);
        mdelay(I2C_DELAY_MS);

        user_data.repeat = read_repeat_reg(&kb);
    }
#if 0
    keyboard_i2c7290_debug("SysReg:%d\n", user_data.key_state);
    keyboard_i2c7290_debug("KEY: %d\n", user_data.key);
    keyboard_i2c7290_debug("Repeat: %d\n", user_data.repeat);
#endif
    if (copy_to_user(buf, (const void *)&user_data, sizeof(struct UserKeyDataStru)) == 0) {
        //Empty
    }

    return sizeof(struct UserKeyDataStru);
}

static long keyboard_i2c7290_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned char key =  *((unsigned char *)arg);

    keyboard_i2c7290_debug("Cmd: %d, Key: %d\n", cmd, (unsigned int)key);
    switch (cmd) {
    case LED_IOCTL_ON:
        led_on(key);
        break;
    case LED_IOCTL_OFF:
        led_off(key);
        break;
    default:
        break;
    }

    return 0;
}

static const struct file_operations keyboard_i2c7290_fops = {
    .owner              = THIS_MODULE,
    .open               = keyboard_i2c7290_open,
    .release            = keyboard_i2c7290_close,
    .unlocked_ioctl     = keyboard_i2c7290_ioctl,
    .read      = keyboard_i2c7290_read,
//  .write     = keyboard_i2c7290_write,
};

static int keyboard_i2c7290_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    struct miscdevice *misc = NULL;
    
    keyboard_i2c7290_debug("In %s\n", __FUNCTION__);

    keyboard_i2c7290_debug("Addr:0x%X, name:%s\n", client->addr, id->name);

    kb.client = client;

    misc = &kb.misc;
    misc->minor = MISC_DYNAMIC_MINOR;
    misc->name = DRV_NAME;
    misc->fops = &keyboard_i2c7290_fops;
    ret = misc_register(misc);
    if (ret) {
        keyboard_i2c7290_error("Unable to register a misc device\n");

        return -1;
    }
    keyboard_i2c7290_debug("Register a misc device Ok\n");


    return ret;
}

static int keyboard_i2c7290_remove(struct i2c_client *client)
{
    struct miscdevice *misc = NULL;

    keyboard_i2c7290_debug("In %s\n", __FUNCTION__);

    misc = i2c_get_clientdata(client);

    free_irq(client->irq, misc);
    misc_deregister(misc);


    return 0;
}

static const struct i2c_device_id keyboard_i2c7290_id[] = {
    {DRV_NAME, 0},
    { },
};

MODULE_DEVICE_TABLE(i2c, keyboard_i2c7290_id);

static struct i2c_driver keyboard_i2c7290_driver = {
    .driver = {
        .name   = DRV_NAME,
        .owner  = THIS_MODULE,
    },
    .probe      = keyboard_i2c7290_probe,
    .remove     = keyboard_i2c7290_remove,
    .id_table   = keyboard_i2c7290_id,
};

/*added by wit_yuan 2017-08-11*/
static struct i2c_board_info __initdata bfin_i2c_board_info4[] = {
#if defined(CONFIG_INPUT_I2C7290)
    {
        I2C_BOARD_INFO("keyboard_i2c7290", 0x38),
    //  .irq = IRQ_PE15,
    },
#endif
};


static int __init keyboard_i2c7290_init(void)
{
    printk("------keyboard_i2c7290_init----\r\n");
    i2c_register_board_info(4, bfin_i2c_board_info4, ARRAY_SIZE(bfin_i2c_board_info4));
    return 0;
}

static void __exit keyboard_i2c7290_exit(void)
{

    return ;
}


module_init(keyboard_i2c7290_init);
module_exit(keyboard_i2c7290_exit);



module_i2c_driver(keyboard_i2c7290_driver);

MODULE_AUTHOR("peace <whb_xxx@sina.com>");
MODULE_DESCRIPTION("Keyboard driver for I2c7290");
MODULE_LICENSE("GPL");

在树莓派A20上查看是否有keyboard_i2c7290设备:

root@marsboard:~# ls /dev/keyboard_i2c7290
/dev/keyboard_i2c7290

到这一步,就可以写测试程序keyTest.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>

#define KEY_DEV "/dev/keyboard_i2c7290"

struct UserKeyDataStru {
    unsigned int key_state : 8;         //按键状态[1:有键按下,0:没有按键按下(或功能键,此处不用)]
    unsigned int key : 8;               //按键键值
    unsigned int repeat : 8;            //连击计数器
    unsigned int reserved : 8;          //预留
};

//按键对应的LED状态定义
typedef struct LedAndKeyInfoStru {
    unsigned int key : 8;
    unsigned int led_state : 8;
}KeyAndLedStateStru_t;

static int fd = -1;

KeyAndLedStateStru_t led_and_key[] = {
    {.key = 1, .led_state = 0},
    {.key = 2, .led_state = 0},
    {.key = 3, .led_state = 0},
    {.key = 4, .led_state = 0},
    {.key = 28, .led_state = 0},
    {.key = 27, .led_state = 0},
    {.key = 26, .led_state = 0},
    {.key = 25, .led_state = 0},
    {.key = 20, .led_state = 0},
    {.key = 19, .led_state = 0},
    {.key = 18, .led_state = 0},
};

#define LED_IOCTL_ON    0
#define LED_IOCTL_OFF   1

static void led_onoff(unsigned int onoff, unsigned int key)
{
    if (fd < 0) {
        return;
    }

    if (onoff == 0) { //ON
        ioctl(fd, LED_IOCTL_ON, &key);
    } else { //OFF
        ioctl(fd, LED_IOCTL_OFF, &key);
    }
}

#define LED_ON_FUN(key)     led_onoff(0, key)
#define LED_OFF_FUN(key)    led_onoff(1, key)

static void key_led_onoff(unsigned int key)
{
    int i = 0;

    if (fd < 0) {
        return;
    }

    for (i = 0; i < (sizeof(led_and_key) / sizeof(KeyAndLedStateStru_t)); ++i) {
        if (led_and_key[i].key == key) {
            break;
        }
    }

    if (i >= (sizeof(led_and_key) / sizeof(KeyAndLedStateStru_t))) {
        return;
    }

    if (led_and_key[i].led_state == 1) {
        LED_OFF_FUN(key);
        led_and_key[i].led_state = 0;
    } else { //OFF
        LED_ON_FUN(key);
        led_and_key[i].led_state = 1;
    }
}

int main()
{
    struct UserKeyDataStru user_key_data = {0};

    fd = open(KEY_DEV, O_RDONLY);
    if (fd < 0) {
        printf("Error open %s\n\n", KEY_DEV);
        
        return -1;
    }           
    printf("[%d]Open %s Ok\n", fd, KEY_DEV);

    while(1) {
        if (read(fd, &user_key_data, sizeof(user_key_data)) < 0) {
            perror("read error");
            break;
        }

        if (user_key_data.key_state != 0) {
            printf("key = %d, repeat = %d\n", user_key_data.key, user_key_data.repeat);
            key_led_onoff(user_key_data.key);
        }
        
        usleep(500);
    }
    
    close(fd);

    return 0;
}

在树莓派A20上做测试,效果如下:


root@marsboard:~# ./keyTest
[3]Open /dev/keyboard_i2c7290 Ok
key = 20, repeat = 1
key = 26, repeat = 1
key = 27, repeat = 1
key = 28, repeat = 1
key = 19, repeat = 1
key = 20, repeat = 1
key = 26, repeat = 1
key = 27, repeat = 1
key = 28, repeat = 1
key = 1, repeat = 1
key = 5, repeat = 1
key = 5, repeat = 1
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容