Linux设备驱动第十四天(input子系统、去除抖动)

1,回顾linux内核I2C设备驱动实现过程
内核I2C驱动框架:
应用程序

open,close,read,write,ioctl…..

I2C设备驱动:
管理硬件:I2C外设本身;
关注用户操作的数据的特定含义;
不关注这些数据是如何通过总线传输;


SUMBUS接口:
给I2C设备驱动使用
I2C设备驱动利用SUBUS接口跟I2C总线驱动进行通信,实现I2C设备驱动和I2C总线驱动的数据交互


I2C总线驱动
管理硬件:I2C控制器
关注数据的硬件传输
不关注传输时的数据特定含义


硬件: I2C控制器 <===> I2C外设

I2C设备驱动程序如何实现:
分离思想:设备-总线-驱动模型

struct i2c_client:描述硬件信息
struct i2c_board_info:描述硬件信息,用于描述 i2c_client
struct i2c_driver:描述软件信息

SMBUS接口:
1,打开接口文档
2,打开I2C外设的芯片手册,获取时序图
3,根据时序图在SMBUS接口文档中找到对应的操作函数
4,在内核源码中找到这个接口函数的定义
5,在驱动使用之

谈谈I2C/谈谈你知道哪些硬件总线?


一线式总线:
单总线
一根数据线
一次传输1bit位
一根数据线可以挂接很多一线式接口的外设

三线制
两线制
前者有独立的电源
后者能通过数据线供电(内部集成了电容)

上拉电阻:总线的默认电平为高电平

问:CPU如何访问总线上的外设?
问:CPU如何通过一个根数据线和外设进行数据交互?
答:一线式总线操作协议上(芯片手册中)

以项目中实际使用的一线式接口的温度传感器DS18B20为例:
CPU访问DS18B20的操作步骤:
1,CPU向线总发送初始化复位信号(类似START信号)
2,CPU如何要访问某个外设,要发送ROM命令,进行匹配工作(类型地址)
3,一旦CPU找到了具体某个设备,CPU发送读写,温度转换命令操作命令,开始对设备进行读写访问和温度转换(类似I2C数据交互过程)

注意:一线总线不像I2C总线,有一根时钟控制信号号,一线式总线没有,只有一根数据线,如果CPU要送一个命令给外设,并且为了保证双方的数据交互能够正常完成,芯片手册给出了传输每一个bit的时序要求!


Linux内核input子系统:
管理的设备对象:USB键盘,PS/2键盘,触摸屏,鼠标,键盘,游戏摇杆,各种传感器
input子系统的目的作用:
1,让以上设备的驱动实现更加标准化;
比如设备文件名标准:/dev/input/event0,/dev/event1….
用户空间和内核空间数据交互涉及的数据结构采用标准
struct input_event
2,让底层驱动开发的我还以为核心内容放在硬件信息上,例如中断的注册,GPIO资源的申请,地址的映射等等,软件的操作信息,例如:xxx_open,xxx_close,xxx_read,xxx_write,xxx_ioctl都是由内核来实现!
3,input 提供一个数据结构和相关的操作函数给底层的驱动使用,用于将硬件信息注册到内核中,供内核的软件使用!

问:内核帮你实现的软件信息长什么样?
问:内核给底层设备驱动提供的描述硬件信息的数据结构和相关操作函数长什么样?
问:如何改造之前的按键驱动,编写成符合input子系统的驱动程序呢?

内核帮咱实现的统一的软件操作接口为:

  static const struct file_operations evdev_fops = {  
        .owner          = THIS_MODULE,  
        .read           = evdev_read,  
        .write          = evdev_write,  
        .poll           = evdev_poll,  
        .open           = evdev_open,  
        .release        = evdev_release,  
        .unlocked_ioctl = evdev_ioctl,  
        .fasync         = evdev_fasync,  
        .flush          = evdev_flush 
   }

操作接口的作用:为用户应用程序服务,应用程序访问底层硬件设备,首先通过系统调用跑到evdev_fops相关操作接口,例如,app:read-> ……->evdev_read

问:evdev_fops相关的操作接口最终要获取硬件信息(例如按键值和按键的状态),这些硬件信息来自底层的硬件设备驱动,问:底层设备驱动如何将硬件信息告知给evdev_fops相关的操作接口呢?
答:
内核给底层设备驱动程序提供了相关的数据结构和相关的操作方法用于实现底层设备驱动和evdev_fops相关操作接口之间的通信(传输硬件信息)。
“硬件信息”:这里涉及的硬件信息最终会上报给用户去使用
例如:按键的硬件信息:按键值和按键的状态
触摸屏的硬件信息:X,Y坐标值(绝对坐标)和触摸屏的操作状态和压力值
鼠标的硬件信息:X,Y坐标值(相对坐标)和方向,按键相关的信息,滑轮相关的相关
温度传感器的硬件信息:温度值

linux内核为底层设备驱动提供的数据结构和操作方法:

struct input_dev{
const char *name;    硬件设备名
const char *phys;      设备在系统中路径
const char *uniq;
struct input_id id;         用于匹配input hander参数
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];               
unsined long evbit[BITS_TO_LONGS(EV_CNT)];                        设备所支持事件类型,主要有EV_SYNC,EV_KEY,EV_REL,EV_ABS等       
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];                     按键所对应的位图
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];                       相对坐标对应位图
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];                       绝对坐标对应位图
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
unsigned int hint_events_per_packet;
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev,  const struct input_keymap_entry *ke,  unsigned int *old_keycode);
int (*getkeycode)(struct input_dev *dev, struct input_keymap_entry *ke);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int rep[REP_CNT];
struct input_mt_slot *mt;
int mtsize;
int slot;
int trkid;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)];                                 按键对应的键值
unsigned long led[BITS_TO_LONGS(LED_CNT)];                                  LED对应的指示灯状态
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);                                         
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);                  事件处理函数,主要是接收用户下发的命令,如点亮led;
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
bool sync;
struct device dev;
stuct list_headh_list;                    设备所支持的input handle; 
struct list_headnode;
};

const char *name; 设备名
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; 设备所支持事件类型,主要有EV_SYNC,EV_KEY,EV_REL,EV_ABS等
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 按键所对应的位图
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; 绝对坐标对应位图

以上结构体的作用:用于描述最终上报的硬件信息
成员说明:
name:硬件设备的名称
evbit:位图,用于描述这个硬件设备将来能够上报哪个事件类型,内核支持的事件类型:
#define EV_KEY 0x1 // 按键类事件
#define EV_ABS 0x3 //绝对位移坐标事件
#define EV_REP 0x14 //重复类事件
操作注意:例如要支持按键类事件,需要将对应的位图位置置1,如果还想支持重复类事件,同时再把对应的位图位置置1
set_bit(EV_KEY,evbit)
set_bit(EV_REP,evbit);

如果是触摸屏:
set_bit(EV_ABS,evbit);

keybit:位图,用于描述按键类事件将来有哪些按键值将会上报给用户,例如:
对应按键,支持上、下、左、右四个方向键:
set_bit(KEY_UP,keybit);
set_bit(KEY_DOWN,keybit);
set_bit(KEY_LEFT,keybit);
set_bit(KEY_RIGHT,keybit);

absbit:位图,用于描述绝对位移坐标事件中将来会上报哪些事件信息给用户,例如:上报X,Y坐标值:
set_bit(ABS_X,keybit);//将来上报X坐标值
set_bit(ABS_Y,keybit);//将来上报Y坐标值

底层驱动如何使用?
1,分配struct input_dev对象
struct input_dev *input = input_allocat_device(void);
2,初始化input_dev对象
对于按键硬件设备:
input->name = “tarena”;//指定硬件设备名称
set_bit(EV_KEY,input->evbit);//上报按键类事件
set_bit(EV_REP,input->evbit);//上报重复类事件
set_bit(KEY_UP,input->keybit);//上报上键
set_bit(KEY_DOWN,input->keybit);
set_bit(KEY_LEFT,input->keybit);
set_bit(KEY_RIGHT,input->keybit);
3,注册input_dev对象到内核中
input_register_device(input);
4,注意:
一个硬件设备对应一个struct input_dev对象
一个struct input_dev对象在用户空间就有对应的设备文件/dev/input/eventx(x=0,1,2,3),也就是说一旦注册一个input_dev对象,内核就会帮你创建这个硬件设备的设备文件(/dev/input/eventx)
但是多个硬件设备,多个input_dev对象共享一个操作接口(ev_dev_fops)

5,设备驱动利用input_event函数,将上报的硬件信息给内核的操作接口发送过去!

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

函数功能:给底层设备驱动使用,设备驱动利用此函数将具体的某个硬件信息丢给内核的evdev_fops相关操作接口中
参数:
dev:指向底层驱动分配的input_dev对象
type:上报的事件类型(EV_KEY,EV_REP,EV_ABS)
code:
如果是按键:指定一个按键值即可KEY_UP
如果是触屏屏,指定上报的坐标即可:ABS_X
value:
如果是按键,指定按键的状态,0 松开,1 按下
如果是触摸屏,指定的具体的坐标值

按键:KEY_UP按键按下,上报:

input_event(input,EV_KEY,KEY_UP,1);//按下
input_event(input,EV_KEY,KEY_UP,0);//松开

触摸屏:上报X坐标:

input_event(input,EV_ABS,ABS_X,x);//上报X坐标
input_event(input,EV_ABS,ABS_Y,y);//上报Y坐标
//其中,x,y为两个值

6,底层设备驱动再将驱动程序中涉及的硬件操作进行初始化即可:
地址映射
GPIO资源申请
中断注册

案例:优化按键驱动,将按键驱动采用input子系统来实现!


按键去抖动:
按键抖动的原因:按键硬件本身是一个机械结构(瞬间可能接触不良)!
按键实际的波形:
按键去抖的方法:

按键抖动产生的电平信号变化之间的时间间隔为5~10毫秒(经验值)
硬件去抖动:增加滤波电路,效果好,成本高
软件去抖动
最典型的方法:如果是单片机或者ARM裸板,一般采用延时(5-10个毫秒),错过前面的波形;
linux内核不允许使用忙延时来解决抖动问题,linux内核一般都采用定时器(struct timer_list)来实现去抖动!

实际波形:
这里写图片描述

处理方法:
这里写图片描述

出于成本考虑,一般采用软件去抖动。

面试:谈谈对中断的认识/请描述按键的驱动如何实现?
1,按键的硬件接法:
独立式:一个按键一个GPIO,100个按键则需要100个IO口;软件操作简单,浪费IO资源
矩阵式:100个按键,只需10*10,只需20个IO口,软件操作复杂,节省IO资源
2,按键的硬件处理过程:中断控制器
3,按键的软件处理
轮询:
中断:
4,中断的处理过程
5,linux内核的中断的编程
中断的处理函数的要求
中断底半部机制
6,按键去抖

    1:44
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用于四线电阻屏的触摸驱动 触摸屏的简要介绍和安装准备 通用的四线电阻触摸屏的特点; 电阻触摸屏的安装准备; 安装电阻触摸屏的注意事项; 触摸屏的安装 触摸屏的安装过程; 触摸屏的驱动软件安装; 触摸屏的硬件安装; 触摸屏的具体使用方法和注意事项 排除故障的要点总结 触摸屏的简要介绍和安装准备 通用的四线电阻触摸屏的特点;    最近几年, 人机对话的界面刚发展起来的一项新技术,它通过计算机技术四线/触摸屏控制处理声音、图像、视频、文字、动画等信息,并在这些信息间建立一定的逻辑关系,使之成为能交互地进行信息存取和输出的集成系统。    触摸屏系统符合简便、经济、高效的原则,具有人机交互性好、 操作简单灵活、输入速度快等特点。它与迅猛发展的计算机网络和四线/触摸屏控制多媒体技术相结合,使用者仅仅用手指触摸屏幕,就能进行信息检索、数据分析,甚至可以做出身临其境、栩栩如生的效果;较键盘输入简单、直观、快捷,具有丰富多采的表现能力,比以往任何传媒更具亲合力。    触摸屏在我国已经得到了非常广阔的应用,主要是公共信息的查询;如电信局、税务局、银行、电力等部门的业务查询;城市街头的信息查询;此外应用于领导办公、工业控制、军事指挥、电子游戏、点歌点菜、多媒体教学、房地产预售等。如今,触摸屏特别是电阻式触摸屏,在不断走入大众家庭。    ,四线电阻式触摸屏:电阻触摸屏的屏体部分是一块与显示器表面非常配合的多层四线/触摸屏控制复合薄膜,由一层玻璃或有机玻璃作为基层,表面涂有一层透明的导电层,上面再盖有一层外表面硬化处理、光滑防刮的塑料层而内表面也涂有一层透明导电层,在两层导电层之间有许多细小(小于千分之一英寸)的透明隔离点把它们隔开绝缘,见图1。    图1 四线电阻触摸屏的基本原理    当手指触摸屏幕时,平常相互绝缘的两层导电层就在触摸点位置有了一个接触导通,因其中一面导电层接通Y纵轴方向的参考电压Vref=5v均匀电压场,使得侦测层的电压由零变为非零,控制器侦测到这个接通后,进行模数A/D转换,并将得到的电压值与参考电压Vref相比即可得到触摸点的Y轴坐标,同理得出X横轴的四线/触摸屏控制坐标,这就是所有电阻技术触摸屏共同的最基本原理。     四线电阻式触摸屏的特点:高解析度(能轻松达到4096*4096),高速传输反应*(小于1/100秒)。 表面硬度处理,减少擦伤、刮伤及防化学处理。一次校正,永不漂移,稳定性高。不怕灰尘、水汽和油污,使用环境要求低,可以用任何非菱角的物体来触摸,技术工艺很成熟,成本较低,是最为广泛实用的触摸屏。 电阻触摸屏的安装准备; 首先,要准备好基本部件:包括:触摸屏,触摸笔,驱动程序(光盘),控制卡,连接线和延长线*(可根据实际需要取舍)。 控制卡按接口类型分为USB型和串口型两种*(通常选用USB型),

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值