IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于RK3399Pro的TM1650键盘读取-IIC总线 -> 正文阅读

[嵌入式]基于RK3399Pro的TM1650键盘读取-IIC总线

目录

原理图

IIC总线简介

tm1650的特性

按键读写时序图

?数据命令设置

程序代码编写

添加设备树

驱动编写

匹配设备节点

文件探索

杂项设备

文件操作集

键值读取接口

IIC读取接口

上层应用代码

编写Makefile文件

测试步骤

编译源码

加载驱动

执行测试程序

实验现象


重要提示:

博客评审专家需要一定的粉丝,所以之后写的文档设置权限粉丝可见,还望谅解。

原理图

TM1650采用的是IIC接口。

IIC总线简介

IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的一种简单、双向、二线制、同步串行总线

  • 起始状态:当SCL保持“高”时,SDA由“高”变为“低”;

  • 结束状态:当SCL保持“高”时,SDA由“低”变为“高”时;

  • 有效数据位传输:SDA线上的数据在SCL“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。SCL高电平期间为传输的数据位;

  • 空闲状态:IC 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态;

应答信号和非应带信号:I2C 总线上的所有数据都是以 8 位字节传送的,发送器(主机)每发送一个字节,就在第9个时钟脉冲期间释放数据线,由接收器(从机)反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。对于反馈有效应答位 ACK 的要求是,接收器在第 9 个时钟脉冲之前的低电平期间将 SDA 线拉低,并且确保在该时钟的高电平期间为稳定的低电平。//第9位为从机反馈的应答信号,若为高电平则没有接受成功。

?

  • IIC读时序

  • ? IIC写时序

tm1650的特性

TM1650 是一种带键盘扫描接口的 LED(发光二极管显示器) 驱动控制专用电路。 内部集成有 MCU输入输出控制数字接口、数据锁存器、LED 驱动、键盘扫描、辉度调节等电路。TM1650 性能稳定、质量可靠、抗干扰能力强,可适用于 24 小时长期连续工作的应用场合。

按键读写时序图

读写的键盘值对应表格如下所示:

?数据命令设置

B7B6B5B4B3B2B1B0说明
01001000模式命令
01001xx1读取按键数据命令

读取键盘的命令位0x49

程序代码编写

添加设备树

在设备树

arch/arm64/boot/dts/rockchip/rk3399pro-toybrick-prop-linux.dts 

中添加

&i2c6 {
        status = "okay";
        //i2c-scl-rising-time-ns = <800>;
        //i2c-scl-falling-time-ns = <200>;
        i2c-scl-rising-time-ns = <140>;
        i2c-scl-falling-time-ns = <30>;
        clock-frequency=<400000>;
        
        tm1650:tm1650@24{
                status = "okay";
                compatible = "tm1650";
                reg = <0x24>;
        };
};

驱动编写

匹配设备节点

static const struct i2c_device_id i2c_id[] = {
    { "tm1650", 0 },
    { }, /* Terminating entry */
};
?
static struct of_device_id i2c_match[] = {
    {.compatible = "tm1650" },
    { },
};
?
MODULE_DEVICE_TABLE(i2c, i2c_id);
??
static struct i2c_driver i2c_driver = {
    .driver = {
        .name = "tm1650",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(i2c_match),
    },
    .probe = i2c_probe,
    .remove = i2c_remove,
    .id_table = i2c_id, 
};

文件探索

static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret;
    struct device_node *tm1650_node = NULL; 
    tm1650_client = client;
    
    printk("The match successful!\n");
    
    printk("client->addr = %x\n",client->addr);
    ret = misc_register(&gec3399_tm1650_misc);   //杂项设备
    if(ret < 0){
        printk("misc register error\n");
        goto err_register_error;        
    }
    
    tm1650_node = of_find_compatible_node(NULL, NULL,"tm1650"); 
    if(tm1650_node == NULL){
        printk("not node of compatible is tm1650\n");
        ret = -ENODEV;
        goto err_gpio_request;
    }
    
    printk("tm1650 dirve install succee\n");
    return 0;
?
err_gpio_request:
    misc_deregister(&gec3399_tm1650_misc);
err_register_error:
    return 0;
}

杂项设备

static struct miscdevice gec3399_tm1650_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "tm1650_drv",
    .fops = &gec3399_tm_fops,
};//杂项设备初始化

文件操作集

static const struct file_operations gec3399_tm_fops = {
    .owner = THIS_MODULE,
    .read = gec3399_tm_read,
};  //文件操作集结构体

键值读取接口

static ssize_t gec3399_tm_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    int ret;
    char data_buf = 0;
    
    //printk("<0>""sizeof(data_buf) = %d\nsizeof(tm() = %d\n",sizeof(data_buf),sizeof(value));
    msleep(250);
    //读取tm1650的值
    ret = i2c_read_byte(tm1650_client,RDADDR,&data_buf,1);
    if(ret != 1){
        printk("%s %d i2c read byte data err\n",__FUNCTION__,__LINE__);
        //return -1;
    }
    //value = (data_buf[0]<<8) | (data_buf[1]<<0);
    //printk("<0>""value = %d\n",data_buf);
    //按键值上报给用户空间
    ret = copy_to_user(buf, &data_buf, sizeof(data_buf));
    if(ret < 0){
        printk("<0>""%s %d err copy tm value to user\n",__FUNCTION__,__LINE__);
        return -EFAULT;
    }
    return ret;
}
?

IIC读取接口

static int i2c_read_byte(struct i2c_client * client, uint8_t reg, uint8_t * buf, int len)
{
    struct i2c_msg msgs[2];
?
    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 1;
    msgs[0].buf = &reg;
?
    msgs[1].addr = client->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = len;
    msgs[1].buf = buf;
?
    if(i2c_transfer(client->adapter, msgs, 2) != 2)
        return 0;
    return 1;
}

上层应用代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>
?
int fd_tm = 0;
short tm_value = 0;  
?
int main(void)
{
    int ret;
    
    //打开设备节点 
    fd_tm = open("/dev/tm1650_drv", O_RDWR);
    if(fd_tm < 0)
    {
        perror("open tm_drv driver");
        return -1;      
    }

    while(1)
    {
        //读取键盘的按键值
        ret = read(fd_tm,&tm_value,1);
        if(ret<0)
        {
            perror("read error\n");
            return -1;
        }
        //打印出按键的按键值
        printf("tm_value = %xH \n",tm_value);   
        sleep(1);
    }
    close(fd_tm);
    
    return 0;
}

编写Makefile文件

obj-m += tm1650_drv.o
KERNELDIR:=/file/RK3399Pro/rk3399pro_git_repo/kernel
PWD:=$(shell pwd)
?
default:
    $(MAKE)  -C $(KERNELDIR) M=$(PWD) modules
test:
    aarch64-linux-gnu-gcc tm1650_test.c -o tm1650_test  
?
clean:
    rm -rf *.o *.order .*.cmd *.ko *.mod.c *.symvers *.tmp_versions

测试步骤

编译源码

在ubuntu中输入:

make

得到驱动目标文件tm1650_drv.ko

输入:

make test

得到测试目标文件:tm1650_test

加载驱动

在开发板命令终端输入:

insmod tm1650_drv.ko

执行测试程序

在开发板命令终端输入:

chmod 777 tm1650_test
./tm1650_test

实验现象

读取到键盘的按键值

root@linaro-alip:~/test# ./tm1650_test 
tm_value = 44H 
tm_value = 45H 
tm_value = 46H 

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-11-17 12:54:59  更:2021-11-17 12:56:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:24:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码