版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2023/7/22第5章:Linux驱动程序设计2023/7/225.1Linux驱动程序概述
5.2虚拟字符设备Demo驱动程序设计
5.3A/D驱动程序设计5.4步进电机驱动程序设计第5章:Linux驱动程序设计2023/7/225.1Linux驱动程序概述
5.2虚拟字符设备Demo驱动程序设计
5.3A/D驱动程序设计5.4步进电机驱动程序设计第5章:Linux驱动程序设计2023/7/22Linux驱动程序的知识结构:
1、Linux驱动设计规范(50%)
2、内核相关知识(25%)
3、硬件相关知识(25%)Linux驱动程序的学习方法:理论实验碰到问题理论实验
2023/7/225.1.1设备驱动原理5.1.2设备分类
5.1.3设备文件接口5.1.4驱动程序的加载方法5.1.5驱动程序的重要数据结构5.1.6驱动程序常用函数介绍5.1Linux驱动程序概述
2023/7/225.1.1设备驱动原理
2023/7/22(1)什么是驱动程序?驱动程序是指挥硬件工作的软件。它是应用程序与硬件之间的一个中层软件层,为应用程序屏蔽硬件的细节。2023/7/22(2)驱动程序的功能是什么?驱动程序的功能包括3部分:对设备初始化和释放。检测和处理设备出现的错误。为应用程序提供统一的接口,用于数据传送。2023/7/22(3)驱动程序的组成驱动程序的组成通常包括3部分:自动配置和初始化子程序。服务于I/O请求的子程序,又称驱动程序的上半部分。中断服务子程序,又称驱动程序的下半部分。2023/7/22(4)驱动程序与应用程序的区别?第一:主动与被动的区别。应用程序有一个main函数,总是从些函数开始主动执行一个任务,而驱动程序安装之后,便停止工作,并等待被应用程序调用。第二:使用的库函数不同。第三:程序运行的区域不同。驱动程序工作在内核态;应用程序工作在用户态。2023/7/225.1.2设备分类
2023/7/22Linux将设备分为3类:字符设备(characterdevices)(重点)块设备(blockdevices)网络设备(networkdevices)2023/7/221、应用程序对不同类型设备的操作有一些差别2023/7/222、字符设备
字符设备是指数据处理以字节为单位,并按顺序进行访问的设备。
如:简单按键、触摸屏、AD转换。2023/7/22初始化字符设备时,字符设备驱动程序向Linux登记,并在字符设备向量表chrdevs中增加一个device_struct数据结构条目,这个设备的主设备号用做这个向量表的索引,即chrdevs[]数组的下标值就是主设备号2023/7/223、块设备块设备是指在输入/输出时数据处理以块为单位的设备,它一般都采用缓存技术,支持数据的随机读写。
典型的块设备有:硬盘、U盘、内存、Flash、CD-ROM等2023/7/22在大部分Unix系统,块设备不能按字节处理数据,只能一次传送一个或多个长度是512字节(或一个更大的2次幂的数)的整块数据。可以随机访问。而Linux允许块设备一次传送任意数目的字节。2023/7/22Linux用blkdevs向量表维护已经登记的块设备文件。它像chrdevs向量表一样,使用设备的主设备号作为索引。2023/7/22块设备又分若干种类型,例如:SCSI类和IDE类。类向Linux内核登记并向内核提供文件操作。一种块设备类的设备驱动程序向这种类提供和类相关的接口。例如,SCSI设备驱动程序必须向SCSI子系统提供接口,让SCSI子系统来对内核提供这种设备的文件操作。2023/7/22字符设备和块设备的区别?最小访问单元不同。访问方式不同(顺序、随机)。2023/7/224、网络接口设备网络设备,又称网络接口(networkinterfaces),用于网络通信。通常它们指的是硬件设备,但有时也可以是一个纯软件设备(如回环接口loopback)。网络接口由内核中网络子系统驱动,负责发送和接收数据包,而且它并不需要了解每一项事务是如何映射到实际传送的数据包。2023/7/22它们的数据传送往往不是面向数据流(少数是,如telnet和FTP是面向数据流),所以不容易把它们映射到一个文件系统的节点上。在Linux中,采用给网络接口设备分配一个唯一的名字的方法来访问该设备。如:eth0eth1lo2023/7/225、设备号在传统方式的设备管理中,除了设备类型以外,内核还需要一对参数才能唯一标识设备,这对参数就是主设备号(majornumber)和次设备号(minornumber)。2023/7/22(1)什么是设备号?
设备号用于区分具体的设备。设备号包括主设备号(majornumber)和次设备号(minornumber)。
标识设备要作用3个参数:设备类型主设备号次设备号2023/7/22
主设备号用于标识设备对应的驱动程序,主设备号相同的设备使用相同的设备驱动程序。(主设备号用于区分设备的类型)
次设备号是用来区分具体设备的实例(次设备号用于区分同类型的设备)。crw-------1rootroot5,64Jan100:00cua0crw-------1rootroot5,65Jan100:00cua1crw-------1rootroot4,64Jan100:11ttyS0crw-------1rootroot4,65Jan100:00ttyS12023/7/22
设备文件、主设备号和驱动程序之间的关系?
2023/7/22应用程序如何使用设备文件?设备文件与驱动程序如何建立联系?2023/7/22使用文件名主设备号2023/7/22应用程序fd=open(“/dev/ad_0”,O_RDWR)ad_0设备文件C600(1)安装驱动,注册主设备号(2)创建设备文件,指向该设备类型,及主次设备号。(3)应用程序,调用设备文件。2023/7/22
有静态申请和动态申请2种方法。(2)Linux内核如何给设备分配主设备号?2023/7/22(1)查找没有使用的主设备号(cat/proc/devices)(2)在驱动程序中,使用register_chrdev函数向内核注册主设备号。静态申请分配主设备号(由人工分配)优点:简单缺点:如果驱动程序被广泛使用,有可能导致设备号冲突。(1)在驱动程序中,使用alloc_chrdev_region函数向内核申请动态分配,并注册主设备号。动态申请分配主设备号(由内核分配)优点:方便驱动程序推广。缺点:无法在安装驱动程序之前创建设备文件(因为安装之前还没有分配主设备号)。解决办法:安装后,使用命令cat/proc/devices查看分配到的设备号2023/7/22设备类型的表示方法:字符设备用C表示块设备用B表示网络设备没有2023/7/22
主设备号用于标识设备对应的驱动程序,主设备号相同的设备使用相同的设备驱动程序。一个主设备号可能有多个设备与之对应,这些设备在驱动程序内通过次设备号来进一步区分。
例如,软驱的主设备号是2,
IDE硬盘的主设备号是3,
并口的主设备号是62023/7/22次设备号是用来区分具体设备的实例(instance)。例如:如果一台计算机上配有2个软驱,则2个软驱的主设备号都是2,但次设备号不同,
第一个软驱的次设备号为0,
第二个软驱的次设备号为1。2023/7/22#cat/proc/devicesCharacterdevices:1mem2pty3ttyp4ttyS…..Blockdevices:1ramdisk2fd3sd……2023/7/226、设备文件设备类型、主设备号、次设备号是内核与驱动程序通信时所使用的,但是对于开发应用程序的用户来说难于理解和记忆,所以Linux使用了设备文件的概念来统一对设备的访问接口。2023/7/222023/7/22
Linux应用程序是通过设备文件(又名:设备节点)来使用驱动程序操作字符设备和块设备。2023/7/22/dev目录是用于存放设备文件的crw-------1rootroot5,64Jan100:00cua0crw-------1rootroot5,65Jan100:00cua1crw-------1rootroot4,64Jan100:11ttyS0crw-------1rootroot4,65Jan100:00ttyS1字符设备用c表示;块设备用b表示2023/7/22设备文件的命名方法设备文件有时也称为设备节点,一般存放在/dev目录下。正常情况下,/dev目录下的每一个设备文件对应一个设备(包括虚拟设备),设备文件的命名一般为“设备名+数字或字母”,其中,数字或字母用于表示设备的子类,例如:/dev/hda1、/dev/hda2分别表示第一个IDE硬盘的第一个分区和第二个分区。2023/7/22设备文件新命令方法
Linux-2.4版本内核中引入了设备文件系统,所有的设备文件作为一个可以挂装的文件,这样就可以被文件系统进行统一管理,从而设备文件就可以挂装到任何需要的地方。设备文件命名规则也发生了变化,一般将主设备建立一个目录,再将具体的子设备文件建立在此目录下。例如:UP-NETARM2410-S中的
MTD设备文件保存在/dev/mtdblock目录下,该目录有2个设备文件0和1。2023/7/22设备文件的创建方法设备文件的创建方式有2种,即自动创建和手动创建。2023/7/22ad_0设备文件C600(1)手工创建(mknod)(2)自动创建(安装驱动程序时)2023/7/22(1)手动创建mknod的语法如下:#mknodnametypemajorminor例如:创建一个字符设备文件,主设备号是100,次设备号是0,设备文件名是/dev/demo,则创建的命令如下:#mknod/dev/demoC10002023/7/22(2)自动创建是指在驱动程序中,通过函数调用,在安装驱动程序时,自动创建设设备文件。
2023/7/225.1.3设备文件接口
2023/7/22Linux应用程序可以通过设备文件的一组固定的入口点来访问驱动程序,这组入口点是由每个设备的设备驱动程序提供的。2023/7/22[程序5.1]编写应用程序实现向串口发送字符串“ATD2109992”。intmain(){intfd,n;charbuf[MAX]="ATD2109992";fd=open("/dev/ttyS0",O_RDWR);//open入口点,ttyS0是设备文件
if(fd<0){perror("Unableopen/dev/ttyS0\n"); return1;}n=write(fd,buf,strlen(buf));//write入口点if(n<0) printf("write()of%dbytesfailed!\n",strlen(buf));else printf("write()of%dbytesok!\n",strlen(buf));close(fd);
//close入口点
}[程序5.2]直流电机控制程序intmain(intargc,char**argv){inti=0,status=1,setpwm=0,factor=DCM_TCNTB0/1024;if((dcm_fd=open(=“/dev/dcm/0raw”,O_WRONLY))<0){
printf(“Erroropening%sdevice\n”,DCM_DEV);
return1;}for(;;){for(i=-512;i<=512;i++){
if(status==1)
setpwm=i;
else
setpwm=-i;
ioctl(dcm_fd,DCM_IOCTRL_SETPWM,(setpwm*factor));
Delay(500);
printf(“setpwm=%d\n”,setpwm);
}
status=-status;
}
close(dcm_fd);
return0;}常用入口点函数intopen(char*filename,intaccess);intclose(inthandle);intread(inthandle,void*buf,intcount);intwrite(inthandle,void*buf,intcount);intioctl(intfd,intcmd,…);intioctl(intfd,intcmd,char*argp);2023/7/225.1.4驱动程序的加载方法
2023/7/22Linux驱动程序的安装有2种方式:直接编译进内核,又称静态连接。模块方式,又称动态连接。
2023/7/22设备驱动模块化编程一般分为加载、系统调用和卸载等3个过程2023/7/22①lsmod命令功能:列出当前动态加载的模块清单。例:#lsmodModuleSizeUsedbyov511671400(unused)videodev58240[ov511]
//被ov511模块使用motor16081
//被一个应用程序使用ad17120(unus注:模块是指设备驱动程序名如:驱动程序motor.o,安装后的模块名是:motor2023/7/22②insmod功能:将驱动模块加载到操作系统内核例:将数码管驱动程序(tube.o)加载到内核。#insmodtube.oUsingtube.oWarning:loadingtubewilltaintsthekernel:no3icenseSeehctp://www.tux.or2/lkml/#export-t4intedforinfor1ationabouttaintedmodules0-numerictube:Dprintkdeviceopens3c2410-hc595initialized#2023/7/22#lsmodModuleSizeUsedbytube20720(unused)ov511671400(unused)videodev58240[ov511]motor16081ad17120(unused)#2023/7/22③rmmod功能:将驱动模块从内核中删除例:请将上一例子中的tube模块删除了。#rmmodtubes3c2410-hc595unloaded#以上显示是删除过程的提示信息。2023/7/225.1.5设备驱动的重要数据结构
2023/7/22
在Linux字符设备驱动程序设计中,有3个非常重要的数据结构:structfilestructinodestructfile_operations设备驱动的重要数据结构2023/7/22
代表一个打开的文件。系统中每个打开的文件在内核空间都有一个关联的structfile。它由内核在打开文件时创建,在文件关闭后释放。重要成员loff_t_pos/*文件读写位置*/structfile_operations*f_op(1)structfile2023/7/22
用来记录文件的物理上的信息。一个文件可以对应多个file结构,但只有一个inode结构。重要成员dev_ti_rdev:设备号(2)structinode2023/7/22
一个函数指针的集合,定义能在设备上进行的操作。结构中的成员指向驱动中的函数,这些函数实现一个特另的操作,对于不支持的操作保留为NULL。(3)structfile_operations2023/7/22structfile_operations{ structmodule*owner; loff_t(*llseek)(structfile*,loff_t,int); ssize_t(*read)(structfile*,char*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar*,size_t,loff_t*); int(*readdir)(structfile*,void*,filldir_t); unsignedint(*poll)(structfile*,structpoll_table_struct*); int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong); int(*mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*flush)(structfile*); int(*release)(structinode*,structfile*); int(*fsync)(structfile*,structdentry*,intdatasync); int(*fasync)(int,structfile*,int); int(*lock)(structfile*,int,structfile_lock*);… };2023/7/22目前对此结构体采用“标记化”方法进行赋值,下面是对此结构体变量s3c44b0_fops用“标记化”方法进行赋值的实例。staticstructfile_operationss3c440_fops={ owner:THIS_MODULE,
open:s3c2410_ts_open,
read:s3c2410_ts_read,
write:s3c2410_ts_write,
release:s3c2410_ts_release,};2023/7/225.1.6驱动程序常用函数
2023/7/221.字符设备注册及注销函数字符设备驱动程序可通过register_chrdev函数向内核注册设备,又可通过unregister_chrdev函数向内核注销设备。intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);voidunregister_chrdev(unsignedintmajor,constchar*name);2023/7/222.中断申请和释放函数设备驱动程序可通过request_irq函数向内核申请中断,又可通过free_irq函数释放中断。它们的定义如下:intrequest_irq(unsignedintirq, void(*handler)(int,void*,structpt_regs*), unsignedlongflags,
constchar*dev_name,
void*dev_id);voidfree_irq(unsignedint
irq,void*dev_id);3.阻塞型I/O操作函数当对设备进行read和write操作时,如果驱动程序无法立刻满足请求时,应当如何响应?驱动程序应当(缺省地)阻塞进程,使它进入睡眠直到请求可继续,即阻塞型I/O操作。可以通过调用以下函数让进程进入睡眠状态。voidsleep_on(structwait_queue**q);voidinterrutible_sleep_on(structwait_queue**q);又可以通过调用以下函数唤醒进程。voidwake_up(structwait_queue**q);voidwake_up_interrutible(structwait_queue**q);4.并发处理函数在编写驱动程序时,需要考虑进程并发处理。当一个进程请求内核驱动程序模块服务时,如果此时内核模块正忙,则可以将进程放入睡眠状态直到驱动程序模块空闲。可以通过调用以下函数完成并发处理。voidup(structsemaphore*sem);voiddown(structsemaphore*sem);intdown_interruptible(structsemaphore*sem);5.内核空间和用户空间的数据传递函数Linux运行在两种模式下:内核模式和用户模式,又叫内核态和用户态。内核模式对应于内核空间,用户模式对应于用户空间。unsignedlongcopy_to_user(void*to,constvoid*from,unsignedlongcount);unsignedlongcopy_from_user(void*to,constvoid*from,unsignedlongcount);6.设备文件自动创建函数可通过devfs_register函数完成设备的注册,以及设备文件的自动创建。函数的定义如下:devfs_register(devfs_handle_tdir,constchar*name,unsignedintflags,unsignedintmajor,unsignedintminor,umode_tmode,void*ops,void*info);2023/7/22小结:1、Linux系统将设备分3类。字符、块和网络。2、驱动程序的安装分2种方式。模块和直接编译到内核。3、驱动程序的使用。字符设备和块设备是通过设备文件来使用驱动程序;网络设备是通过套接字来使用网络驱动程序的。2023/7/225.1Linux驱动程序概述
5.2虚拟字符设备Demo驱动程序设计
5.3A/D驱动程序设计5.4步进电机驱动程序设计第5章:Linux驱动程序设计2023/7/225.1Linux驱动程序概述
5.2虚拟字符设备Demo驱动程序设计
5.3A/D驱动程序设计5.4步进电机驱动程序设计第5章:Linux驱动程序设计2023/7/225.1Linux驱动程序概述
5.2虚拟字符设备Demo驱动程序设计
5.3A/D驱动程序设计5.4步进电机驱动程序设计第5章:Linux驱动程序设计2023/7/22驱动程序与应用程序的区别?2023/7/22一、DEMO介绍1、Demo字符设备简介设有一个简单的虚拟字符设备Demo,该设备只在内核空间开辟一个40个字节的缓冲区(drv_buf)。要求为该设备设计一个驱动程序,它能够为应用程序提供读、写两种操作。2023/7/222、Demo驱动程序的功能说明如下:(1)将驱动程序编译成模块,以模块方式动态加载。(2)模块加载时,完成设备的注册。设备名为demo,主设备号为249,次设备号为0。(3)打开设备时,完成对缓冲区的初始化。(4)读操作时,将内核缓冲区中的数据读出。(5)写操作时,将数据写入内核缓冲区。(5)模块卸载时,完成设备的注销。2023/7/223、Demo设备驱动程序的结构(动画)2023/7/224、驱动程序的框架:S3c2410_adc_open(){…..}S3c2410_adc_release(){…..}S3c2410_adc_read(){…..}S3c2410_adc_write(){…..}staticstructfile_operationss3c2410_fops={
open: s3c2410_adc_open,
read: s3c2410_adc_read,
write:s3c2410_adc_write,
release:s3c2410_adc_release,};S3c2410_adc_init(){…..}S3c2410_adc_exit(){…..}module_init(S3c2410_adc_init);module_exit(S3c2410_adc_exit);2023/7/22二、驱动程序介绍实例:编写一个最简单的驱动程序demo.c
在内核空间开一个40个字节的缓存区drv_buf,请问应用如何访问它?用户区内核区drv_buf
要求设计2个函数,read用于读出缓存区的内容,write用于更新缓存区的内容。设备文件名:/dev/demo/0
主设备号为:249
次设备号为:02023/7/22demo_open(){…..}demo_release(){…..}demo_read(){…..}demo_write(){…..}staticstructfile_operationsdemo_fops={
open: demo_open,
read: demo_read,
write:demo_write,
release:demo_release,};demo_init(){…..}demo_exit(){…..}module_init(demo_init);module_exit(demo_exit);1、demo驱动程序的框架:2023/7/222、驱动程序函数初始化函数的主要功能是什么?demo_init(){…..}module_init(demo_init);设备驱动在加载时首先调用入口函数module_init()完成设备驱动的初始化工作,比如寄存器置位、结构体赋值、申请中断等。向内核注册本设备。注册成功后,该设备获得了系统分配的主设备号、自定义的次设备号,并建立起与文件系统的关联。2023/7/22staticint__initdemo_init(void){#ifdefCONFIG_DEVFS_FSdevfs_demo_dir=devfs_mk_dir(NULL,"demo",NULL);devfs_demoraw=devfs_register(devfs_demo_dir,"0",DEVFS_FL_DEFAULT, demo_MAJOR,demo_MINOR,S_IFCHR|S_IRUSR|S_IWUSR, &demo_fops,NULL);#elseintresult;SET_MODULE_OWNER(&demo_fops);result=register_chrdev(demo_MAJOR,"demo",&demo_fops);if(result<0)returnresult;#endifprintk(DEVICE_NAME"initialized\n");return0;}如果配置了设备文件系统,交叉编译环境配了注册设备文件/dev/demo/0驱动程序接口变量给设备文件系统创建目录/dev/demo用gcc编译时,会运行这一段。它只在系统中注册主设备号,不会生成设备文件。mknod/dev/democ24902023/7/22demo_open(){…..}demo_release(){…..}demo_read(){…..}demo_write(){…..}demo_init(){…..}demo_exit(){…..}module_init(demo_init);module_exit(demo_exit);demo驱动程序的框架:staticstructfile_operationsdemo_fops={
open: demo_open,
read: demo_read,
write:demo_write,
release:demo_release,};2023/7/22demo_open(){…..}demo_release(){…..}demo_read(){…..}demo_write(){…..}demo_init(){…..}demo_exit(){…..}module_init(demo_init);module_exit(demo_exit);demo驱动程序的框架:staticstructfile_operationsdemo_fops={
open: demo_open,
read: demo_read,
write:demo_write,
release:demo_release,};这是给结构赋值staticstructfile_operationsdemo_fops={
open: demo_open,
read: demo_read,
write:demo_write,
release:demo_release,};2023/7/22staticintdemo_open(structinode*inode,structfile*file){ MOD_INC_USE_COUNT; sprintf(drv_buf,"deviceopensucess!\n"); printk("deviceopensucess!\n"); return0;}staticintdemo_release(structinode*inode,structfile*filp){ MOD_DEC_USE_COUNT; printk("devicerelease\n"); return0;}模块计数器+1,表示增加了一个模块。模块计数器-1,表示减少了一个模块。2023/7/22staticssize_tdemo_write(structfile*filp,constchar*buffer,size_tcount){ copy_from_user(drv_buf,buffer,count); printk("userwritedatatodriver\n"); returncount;}staticssize_tdemo_read(structfile*filp,char*buffer,size_tcount,loff_t*ppos){ if(count>MAX_BUF_LEN) count=MAX_BUF_LEN; copy_to_user(buffer,drv_buf,count); printk("userreaddatafromdriver\n"); returncount;}将用户态的数据复制到内核态将内核态的数据复制到用户态2023/7/223、驱动程序编译过程驱动程序一般采用make工具进行编译。使用make工具的关键是编写Makefile文件。以下是编译成x86平台上的Makefile文件内容:KERNELDIR=/usr/src/linuxINCLUDEDIR=$(KERNELDIR)/includeCROSS_COMPILE=CC=$(CROSS_COMPILE)gccCFLAGS+=-I..CFLAGS+=-Wall-O-D__KERNEL__-DMODULE-I$(INCLUDEDIR)TARGET=demo.oOBJS=demo.c$(TARGET):$(OBJS) $(CC)-c$(CFLAGS)$^-o$@clean: rm-f*.o*~core.depend2023/7/22如果需要编译成ARM平台上的驱动程序,只需修改Makefile中KERNELDIR和CROSS_COMPILE变量即可,例如修改如下:#KERNELDIR=/usr/src/linuxKERNELDIR=/arm2410s/kernel-2410s
INCLUDEDIR=$(KERNELDIR)/include
#CROSS_COMPILE=CROSS_COMPILE=/opt/host/arm/bin/arm-linux-CC=$(CROSS_COMPILE)gccCFLAGS+=-I..CFLAGS+=-Wall-O-D__KERNEL__-DMODULE-I$(INCLUDEDIR)TARGET=demo.oOBJS=demo.c$(TARGET):$(OBJS) $(CC)-c$(CFLAGS)$^-o$@clean: rm-f*.o*~core.depend2023/7/22运行make命令后,就会生成驱动程序demo.o2023/7/224、驱动程序加载和设备文件创建加载驱动程序可以使用insmod命令,如下:#insmoddemo.o驱动程序加载时,如果系统支持设备文件系统,则系统会自动创建设备文件,否则需要手动创建。手动创建可使用mknod命令,如下:#mknod/dev/demo/0c24902023/7/22编写一个应用程序来测试驱动程序是否正确,要求测试程序test_demo.c的功能是:首先从设备上读出数据,并将数据显示在屏幕上,这时读到的数据为初始化值。然后向设备写入数据,再从设备上读出数据,又将数据显示在屏幕上,这时读到的数据应为上一步写入的数据三、应用程序2023/7/22intmain(){
intfd;
inti;
charbuf[255];
fd=open("/dev/demo",O_RDWR);//打开设备文件
if(fd<0){
printf("####DEMOdeviceopenfail####\n");
return(-1);
}
read(fd,buf,40);//从设备读取数据
printf("Fristreaddata:%s\n",buf);
printf("Pleaseinputstring\n"); scanf("%s",buf); write(fd,buf,40);//向设备写数据
read(fd,buf,40);//从设备读取数据 printf("Secondreaddata:%s\n",buf);
close(fd);//关闭设备 return0;
}运行的结果如何?2023/7/222.编译和运行(1)编译测试程序将测试程序编译成x86平台上运行的可执行程序,命令如下:#gcctest_demo.c-otest_demo将测试程序编译成ARM平台上运行的可执行程序,命令如下:#arm-linux-gcctest_demo.c-otest_demo2023/7/22(2)运行测试程序测试程序运行结果如下:#./test_demoFristreaddata:deviceopensucess!PleaseinputstringNanchangSecondreaddata:Nanchang2023/7/225.1Linux驱动程序概述
5.2虚拟字符设备Demo驱动程序设计
5.3A/D驱动程序设计5.4步进电机驱动程序设计第5章:Linux驱动程序设计2023/7/225.3.1A/D转换的基础理论5.3.2A/D转换的驱动程序分析5.3.3A/D转换应用程序分析5.3A/D驱动和测试程序设计2023/7/221、A/D是什么?A是analog的缩写,D是digital的缩写。A/D是将模拟信号转换成数字信号的意思。5.3.1A/D转换的基础理论2023/7/222、A/D的具体应用?(1)测试温度。(2)测试冒雾浓度(煤气浓度\CO2)。(3)压力5.3.1A/D转换的基础理论2023/7/223、A/D转换器是什么?
是模拟信号源与CPU之间的接口,它的任务是将连续变化的模拟信号转换成数字信号。2023/7/224、A/D转换器的类型有那些?A/D转换器的类型有:逐位比较型(逐次逼近型)、积分型、计数型、并行比较型、电压—频率型等。用户应根据使用的场合的具体要求,来决定选择那一种类型的转换器。2023/7/225、逐次逼近型A/D转换器的工作原理
设转换器最大可检测的电压值为4.096V,转换器的寄存器有效位为10位(即最大值为1024),则最小单位1表示的电压值为4.096/1024=0.004V。原理动画演示2023/7/22逐次逼近型A/D转换器的工作原理转换开始,先设定SAR寄存器的最高位为“1”,其余位为“0”,将试探值经D/A转换成电压Vc,然后将Vc与模拟输入电压Vx比较。如果Vx≥Vc,说明SAR最高位的“1”应予保留;如果Vx<Vc,说明SAR该位应予清零。然后再对SAR寄存器的次高位置“1”,依上述方法进行D/A转换和比较。如此重复上述过程,直至确定SAR寄存器的最低位为止。最后,逐次逼近寄存器SAR中的内容就是与输入模拟量V相对应的二进制数字量。2023/7/226、A/D转换器的电路图
ARMS3C2410芯片自带一个8路10位A/D转换器,并且支持触摸屏功能。ARM2410开发板只用作3路A/D转换器。2023/7/22ARMS3C2410芯片自带一个8路10位A/D转换器,并且支持触摸屏功能。2023/7/222023/7/22IO有控制、数据和状态寄存器,它们的功能是什么?2023/7/22A/D转换器的主要寄存器寄存器地址描述ADCCON0x58000000ADC转换控制寄存器ADCDAT00x58000000ADC转换数据寄存器2023/7/22ADCCON控制寄存器ADCCON位描述ECFLG[15]Endofconversionflag(readonly)0=A/Dconversioninprocess1=EndofA/DconversionPRSCEN[14]A/Dconversionprescalerenable0=Disable1=EnablePRSCVL[13:6]A/Dconverterprescalervalue.Datavalue:1–255Notethatdivisionfactoris(N+1)whentheprescalervalueisN.SEL—MUX[5:3]Analoginputchannelselect.000=AIN0001=AIN1010=AIN2011=AIN3100=AIN4101=AIN5110=AIN6111=AIN72023/7/22ADCCON控制寄存器ADCCON位描述STDBM[2]Standbymodeselect0=Normaloperationmode1=StandbymodeREAD_START[1]A/Dconversionstartbyread0=Disablestartbyreadoperation1=EnablestartbyreadoperationENABLE_START[0]A/Dconverterstartbysettingthisbit.IfREAD_STARTisenabled,thisvalueisnotvalid.0=Nooperation1=A/Dconversionstartsandthisbitisclearedafterthestart-up.2023/7/22A/D转换器接口输入电路图2023/7/22A/D转换器接口输入电路图工作流程动画演示2023/7/224.1A/D转换的基础理论4.2A/D转换的驱动程序分析4.3A/D转换应用程序分析5.4A/D驱动和测试程序设计2023/7/225、驱动程序分析驱动程序的框架:S3c2410_adc_open(){…..}S3c2410_adc_release(){…..}S3c2410_adc_read(){…..}S3c2410_adc_write(){…..}staticstructfile_operationss3c2410_fops={
open: s3c2410_adc_open,
read: s3c2410_adc_read,
write:s3c2410_adc_write,
release:s3c2410_adc_release,};S3c2410_adc_init(){…..}S3c2410_adc_exit(){…..}2023/7/22驱动程序设计的总体构思定义一个数据结构typedefstruct{
structsemaphorelock;
wait_queue_head_twait;
intchannel;存放具体操作的A/D通道
intprescale;操作时的比例因子值}ADC_DEV;
staticADC_DEVadcdev;read()函数的功能是:读取数据结构中,channal指向的A/D通道值。Write()函数的功能是向数据结构写A/D通道值和比例因子值。2023/7/22驱动程序设计的总体构思typedefstruct{
structsemaphorelock;
wait_queue_head_twait;
intchannel;intprescale;}ADC_DEV;
staticADC_DEVadcdev;S3c2410_adc_open(){…..}S3c2410_adc_release(){…..}S3c2410_adc_read(){…..}S3c2410_adc_write(){…..}staticstructfile_operationss3c2410_fops={
open: s3c2410_adc_open,
read: s3c2410_adc_read,
write:s3c2410_adc_write,
release:s3c2410_adc_release,};S3c2410_adc_init(){…..}S3c2410_adc_exit(){…..}2023/7/22驱动程序各函数的功能这个函数在什么时候运行?1、S3c2410_adc_init(){…..}安装驱动程序时,运行这个函数。设:生成的驱动程序的文件名为:adc.o则在运行insmodadc.o时执行此函数。2023/7/22驱动程序各函数的功能这个函数的主要功能是什么?1、S3c2410_adc_init(){…..}(1)申请中断,使用request_irq()函数。(2)申请主设备号,使用register_chrdev()函数。
(3)创建设备文件的目录和设备文件。使用devfs_mk_dir()和devfs_register()函数。
2023/7/22驱动程序各函数的功能这个函数什么时候运行?2、S3c2410_adc_exit(){…..}卸除驱动程序时,运行这个函数。设:在运行insmodadc.o时,生成一个名为adc的模块驱动程序(可以用lsmod来查看)。则在运行rmmodadc时执行此函数,这是删除已经安装的驱动程序。2023/7/22驱动程序各函数的功能这个函数的主要功能是什么?2、S3c2410_adc_exit(){…..}(3)删除已申请中断,使用free_irq()函数。(2)删除已申请主设备号,使用unregister_chrdev()函数。
(1)删除设备文件的文件和目录。使用devfs_unregister()函数。
2023/7/22驱动程序各函数的功能这个函数的主要功能是什么?3、S3c2410_adc_open(){…..}初始化数据结构typedefstruct{
structsemaphorelock;
wait_queue_head_twait;
intchannel; intprescale;}ADC_DEV;
staticADC_DEVadcdev;2023/7/22驱动程序各函数的功能这个函数的主要功能是什么?4、S3c2410_adc_release{…..}可以理解成,未做什么。设想成空函数2023/7/22驱动程序各函数的功能这个函数的主要功能是什么?5、S3c2410_adc_write{…..}
将应用程序传来的a/d通道和比例因子信息,保存到数据结构中。思考:write(指针,数据指针,数据长度),每次只能传送一个数据,如何传送2个数据(a/d通道和比例因子)?“a/d通道”+“比例因子”=新的数新的数“a/d通道”+“比例因子”2023/7/22驱动程序各函数的功能这个函数的主要功能是什么?6、S3c2410_adc_read{…..}
读出a/d的模拟电压值,有3个通道,读那一个?由数据结构中的值来决定。思考:a/d转换的几个过程?2023/7/22驱动程序各函数的功能A/d转换的步骤:(1)给数据结构加锁。不准改变数据结构中元素的数据。(3)向ADC控制寄存器写数据,告诉A/D转换开始工作。(4)A/D转换要花费时间,所以在A/D开始转换后,程序进入休眠状态,让CPU去做其它工作。(2)向ADC控制寄存器写数据,告诉选择那一个A/D转换通过道。2023/7/22驱动程序各函数的功能A/d转换的步骤:(5)A/D转换完成后,唤醒程序继续执行。(6)ADC数据寄存器的低10位就是模拟信息对应的数值。(因为S3C2410内部是10
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年护士执业资格考试题库(内科护理学专项)护理团队协作试题及答案
- 2026年不动产登记考试题及答案
- 2026年经济合同法考试题及答案
- 【2026年新】汽车维修高级工考试试题及答案
- 2026-2030中国电解液行业投资策略与发展前景分析报告版
- 2025年民事诉讼法真题及答案解析
- 2025-2026年甘肃省兰州市一中高一上学期英语期末试题及答案
- 2026年陕西宝鸡市新建路中学中考一模化学试卷
- 2026年山西省吕梁市临县刘家会九年制学校等第一次中考模拟化学试卷
- 商业办公楼能源节约创新方案
- 派驻组培训课件
- 2025年吉林省中考数学试卷 (含答案解析)
- 肾囊肿穿刺硬化术后护理
- 爱永在混声四声部合唱简谱
- 康复评定技术学课程大纲与教学目标
- 机械原理考试模拟题(含答案)
- 成都环境集团笔试题库
- 血透患者钙磷的管理
- 全媒体运营师职业技能竞赛试题及答案(251-500单选题)
- JCT2460-2018 预制钢筋混凝土化粪池
- (完整版)口腔科学试题库
评论
0/150
提交评论