




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
内核和设备驱动编程一、 实验目的学习linux操作系统下内核程序的编写和应用;学习8255和8253等可编程芯片的编程控制方法; 实现通过控制8255和8253来控制主板的扬声器发声。二、 实验原理 1、定时器/计数器8253简介Intel8252是微计算机系统中常用的定时/计数器,作为系统的硬件时钟设备在系统,它的内部有3个完全独立的16位计数器,而且每个计数器又有6中工作方式,可按二进制或十进制计数,每个计数通道都可随时设置或改变计数初值。8253在系统中分配的端口地址为40H43H。读写操作其功能表如下:CSWRRDA1A0操 作PC机地址00100写入计数器0初值40H00101写入计数器1初值41H00110写入计数器2初值42H00111写控制字43H01000读计数器0当前计数值40H01001读计数器1当前计数值41H01010读计数器2当前计数值42H控制字控制每个计数器的工作方式和计数方式,控制字寄存器的信息只能写入,不能读出。如下表:D7D6D5D4D3D2D1D0计数器选择:00=计数器0,01=计数器1,10=计数器2,11=回读(8254)计数器读写方式:00=计数器锁存,01=仅读写低8位,10=仅读写高8位,11=先读写低8位 后读写高8位工作方式设置:000=方式0,001=方式1,010=方式2,011=方式3,100=方式4,101=方式5计数方式:0为二进制计数,计数范围为065535, 1=BCD方式,计数范围为0000H9999H,工作方式8253三个计数器均有六个不同的计数/计时方式,介绍如下: 方式0计数结束产生中断 方式1可编程单稳态输出方式 方式2频率发生器/分频器 方式3方波发生器 方式4软件触发的选通信号发生器 方式5硬件触发的选通信号发生器 PC中8253的作用早期PC机中,8253作为系统的硬件时钟设备。8253在系统中占用40H43H端口。三个定时器/计数器的时钟输入均为1.19MHz,各自承担以下功能: T/C0:系统的日时钟,初始化为工作方式3,计数初值为0 T/C1:动态存储器刷新时钟,初始化为工作方式2,计数初值为12H T/C2:控制系统的扬声器,产生声音信号。它的控制端GATE2和扬声器前均接有控制信号,这些控制信号来自可编程I/O接口芯片8255的PB0和PB1。8255的初始化已将B口设为方式0输出。显然,T/C0和T/C1在系统中的作用比较重要,随意改动会导致系统错乱甚至崩溃。本次实验即控制T/C2,通过控制它来控制扬声器发声。较新的PC中已经不存在独立的8253等芯片,而是把它们集成在一块芯片中,但其控制方式在程序员看来仍然和控制独立芯片一样。2、 可编程并行接口8255A简介并行接口可分为硬线连接接口和可编程接口:硬线连接接口是直接使用导线将外设连接到主机,其工作方式和接口功能不能通过软件编程来实现;若可通过编程来实现,则就是可编程并行接口,如常用的8255。Intel8255A是一种通用的可编程并行I/O接口芯片,他有三个输入输出接口A口、B口和C口。8253的初始化已将A口设置为键盘输入端口,B口设置为方式0输出,本实验主要通过8255A的B口的低两位PB0和PB1来控制8253和扬声器的开关。个人计算机为8255A分配的端口为60H63H。 控制字用于控制8255A各个端口的工作方式和端口的输入/输出,具体如下D7D6D5D4D3D2D1D01A口方式A口C口74B口方式B口C口30特征位00=0方式01=1方式02=2方式0=输出1=输入0=输出1=输入0=0方式1=1方式0=输出1=输入0=输出1=输入工作方式可编程并行接口芯片有三种工作方式,可适用于CPU和I/O接口的多种数据传送方式。具体如下:方式0基本的输入/输出方式方式1选通输入输出方式方式2双向传输方式PC端口,当工作在方式1、2时,部分引线分配为专用联络信号。 音符和频率的对应表:音阶1234567低音131147165175196220247中音262294330370392440494高音5235876596987848809873、内部电路原理图如上图所示,8253通道2的计数由8255A的PB0控制,当PB0输出高电平时,使门控GATE2为高电平。此时,8253通道2允许计数,故通道2的输出方波受PB0的控制,从而可控制扬声器的音调高低。通道2的输出能否对扬声器产生持续控制还决定于8255A的PB1,当PB1为“0”时,OUT2不能通过“与门”;反之,则可通过“与门”来控制扬声器。所以,扬声器发音时间的长短取决于8255A的PB1信号。另外,CPU可通过读8255A的C口,得知8253通道2的状态和扬声器驱动器的状态。三、 实验过程1、 驱动模块编写初始化函数init_module() 初始化函数在模块被装入内核时调用,主要负责注册设备,分配io口资源等工作。int init_module(void)int ret;ret=register_chrdev(MAJOR,NAME,&fops);if(ret0) printk(”register error!”); return -1; return SUCCESS;register_chrdev(unsigned int major,const char *name,struct file_operations *fops)函数是为了向内核注册一个设备,其中major是被请求的主设备号,name是设备名称,fops是指向接口定义函数指针数组的指针,用于告诉内核可以对本设备进行什么操作。返回值为负表示错误,0或正值表示成功。本次MAJOR和NAME是宏,这里分别为222,和“8253”。从系统中删除设备驱动程序从系统中卸载模块时需要释放主设备号,释放在初始化函数中申请的资源等。程序如下: void cleanup_module(void)unregister_chrdev(MAJOR,NAME);printk(“byebye8253”);本实验由于io口都是固定的,不需要申请额外资源,故只需要调用unregister_chrdev()函数进行释放主设备号即可。以上是设备驱动模块最基本的两个函数,分别在将模块注入内核和卸载模块时调用。我们知道:用户程序是通过设备文件同硬件打交道,对设备文件的操作基本如同对普通文件操作一样,主要用到的函数有:open,read,write,close等,当然对io口操作少不了ioctl函数,因为此函数可以方便的提供对各种各样的硬件设备控制能力。而这些函数都对应着一个系统调用。当用户进程利用系统调用在对设备文件进行诸如open操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取file_operations结构体中相应的函数指针,接着把控制权交给该函数(例如本实验中用户程序对应驱动程序中的dopen()函数)。这是linux的设备驱动程序工作的基本原理。故编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个元素。分析本次实验需要实现的功能:1, 对8253进行初始化;2, 在用户程序改变声音频率时要改变8253的初值;3, 要往8255中写入输出信号(实际上是用来控制8253和扬声器的);可以发现,此次实验不需要从io口中读取数值,只需要写入控制字和频率等就可以了。往设备文件中写入数值,write和ioctl函数都可以,而以上任务需要分开执行,故用ioctl函数更好。当然,对于本次实验,write函数也完全满足要求,因为函数的功能基本完全在于函数的内容是为了实现什么。open函数open函数用来打开一个设备,在该函数中可以对设备进行初始化。如果该函数被赋为NULL,则打开设备会用永远成功,并不会对设备产生影响。故在open函数中可以什么都不做。当然为了防止设备被重复打开,需要进行对打开次数计数。open函数如下:static int dopen(struct inode *inode,struct file *file) if(Device_Open)printk(“8253 is busy”);return -EBUSY; Device_Open+; return SUCCESS;EBUSY为定义在include/asm-generic/errno-base.h中的宏定义,其值为16,至于返回-EBUSY,我认为应该就是看到负值就知道是出错了,然后可以根据绝对值来判断是什么地方出错。release函数release函数用于释放open函数中申请的资源,将在文件引用计数为0时,被系统调用,其对应应用程序中的close函数,但并不是每一次close系统调用都会引起release函数的调用。只有那些真正释放设备数据结构的close系统调用才会引起release函数的调用。因为Linux内核为每个file结构体维护其被引用多少次的计数器,只有当file结构体的计数器归0时,close系统调用才会引用release函数,这只在删除这个结构时才会发生,因此每次open驱动程序都只会看到一次对应的一次release调用。本实验没有申请io资源,故只需要关掉扬声器即可,方法是让8255送出0x00,禁止与门和定时器即可static int dclose(struct inode *inode,struct file *file)Device_Open-; outb_p(0,0x61); return SUCCESS;ioctl函数ioctl函数是本驱动程序中最重要的函数,因为对8253的控制基本全由ioctl函数实现。int dioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)int freq_low,freq_high;switch(cmd)case INIT : outb_p(0xb6,0x43);break; case START: outb_p(0x03,0x61);break; case FRE : freq_low = arg& 0x00ff;/得到低八位 freq_high =arg 8;/ outb_p(freq_low,0x42); outb_p(freq_high,0x42); break;case STOP : outb_p(0x00,0x61);break; default: break;INIT,START,FRE和STOP是宏定义,分别为1,2,3,4。其中INIT命令是为了初始化8253控制字,通过对8253控制字分析可知要写入10110110,表示用计数器2,并且计数值高低位都要写入,工作在方式3,用二进制方法计数,之所以用二进制计数是因为二进制最大可到65535,而BCD计数只能计到9999,使用二进制可有较大范围频率选择。由于8253工作方式3是高电平触发,所以要有START和STOP命令,分别用于启动8253(即使gate信号为高电平,打开与门)和关闭8253(使gate信号为低电平和关掉与门)。还要有一个FRE命令实现频率参数传递。ioctl第三个参数arg表示频率,由于对io口操作最多为8位,故需要将arg分为低八位和高八位来写入0x42地址。写入函数用类汇编语句outb_p(arg1,arg2),其中arg1 表示要写入的参数,arg2表示要写入的地址。以上就是控制8253需要的使用的函数,当然要想实现系统调用,需要将以上函数与file_operations中的成员相对应,从而控制硬件。定义过程过程如下struct file_operations fops=open:dopen,release:dclose,ioctl:dioctl, ;当然,上面的对应关系也可以使用如“.open=dopen”的格式实现。2,用户程序编写 用户程序相对比较简单,只要打开设备,并用ioctl函数实现开始,输入频率,关闭等,即可。因为驱动设计的是传入与频率相对应的定时器初值,故需要将频率转化成相应的定时器初值,根据音符和频率的对应表算出的对应定时器初值(二进制)如下(只计算了高阶的七个音符)音符1234567对应初值0x08e30x07e80x070d0x06a80x05ed0x05480x0485只要先实现让8253发声即完成了本次实验的大部分功能。最初主函数如下:int main() int fd; fd=open(./8253,O_RDWR);/打开设备,假设8253设备就在当前目录中 ioctl(fd,INIT,0); /初始化 ioctl(fd,FRE,0x07e8);/传入频率 ioctl(fd,START,0);/打开 sleep(1);/响一秒的时间 ioctl(fd,STOP,0);/关闭 close(fd);/关闭设备 return 0;其中FRE,START等命令如同设备驱动程序中的宏定义一样。3, 编译程序首先编译驱动模块,使用Makefile文件,Makefile如下:KSRC = /lib/modules/uname -r/buildPWD = $(shell pwd)obj-m = 8253_drive.odefault:$(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modulesclean:$(MAKE) -C $(KSRC) SUBDIRS=$(PWD) clean 执行make命令,生成驱动模块8253_drive.ko及一些中间文件。4, 加载驱动模块执行命令/sbin/insmod 8253_drive.ko然后执行lsmod可以看到8253_drive被加入到内核中,且被调用次数为0。证明加载成功。5, 创建设备节点执行mknod 8253 c 222 0 m 666生成字符设备文件8253,其主设备号为222,此设备号为0,所有用户都可读可写。6, 编译用户程序执行gcc o 8 8253_app.c生成可执行文件8;执行./8可以听到发出高音“1”,响一秒后结束。7, 修改用户程序,实现播出一段音乐的功能。在验证驱动可以工作后再实现此功能就比较简单,首先根据算出与频率相对应的计数器初值定义出七个音阶,unsigned int freq =0x08e3,0x07e8,0x070d,0x06a8,0x05ed,0x0548,0x0485;再根据乐谱写出谱unsigned char music =5,3,5,1,0,6,1,5,0,5,1,2,3,2,1,2,0,0,0,5,3,5,1,7,6,1,5,0,5,2,3,4,7,1,0,0,0,6,1,1,0,7,6,7,1,0,6,1,6,3,1,0,0,0;然后主程序如下: fd=open(./8253,O_RDWR); ioctl(fd,INIT,0); ioctl(fd,START,0); for(n=0;musicn!=0;n+) ioctl(fd,STOP,0); switch(musicn) case 1: ioctl(fd,FRE,freq0);break; case 2: ioctl(fd, FRE,freq1);break; case 3: ioctl(fd, FRE,freq2);break; case 4: ioctl(fd, FRE,freq3);break; case 5: ioctl(fd, FRE,freq4);break; case 6: ioctl(fd, FRE,freq5);break; case 7: ioctl(fd, FRE freq6);break; default : break; usleep(900000); ioctl(fd,STOP,0); close(fd); return 0;编译后执行,虽然乐谱是按照下面的写出来到,但实际的声音并不像是送别的声音,可能是对乐谱不太理解,并且每个声音响的时间都一样,这与乐谱不符。由于乐谱共有几十个节拍,时间较长,如果在响的过程中按Ctrl+c,很可能会导致扬声器一直按照同
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- flyingdonuts课件教学课件
- 6.3.1 生命的起源(说课稿)2023-2024学年八年级生物下册同步教学(冀少版河北专版)
- 江西省余干县七年级地理上册 1.1地球和地球仪说课稿 (新版)新人教版
- Excel课件讲解教学课件
- ERP销售课件教学课件
- 综合复习与测试说课稿高中数学人教B版2019必修第一册-人教B版2019
- 九年级化学下册 第十单元 酸和碱 课题2 酸和碱的中和反应第2课时 溶液的pH及其应用说课稿(新版)新人教版
- 2024-2025学年高中物理 第六章 传感器 3 实验:传感器的应用(1)说课稿 新人教版选修3-2
- 项目2 编五彩绳说课稿小学劳动一年级下册湘人版《劳动实践指导手册》
- Warming up说课稿中职基础课-基础模块 2-外研版(2021)-(英语)-52
- 《湖南民居特色》课件
- 2025年度火锅店合伙人合作协议书:特色火锅底料配方保密协议
- 脑血管造影术围手术期管理
- 岗位化验员述职报告
- 2023年价格鉴证师考试《价格鉴证案例分析》试题真题及答案二
- 小学阶段多音字总汇
- 生育服务证办理承诺书(河北省)
- 2025年中信保诚人寿保险有限公司招聘笔试参考题库含答案解析
- 两人合伙经营网吧协议
- 【课件】纪念长津湖吾辈当自强!课件 -2024年12.24纪念抗美援朝主题班会
- 全科医生培训个人总结
评论
0/150
提交评论