嵌入式linux驱动开发之给你的linux系统添加温度传感器模块

忙了几天,终于可以让ds18b20在自己的开发板的linux系统上跑了!虽然ds18b20不是什么新鲜玩意,但是想想知己可以给linux系统添加模块了还是有点小鸡冻呢!

虽然说现在硬件的资源非常丰富而且剩余很多,可以用软件资源来代替硬件资源,比如说可以用视频编解码软件取代硬件来工作。但有很多模块需要实时的采集数据这都是软件永远无法代替的,而且随着互联网的进一步发展,智能化也是一个必然的趋势,因此大量的传感器和控制芯片将被应用到生产生活中,所以个人觉得驱动开发还是个不错的方向。同时,作为学习者,再进行嵌入式linux开发过程中,可以接触到软件和硬件,对它们如何协同工作有了更加深刻的理解。这些东西在计算机的世界里应该算是内功了,修炼好了这些,在练习那些上乘的武功也许就更快了。

虽然成功了,但是通过这次开发我的确有一点小担忧,因为这次有意想不参考其他前辈写过的的资料,想自己靠数据手册来编写这个驱动,可是问题来了,突然自己一下傻了,不知道改怎么下手了,从那里下手了?怎么会这样呢?接触代码这么长时间,突然想自己“裸写”,居然没有思路,或者说有大致的思路,细节的地方有点模糊,总之下不了笔。后来想想互联网真是一把双刃剑呀!自己平时凭借这深厚的百度技巧几乎解决掉了学习中遇到了八成问题,于是对网络上的资源依赖便不知不觉中与日俱增,特别是一些直男前辈上来先贴代码,以前我很喜欢这样的前辈,现在想想有点忧虑了!还是自己的自控力不够啊!因此,鉴于此,本人以后的博客中将不在完整的贴代码了,只描述实现过程和想法。

还有一点就是抄袭现象太严重了,虽然同一个问题可能几时页的搜索结果,但版本真的太少,一两种版本很常见,想找个不同的观点真的太难了,因此,本博客以后就随心所欲的按自己的想法写了,哪怕即使是错的,也给这个博客园和csdn带来一丝不同的色彩。

好了,还是老毛病废话太多,下面就进入正题吧

关于DS18B20————————微电子间的“语言”

本次要想给linux添加的模块正是恶俗的ds18b20,关于ds18b20和嵌入式下的驱动网上资料都很多,基本的都不说了。就说说ds18b20与我们的核心芯片的是如何交流的。ds18b20和cpu都是半导体芯片,如果要通过ds18b20采集温度给cpu,他们之间必须存在有效的沟通和对话,人与人之间说话靠语言,它们之间交流也有语言,他们的语言便是对着连接他们的那根线进行高低电平控制以及控制的时间,那么他们拉高拉低电平也必须有规则吧!我们人类也有语法啊!它们之间确实存在语法,那便是datasheet中的时序图,这个时序图可是他们对话的语法,想hold住ds18b20,核心就在时序图。

以ds18b20的写时序为例描述这个对话过程:当我们的单片机(主控芯片)想要ds18b20执行任务的时候必须要告诉他任务,这个任务就是通过写命令发出的,单片机先拉低与ds18b20相连接IO口电平然后持续15us,它就好比给ds18b20说:“孩子,有任务 来了,过来取任务吧!“,ds18b20听到后就过来了,然后看看它与单片机相互链接的”专线“现在是高电平还是低电平,是高电平记为1,低电平是0.这样它反复接了8次就是一个完整的命令,ds18b20一看这个命令数据是0xbe,就知道单片机要来读温度数据了,赶紧做好准备。

ds18b20的故事就先聊到这里吧!毕竟这些东西时需要几次反复看和揣摩的。

不过在linux 系统下给ds18b20写驱动还是有不少方便的,ds18b20是一个对时间很敏感的器件,linux 中的udelay/ndelay为我们提供了微秒以及纳秒级别的精确延时,这点很方便。

另外系统给我提供了,s3c2410_gpio_setpin,s3c2410_gpio_getpin,等IO口操作函数,可以让我们方便的设置IO口的高低电平。它们中尤其值得注意的是s3c_2410_getpin函数,这个函数当IO口设置为input时,也就是输出的时候,它的返回值是0或者大于1的数,这里千万不要误以为返回值为1.特别是在编写读一个字节用到时,需特别注意。

关于嵌入式linux驱动————链接和规范

linux驱动的核心还在于器件本身,建议编写某个模块的 器件时,先熟悉器件在裸板上的驱动,先把这个器件的驱动每个细节搞清楚,然后在linux下只要注意规范和提供接口就可以了。

上一篇文章主要详细介绍了,应用程序到内核的接口,即系统函数与file_operations的关系映射。这一篇详细介绍设备与file_operations的链接,这样就形成了一个完整的linux下驱动链条。即  设备———>file_operations————>系统函数接口。

ds18b20是字符型设备,所以下面就详细介绍下如何创建一个字符设备以及这个字符设备使如何与file_operations发生关系的。

开始我们的工作前,先拍拍脑门清醒清醒,我们要干什么。。。。。。。

首先,要明确linux是一个有纪律有组织的机构,我们想在linux下添加一个新的模块,linux当然有这个机制了,所以在驱动编写中,一定要牢记一点规则很重要,既然我们添加的ds18b20是一个字符设备,那么你想linux这么大一个系统只有三种设备类型,它能不为字符类型的设备提供一个标准的样表吗?必须有啊!这货就是cdev,可以看出它就是英文的字符设备的缩写,它是一个结构体,所以必须要好好看看它。

1 struct cdev {
2         struct kobject kobj;
3         struct module *owner;
4         const struct file_operations *ops;
5         struct list_head list;
6         dev_t dev;
7         unsigned int count;
8 };

不看不知道,一看吓一跳,原来这字符设备内部的成员函数虽然不是很多,但是很管用啊!这第一个和四个我们就不说了,那都是系统自动填充的。作为小白我们把剩下的搞明白就棒棒的啦!首先看到了file_operatition这个成员函数,心中非常兴奋,因为file_operactions可是系统应用函数的接口啊,它可是驱动函数中的交通枢纽啊!它出现在字符设备的结构体里面,用屁股想一下得出了结论,只要我们初始化了这个file_operations这个成员函数,我们的字符设备和file_operations就建立了对应关系。那样当我们使用一个字符设备时,就知道调用哪一个file_operatitions了。

在看dev_t,这个是字符设备的设备号字符类型,就是我们的设备必须有一个设备号,就像我们学生要有一个学号一样,那为什么我们不直接使用名字,而要弄一个设备号呢!个人觉得第一数字更有调理,更容易检测设备号是否再用,第二linux系统中一个主设备号可以对应多个同类型的设备,鉴于此,设备还必须需要设备号了,还是那句话我们说这个没用,linux驱动开发最大的一个特点你就要适应规则,人家有这个成员函数,咱们就必须填写符合要求的。

经过一番激烈的分析,我们明白鸟,其实关于建立这个新的设备并要得到内核的承认,我们的核心任务就是要把cdev这个结构体给初始化完毕。这样才能达到,有了设备节点名称我们能知道设备的设备号,有了设备号我们知道系统函数调用的时候我们该提供那个设备的file_operactions函数,

ao,搜得死那!           下面就一起来填空把!

我们需要为这个填空来做准备:首先是获得dev_t  dev;设备号

step1:要创建linux系统可接纳的驱动,我们必须向linux申请一个设备号以給我们的设备 用。

创建设备在2.6内核以前的版本是很easy的,只需要一个函数,便可申请/分配设备内存/注册设备,但是以后的内核机制中,这种方便的东西就被废除了,因为以前是我们设定一个设备号,然后申请,这种做法在linux大量应用时容易造成设备号重复冲突。因此在新的内核机制中建议大家动态的申请设备号,这样以来系统便会自动找到一个没有使用的设备号。linux 中比较经典的处理方法来自ldd书中的这段:

 1 dev_t  dev;
 2 dev=MKDEV(ds18b20_major,ds18b20_minor);
 3         if(ds18b20_major)
 4         {
 5                 ret=register_chrdev_region(dev,ds18b20_devs,"ds18b20");
 6         }
 7         else
 8         {
 9                 ret=alloc_chrdev_region(&dev,ds18b20_minor,ds18b20_devs,"ds18b20");
10                 ds18b20_major=MAJOR(dev);
11         }

dev_t是用来保存设备编号的类型,MKDEV是主次设备号转换成dev_t类型。

然后就是检测主设备号是否为0,为0则标示要进行动态申请设备号。这里一般建议采用动态申请的方式。

申请完毕后可以用MAJOR(dev)来获取申请的主设备号。

step2:file_operactions函数的书写,这个也可是重中之重,它的写法由于前面已经接受过了,这里就不多提了。

1 static struct file_operations ds18b20_fops={
2         .owner=THIS_MODULE,
3         .open=ds18b20_open,
4         .read=ds18b20_read,
5 };

当然这个结构体中的open,read函数就不罗列在这坑害后人了。

有了上面的两步之后那我们就开始填空啦!

这次填空分为两步,需要两个函数,第一个是cdev_init,第二个是cdev_add;

有了这两个函数我们进行填空:1  首先调用cdev_init;将我们的file_operactions填进去。

 1 void cdev_init(struct cdev *cdev, const struct file_operations *fops)
 2
 3 参数:
 4
 5 cdev:之前我定义的cdev结构体;
 6
 7 fops:设备对应的文件操作结构体。
 8
 9 返回值:(函数有可能失败,查看返回值是必须的)
10
11 成功返回0,示范返回对应的错误码

2 下面填写设备的设备号  调用的函数是cdev_add

 1 int cdev_add(struct cdev *cdev, dev_t dev, unsigned count)
 2
 3 参数:
 4
 5 cdev:指定要被添加的cdev结构体;
 6
 7 dev:对应的设备号
 8
 9 count:从设备号dev开始添加count个设备.
10
11 返回值:
12
13 成功返回0,失败返回对应的错误码。

这个函数就将我们的设备号同设备关联起来了,这样以来我们的字符设备结构体就填充完毕了,我们就将这个字符设备加入到内核里面了。

这样以来我们的字符设备——设备编号——file_operactions就建立起了联系,而file_operactions又是系统函数的枢纽,所以这样在编写系统的应用函数的时候,我们就可以通过联系设备的节点而知道该操作那个设备的file_operactions了,因为它们变成了一个环,通过其中的一节一定能够找到环中的另一节。

这样看来还少设备节点啊!下面还需要做的就是创建一个设备节点, 创建设备节点的时候我们一般采用自动创建设备节点的办法,linux中为我们提供了struct class结构体,这个结构体对应一个类,我们用class_create函数来创建一个存放于sysfs里面的类,然后调用device_create就可以创建一个设备节点了。

1 static struct class *ds18b20_class;
2 static struct class_device *ds18b20_class_dev;/........................................................../
3 ds18b20_class=class_create(THIS_MODULE,"ds18b20_sys_class");
4         if(IS_ERR(ds18b20_class))
5                 return PTR_ERR(ds18b20_class);
6         ds18b20_class_dev=device_create(ds18b20_class,NULL,MKDEV(ds18b20_major,0),NULL,"ds18b20");
7         if(unlikely(IS_ERR(ds18b20_class_dev)))
8                 return PTR_ERR(ds18b20_class_dev);

在做这个驱动的过程中,遇到很多好的文章,分享给大家

第一是位是jammy前辈的:

http://wenku.baidu.com/link?url=r_W8dizlV8cxD1s-6cmL3N3KztRM9q3xEgp9O6A3JJS86I_0-mnSob8hYjvGkS7c18y7upIPhhWb7868g-8NM8cKi4_BedKV31PF-o4Z6fy

jammy的代码中大量使用了预处理,使得代码程序中的代码可读性非常强,非常值得学习,不过程序中有处小小的错误。而且jammy是在09年写的这篇文章,文中很多设备的注册在新版内核中是不被注册的。

第二位是小白前辈的:

http://blog.chinaunix.net/uid-25014876-id-59416.html

不多说了,小白前辈的文章灰常认真,灰常全面,条理清楚,看的出我很多的东东都是他哪儿的。

第三位是sg131971前辈的:

http://www.linuxidc.com/Linux/2012-02/54677.htm

这位前辈是直男,直接上代码,它的文章字符注册采用新的机制,可以供参考。

时间: 2024-10-24 07:13:32

嵌入式linux驱动开发之给你的linux系统添加温度传感器模块的相关文章

linux驱动开发重点关注内容--摘自《嵌入式Linux驱动模板精讲与项目实践》

本文摘自本人拙著 <嵌入式Linux驱动模板精讲与项目实践> 初步看起来Linux设备驱动开发涉及内容非常多,而须要实现驱动的设备千差万别.事实上做一段时间驱动之后回首看来主要就是下面几点: (1)对驱动进行分类.先归纳为哪个类型的驱动.归类正确再利用内核提供的子系统进行开发,往往会发现事实上非常多通用的事情内核已经帮我们做了,一个优秀的驱动project师应该最大程度上利用内核的资源.内核已经实现的毕竟稳定性强.可移植性高. (2)找到内核的提供的子系统.接下来就是要制作该子系统对该类设备提

驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 不能再扯了,涉及到linux的驱动开发知识面灰常广,再扯文章就会变得灰常长.首先还是回到led驱动的本身上,自从linux被移植到arm上后,做驱动开发的硬件知识要求有所降低,很多都回归到了软件上,这是系统编程的一大特点,当然 ,也不排除有很多

嵌入式linux驱动开发之点亮led未遂(驱动编程思想之初体验)

有了上两篇文章的基础,我们就可以开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 另外实践很重要,一年多以前就知道了arm,那时整天用单片机的思维去yy着arm,直到前段时间弄来一块arm板,烧上linux系统后才知道,坑呀!根本不是那回事,所以实践是学习计算机类最重要的基本素质,如果整天看书,那基本上

嵌入式Linux驱动开发实战视频教程

嵌入式Linux驱动开发实战教程(内核驱动.看门狗技术.触摸屏.视频采集系统)适合人群:高级课时数量:109课时用到技术:嵌入式 Linux涉及项目:驱动开发.看门狗技术.触摸屏.视频采集咨询qq:1840215592 课程介绍:本课程即是针对有兴趣学习嵌入式linux驱动开发又不知道从何处着实开始学习嵌入式linux驱动开发的在校同学以及社会在职人员.本课程采用理论教学与实验相结合的方式,软件与硬件相结合的方式,重点给大家讲解嵌入式linux驱动开发的方法,系统地介绍嵌入式linux驱动开发的

嵌入式Linux驱动开发实战教程

嵌入式Linux驱动开发实战教程(内核驱动.看门狗技术.触摸屏.视频采集系统) http://www.ibeifeng.com/goods-475.html 咨询QQ2110053820 课程讲师:韩老师 课程分类:Linux 适合人群:高级 课时数量:109课时 更新程度:完成 用到技术:嵌入式 Linux 涉及项目:驱动开发.看门狗技术.触摸屏.视频采集 课程简介:    嵌入式软件开发无疑是当今最热门的行业,嵌入式软件工程师的薪资比普通的软件工 程师的薪资平均高50%以上.随着智能控制.物

【转】linux驱动开发的经典书籍

原文网址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书为<linux_device_driver 3rd Edition>,这是一本很经典的书,无奈Linux的东东还是过于庞大,这本侧重于实战的书籍也只能停留在基本的接口介绍上,更深入的东东只能靠我们自己摸索了.但万事总有一个开头,没有对Linux驱动整体框架的把握是很难做一个优秀的驱动开发者的.除了

linux驱动开发学习路线

这篇文章是和大四学弟交流的文章,贴出来,和大家学习讨论 需要掌握的基本技能: C/C++/ python shell makefile linux基本操作 以android手机为例,我通俗的介绍下市场上产品的软件结构. 手机---> 硬件:cpu(arm架构单片机)+各种传感器(显示屏.距离传感器.温度传感器.gms模块 gprs模块等等).本质上手机就是一个单片机加上一堆传感器,单片机控制各个传感器与人进行负责的交互.(驱动工程师就是在linux底层让传感器可以工作,然后提供控制硬件的接口交给

Linux 驱动开发索引

1.嵌入开发环境搭建 Telnet 在 mini2440 上的移植 Opencv-2.4.9 在 mini2440 上的移植 搭建嵌入式开发环境总结 2.Linux 设备驱动 Linux 驱动程序头文件 一步一步学习Linux驱动之驱动模块MakeFile解析 一步一步学习 Linux 驱动之(Kconfig.Makefile) 一步一步学习 Linux 驱动之字符设备 LED 静态编译进 Linux 内核 内核怎么通过主设备号找驱动.次设备号找设备 Linux 驱动之内核空间分配内存 一步一步

linux驱动开发流程

嵌入式linux驱动开发流程嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的.设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,可以像操作普通文件一样对硬件设备进行操作.设备驱动程序是内核的一部分,完成以下功能:◇ 驱动程序的注册和注销.◇ 设备的打开和释放.◇ 设备的读写操作.◇ 设备的控制操作.◇ 设备的中断和轮询处理.Linux主要将设备分为三类:字符设备.块设备和网络设备.字符设备是指发送和接收数据以字符的