驱动篇:字符设备驱动综合实例(一)(摘录)

2023-05-16

驱动篇:字符设备驱动综合实例(一)

1.按键的设备驱动
在嵌入式系统中,按键的硬件原理比较简单,通过一个上拉电阻将处理器的外部中断(或 GPIO)引脚拉高,电阻的另一端连接按钮并接地即可实现。如图 12.1 所示,当按钮被按下时,EINT10、EIN13、EINT14、EINT15 上将产生低电平,这个低电平将中断 CPU(图中的 CPU 为 S3C2410),CPU 可以依据中断判断按键被按下。
在这里插入图片描述如果按键对应的引脚本身不具备中断输入功能,则可以改为完全查询方式如图b

在这里插入图片描述设备驱动中主要要设计的数据结构是设备结构体,按键的设备结构体中应包含一个缓冲区,因为多次按键可能无法被及时处理,可以用该缓冲区缓存按键。此外,在按键设备结构体中,还包含按键状态标志和一个实现过程中要借助的等待队列、cdev结构体。为了实现软件延时,定时器也是必要的,但可以不包含在设备结构体中。

#define MAX_KEY_BUF 16 //按键缓冲区大小
typedef unsigned char KEY_RET;
//设备结构体:
typedef struct
{
unsigned int keyStatus[KEY_NUM]; //4 个按键的按键状态
KEY_RET buf[MAX_KEY_BUF]; //按键缓冲区
unsigned int head, tail; //按键缓冲区头和尾
wait_queue_head_t wq; //等待队列
struct cdev cdev;
//cdev 结构体
} KEY_DEV;
static struct timer_list key_timer[KEY_NUM];//4 个按键去抖定时器

在按键设备驱动中,可用一个结构体记录每个按键所对应的中断/GPIO 引脚及键值

static struct key_info
{
int irq_no;
//中断号
unsigned int gpio_port; //GPIO 端口
int key_no;
//键值
} key_info_tab[4] =
{
/*按键所使用的 CPU 资源*/
{
IRQ_EINT10, GPIO_G2, 1
},
{
IRQ_EINT13, GPIO_G5, 2
},
{
IRQ_EINT14, GPIO_G6, 3
},
{
IRQ_EINT15, GPIO_G7, 4
},
};

按键设备驱动文件操作结构体主要实现了打开、释放和读函数,因为按键只是一个输入设备,所以不存在写函数

static struct file_operations s3c2410_key_fops =
 {
 owner: THIS_MODULE,
 open: s3c2410_key_open, //启动设备
 release: s3c2410_key_release, //关闭设备
 read: s3c2410_key_read, //读取按键的键值
 };

按键设备作为一种字符设备,在其模块加载和卸载函数中分别包含了设备号申请和释放、cdev 的添加和删除行为,在模块加载函数中,还需申请中断、初始化定时器和等待队列等,模块卸载函数完成相反的行为

模块加载函数

static int __init s3c2410_key_init(void)
 {
...//申请设备号,添加 cdev
request_irqs(); //注册中断函数
keydev.head = keydev.tail = 0; //初始化结构体
for (i = 0; i < KEY_NUM; i++)
keydev.keyStatus[i] = KEYSTATUS_UP;
init_waitqueue_head(&(keydev.wq)); //等待队列
//初始化定时器,实现软件的去抖动
 for (i = 0; i < KEY_NUM; i++)
setup_timer(&key_timer[i], key_timer_handler, i);
 //把按键的序号作为传入定时器处理函数的参数
 }

模块卸载函数

static void __exit s3c2410_key_exit(void)
 {
 free_irqs(); //注销中断
 ...//释放设备号,删除cdev
 }

按键设备驱动的中断申请函数

/*申请系统中断,中断方式为下降沿触发*/
 static int request_irqs(void)
 {
 struct key_info *k;
 int i;
 for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab[1]); i++)
 {
 k = key_info_tab + i;
 set_external_irq(k->irq_no, EXT_LOWLEVEL, GPIO_PULLUP_DIS);
 //设置低电平触发
 if (request_irq(k->irq_no, &buttons_irq, SA_INTERRUPT,DEVICE_NAME, i)) 
 //申请中断,将按键序号作为参数传入中断服务程序
 {
 return - 1;
 }
 }
 return 0;
 }

中断释放函数

 /*释放中断*/
static void free_irqs(void)
{
struct key_info *k;
int i;
for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab[1]); i++)
{
k = key_info_tab + i;
free_irq(k->irq_no, buttons_irq); //释放中断
}
}

在键被按下后,将发生中断,在中断处理程序中,应该关闭中断进入查询模式,延迟 20ms 以实现去抖动这个中断处理过程只包含顶半部,无底半部。

static void s3c2410_eint_key(int irq, void *dev_id, struct pt_regs *reg)
 {
 int key = dev_id;
 disable_irq(key_info_tab[key].irq_no); //关中断,转入查询模式
 keydev.keyStatus[key] = KEYSTATUS_DOWNX;//状态为按下
 key_timer[key].expires == jiffies + KEY_TIMER_DELAY1;//延迟
 add_timer(&key_timer[key]); //启动定时器
 }

在定时器处理程序中,查询按键是否仍然被按下,如果是被按下的状态,则将该按键记录入缓冲区。同时启动新的定时器延迟,延迟一个相对于去抖更长的时间(如100ms),每次定时器到期后,查询按键是否仍然处于按下状态,如果是,则重新启用新的 100ms 延迟;若查询到已经没有按下,则认定键已抬起,这个时候应该开启对应按键的中断,等待新的按键。每次记录新的键值时,应唤醒等待队列。
定时器处理函数

static void key_timer_handler(unsigned long data)
 {
int key = data;
if (ISKEY_DOWN(key))
{
if (keydev.keyStatus[key] == KEYSTATUS_DOWNX)
//从中断进入
{
keydev.keyStatus[key] = KEYSTATUS_DOWN;
key_timer[key].expires == jiffies + KEY_TIMER_DELAY; //延迟
keyEvent(); //记录键值,唤醒等待队列
add_timer(&key_timer[key]);
}
else
{
key_timer[key].expires == jiffies + KEY_TIMER_DELAY; //延迟
add_timer(&key_timer[key]);
}
 }
 else
//键已抬起
 {
keydev.keyStatus[key] = KEYSTATUS_UP;
enable_irq(key_info_tab[key].irq_no);
 }
 }

在这里插入图片描述按键设备驱动的打开和释放函数比较简单,主要是设置 keydev.head、keydev.tail和按键事件函数指针 keyEvent 的值

static int s3c2410_key_open(struct inode *inode, struct file *filp)
{
keydev.head = keydev.tail = 0; //清空按键动作缓冲区
keyEvent = keyEvent_raw; //函数指针指向按键处理函数 keyEvent_raw
return 0;
}
static int s3c2410_key_release(struct inode *inode, struct file
{
keyEvent = keyEvent_dummy; //函数指针指向空函数
return 0;
}

按键设备驱动的读函数主要提供对按键设备结构体中缓冲区的读并复制到用户空间。当keydev.head ! = keydev.tail 时,意味着缓冲区有数据,使用 copy_to_user()拷贝到用户空间,否则,根据用户空间是阻塞读还是非阻塞读,分为如下两种情况。
l 若采用非阻塞读,则因为没有按键缓存,直接返回- EAGAIN;
l 若采用阻塞读,则在 keydev.wq 等待队列上睡眠,直到有按键被记录入缓冲区后被唤醒。
驱动读函数

static ssize_t s3c2410_key_read(struct file *filp, char *buf, ssize_t count,loff_t*ppos)
{
retry: if (keydev.head != keydev.tail)
//当前循环队列中有数据
{
key_ret = keyRead(); //读取按键
copy_to_user(..); //把数据从内核空间传送到用户空间
}
 else
 {
if (filp->f_flags &O_NONBLOCK)
//若用户采用非阻塞方式读取
{
return - EAGAIN;
}
interruptible_sleep_on(&(keydev.wq));
//用户采用阻塞方式读取,调用该函数使进程睡眠
goto retry;
 }
 return 0;
 }

在设备驱动的打开函数中,keyEvent 被赋值为 keyEvent_raw,这个函数完成记录键值, 并使用 wait_up_interrupt(&(keydev.wq))语句唤醒 s3c2410_key_read()第 17 行所期待的等待队列。而 keyRead()函数则直接从按键缓冲区中读取键值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

驱动篇:字符设备驱动综合实例(一)(摘录) 的相关文章

  • TokenEndpoint : Handling Null Pointer Exception

    springboot oauth2 0生成token时报错 详细的日志没有打印出来 需要手动配置log 64 Override public void configure AuthorizationServerEndpointsConfig
  • linux(ubuntu)无法连接网络

    提示 xff1a 版本 xff1a ubuntu16 0 4 问题 xff1a 开机没有网络 xff0c 无法连接网络 xff0c 尝试了很多方法最终才可以 首先查看ifconfig 查看网卡信息 ifconfig 查看ip ip a 查看
  • 八皇后问题

    问题描述 在国际象棋中 xff0c 有一个非常强势的棋子 皇后 xff0c 他的走法可以在网上参考一下 xff0c 概括来说就是可以沿着行 列 与对角线平行的线走 而在计算机中有一个关于他的经典问题 xff0c 8皇后 xff0c 就是在8
  • ubuntu18.04.3如何在终端下切换到指定文件夹或根目录

    看到很多的新手 xff0c 不知道如何在终端切换到根目录的 xff0c 或者是指定的目录的 xff0c 下面介绍一下切换的方法 1 先按键盘 ctrl 43 alt 43 t 弹出终端 xff0c 那么你会看到终端上的提示当前目录为 这个就
  • MySql简单查询——单表查询

    一 DDL xff08 Data Definition Language xff09 xff1a 数据定义语言 xff0c 用来定义数据库对象 xff1a 库 表 列等 xff1b 相关字段 xff1a create drop alter
  • linux下可视化git工具git-cola安装与使用(HTTP方式)

    一 git cola为何物 很多小伙伴 xff0c 特别喜欢使用TortoiseGit xff0c 该软件是做什么的 xff0c 就不用多说吧 奈何 xff0c TortoiseGit只有windows版 xff0c 这让在linux上开发
  • 解决ubuntu下应用程序菜单不在程序的左上角

    测试版本 xff1a ubuntu16 04 问题 xff1a 应用程序菜单不在程序的左上角 xff0c 默认放在了桌面顶部的菜单栏上 如下 xff1a 解决办法 xff1a System Settings gt Appearance gt
  • linux下可视化git工具git-cola安装与使用(SSH方式)

    一 git cola为何物 很多小伙伴 xff0c 特别喜欢使用TortoiseGit xff0c 该软件是做什么的 xff0c 就不用多说吧 奈何 xff0c TortoiseGit只有windows版 xff0c 这让在linux上开发
  • CAS实现SSO单点登录原理

    yale cas可以百度一下 xff0c 这是学习cas后的一点总结 xff0c 以备日后使用 xff01 安全性 xff1a 用户只须在cas录入用户名和密码 xff0c 之后通过ticket绑定用户 xff0c 在cas客户端与cas校
  • 五种知网文献免费下载方式

    1 idata中国知网 网址 xff1a idata中国知网 进入系统 xff0c 注册账号 xff0c 登录即可 每天五篇额度 xff0c 基本够用 xff0c 可注册多个账号使用 2 上海研发公共服务平台 网址 xff1a 上海研发公共
  • 【FreeRTOS】二值信号量实现线程的同步

    FreeRTOS 二值信号量实现线程的同步 测试环境如下 stm32L431RCT6 MDK keil5 stm32cube 43 FreeRTOS 一 添加多个任务 1 引脚配置 LED使用的引脚PA8和PB2设置成output 将按键引
  • 暗影精灵2pro安装win10+ubuntu16.10双系统

    暗影精灵2pro预装win10家庭版 xff0c 默认启动win10系统 xff0c 且无法引导其他系统 xff0c 今天我们来解决这个问题 先进入到win10的磁盘管理器服务 xff0c 为ubuntu单独分配磁盘空间 xff0c 让wi
  • 第二十三讲.从HadoopURL中读取数据

    视频 xff1a 美妙人生 Hadoop课程系列之HDFS 手把手教你精通HDFS 美妙人生 Hadoop课程系列之HDFS 手把手教你精通HDFS 视频笔记 从hadoop URL读取数据 static URL setURLStreamH
  • winform窗体

    一 winform介绍 WinForm xff0c 是 Net开发平台中对Windows Form的一种称谓 WinForm是窗体应用程序 xff0c 由若干个窗体应用组成 xff0c 基于C S架构 二 winform的使用 xff08
  • 赋予人工智能记忆的人,带你梳理深度学习核心算法

    新智元翻译 1 来源 xff1a Idsia 作者 xff1a J rgen Schmidhuber 翻译 xff1a 张巨岩 作者介绍 xff1a J rgen Schmidhuber 被称为是赋予人工智能记忆的人 xff0c 递归神经网
  • C++实现贪吃蛇游戏

    注意 xff1a 本代码是在VC 43 43 6 0环境下编译的 xff0c 在其他环境如codeblocks下运行可能会产生意想不到的问题 xff0c 请尽量使用VC xff01 最近由于小编闲着慌 xff0c 捣鼓了一个贪吃蛇游戏 xf
  • Win10正式版19044.2132(KB5020435)来啦!(附完整更新日志)

    微软发布了Win10正式版KB5020435 xff08 操作系统内部版本 19042 2132 19043 2132 和 19044 2132 xff09 xff0c 此次更新主要解决了某些类型的安全套接字层 xff08 SSL xff0
  • SOUI总结之皮肤说明

    皮肤说明 说明 框架自带的皮肤都是 skin sys XXXX开始 xff0c 自带的皮肤存放位置trunk soui sys resource theme sys res xff0c 图片和名称映射关系可以打开trunk soui sys
  • C++中逗号运算符

    今天测试代码的时候 xff0c 遇到一行代码出现了疑问 xff0c 原因是出现了自减运算符和逗号运算符 xff0c 这就涉及到一个顺序的问题 xff0c 于是写了一个C 43 43 小程序 xff0c 验证了一下这个想法 include u
  • PsExec的问题及其解决办法

    C gt PsExec exe 192 168 1 142 cmd PsExec v1 98 Execute processes remotely Copyright C 2001 2010 Mark Russinovich Sysinte

随机推荐

  • ubuntu 18.04安装protobuf

    今天需要安装protobuf 在网上搜了一篇教程 xff0c 但是篇幅太长 xff0c 于是对其进行简化一下 原文 1 96 96 96 git clone https github com protocolbuffers protobuf
  • 读取配置文件的程序

    时常会遇到需要从配置文件中读取一些信息 xff0c 这里就提供一个例子 xff0c 方便日后使用 xff1a span class token comment ini h span span class token macro proper
  • 命令行读取参数

    有时需要从命令读取一些输入 xff0c 这里找到一个方法 xff0c 怎么实现的没有仔细研究 xff0c 但是可用 cmdline h span class token comment Copyright c 2009 Hideyuki T
  • 如何在一个shell脚本中开启多个应用程序?

    之前在csdn上搜索 xff0c 提示用gnome terminal指令 xff0c 但是发现怎么都不好使 于是找到一种解决方案 span class token comment bin bash span span class token
  • 使用openCV播放视频 在视频中加入滑动条

    include 34 opencv2 highgui highgui hpp 34 include 34 opencv2 imgproc imgproc hpp 34 include lt iostream gt include lt fs
  • Linux下vscode无法查看定义?

    今天要用到vscode查到c 43 43 程序 但是发现vscode无法查看程序的定义 于是找了一下解决方法 vscode无法转到定义可能是因为没有安装插件 由于我需要使用C 43 43 所以我这里安装的是C 43 43 插件 第一步 第二
  • 冒泡排序的实现(基于顺序表)

    对于冒泡排序的含义以及图示表示 这里就不再赘述 这篇博客已经说的很明白了 添加链接描述 于是就用代码实现了一下基于顺序表的冒泡排序 因为一直看的时大话数据结构这本书 于是把上面介绍的三种实现方法都在代码中实现一下 具体实现与书中有一些出入
  • ambiguating new declaration of 问题的解决

    今天在运行代码的时候 一直在报这样的错误 ambiguating new declaration of int NewPartition seqlist int int 查看了许久 原来是头文件中的声明类型与函数实现的声明类型不一致造成的
  • opencv中的MatConstIterator,NAryMatIterator迭代器的使用

    第一个迭代器 MatConstIterator迭代器 使用迭代器计算一个三通道三维数组中 34 最长元素 34 这个代码实现过程中 照着书中的代码抄下来一直报错 后来在查阅代码的时候 发现了问题所在 具体已经在代码中标明了 include
  • 用python实现查询天气的功能

    附上代码 import urllib request import gzip import json print 39 天气查询 39 def get weather data city name 61 input 39 请输入要查询的城市
  • 1.Docker 安装

    安装 wget 命令 yum install wget 安装docker wget q O https get docker com sh O 下载并以指定的文件名保存 以 39 39 作为file参数 xff0c 那么数据将会被打印到标准
  • linux下sudo apt-get update 报Err http://security.ubuntu.com precise-security InRelease 等

    今天在进行linux更新的时候一直报错 尝试了很多办法都不行 于是找到一个方法 切实可行 以根用户运行 cd var lib apt lists rm rm var cache apt archives lock rm var lib dp
  • HTTP Authentication之Basic认证、Digest认证

    本文为博主原创 xff0c 未经许可严禁转载 本文链接 xff1a https blog csdn net zyooooxie article details 109691608 前面说到 Fiddler 的QuickExec Filter
  • Qt学习笔记(5) — Qt 类库【C++】

    目录 一 Qt核心特点1 元对象系统2 信号与槽的关联方式 二 Qt全局定义 xff08 常用头文件 xff09 1 lt QtGlobal gt 头文件1 xff09 数据类型定义2 xff09 函数3 xff09 宏定义 三 容器类1
  • 【C++】STL学习小总结

    经过自学以及查找资料汇总的一些记录 STL概述 长久以来 xff0c 软件界一直希望建立一种可重复利用的东西 xff0c 以及一种得以制造出 可重复运用的东西 的方法 xff0c 从函数 functions xff0c 类别 classes
  • ssh连接云服务器失败,能ping通但是连接不上

    环境 xff1a 腾讯云服务器 远程工具 xff1a xshell 7 问题描述 使用xshell远程工具时 xff0c 输入云服务器地址 xff0c 输入用户名密码之后显示 Connection established To escape
  • cheom 修改文件权限

    Chmod命令主要用于修改 设置文件权限 chmod 修改文件权限主要有两种方式 xff1a 字母法与数字法 1 字母法 xff1a chmod u g o a 43 61 r w x 文件名 以上是chmod的用法 xff0c 每个括号是
  • 通俗易懂的布谷鸟算法与莱维飞行,(附求解函数最小值matlab源码)

    1 从布谷鸟的育雏到布谷鸟算法2 布谷鸟算法3 萊维飞行与公式 1 的深层含义4 附 xff1a CS算法求解函数最小值代码5 源码下载6 参考文献 1 从布谷鸟的育雏到布谷鸟算法 布谷鸟不会做窝 xff0c 也不会育雏 xff0c 在春末
  • kubernetes容器网络接口(CNI) midonet网络插件的设计与实现

    相关原理概述 先来讲讲什么是CNI CNI xff08 容器网络接口 xff09 是一种操作容器网络规范 xff0c 包含方法规范 xff0c 参数规范等 CNI只关心容器的网络连接 xff0c 在容器创建时分配网络资源 xff0c 并在删
  • 驱动篇:字符设备驱动综合实例(一)(摘录)

    驱动篇 xff1a 字符设备驱动综合实例 xff08 一 xff09 1 按键的设备驱动 在嵌入式系统中 按键的硬件原理比较简单 通过一个上拉电阻将处理器的外部中断 或 GPIO 引脚拉高 电阻的另一端连接按钮并接地即可实现 如图 12 1