蜂鸣器驱动文档模板
- 格式:doc
- 大小:1.48 MB
- 文档页数:20
易嵌教育•南京分中心安徽理工大学嵌入式系统开发课程设计专业:电子信息技术及仪器班级:电子仪器10-1班学号:2010302936姓名:訾振恒设计题目:蜂鸣器字符设备驱动设计开发日期:2013/3/27-2013/4/19目录目录 (1)一.任务 (2)1.目标 (2)2.环境 (2)3.需求: (2)二.总体设计 (2)1.处理流程 (2)2.模块介绍 (3)3.模块接口设计 (3)4.各个模块设计 (3)三.PWM蜂鸣器字符设备驱动 (3)1.模块设计 (3)1. 模块介绍 (3)2. 模块结构图 (4)2.接口设计 (4)1. 数据结构设计 (4)2. 驱动程序接口 (4)3.函数设计 (4)1.初始化函数 (5)2. 字符设备打开函数 (6)3. 字符设备关闭函数 (7)4. 模块卸载函数......................................................................................... (8)5. 文件操作接口函数 (8)四. PWM蜂鸣器字符设备驱动测试 (8)1.调用系统函数ioctl实现对蜂鸣器的控制 (8)五.MINI2440开发板调试 (9)六.综合设计总结与思考 (10)一.任务1.目标:编写按键蜂鸣器驱动程序函数与测试文件,实现上位机与mini2440-ARM9开发板的连接,利用函数实现对蜂鸣器通过按键来启动与关闭。
2.环境:①软件环境:windows 7 系统和VMware Workstation 软件②硬件环境:mini2440 开发板,内核部分Linux-2.6.29 ,交叉编译版本arm-linux-gcc-4.3.2Linux系统介绍:Linux是一种自由开发源码的类Unix操作系统,存在这许多不同的Linux 版本,但它们都使用了Linux内核。
Linux可安装在各种计算机硬件设备中,比如手机、平板电脑、路由器、视频游戏控制台、台式计算机、大型机和超级计算机。
Linux是一个领先的操作系统,世界上运算最快的10台超级计算机运行的都是Linux操作系统。
严格来说,Linux这个词本身只表示Linux内核,但实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU工程各种工具和数据库的操作系统。
Linux得名于天才程序员林纳斯·托瓦兹。
Mini2440开发板中模块介绍:①PWM蜂鸣器模块PWM(脉冲宽度调制)简单的讲是一种变频技术之一,是靠改变脉冲宽度来控制输出电压,通过改变周期来控制其输出频率。
如果还不是很清楚,好吧,来看看我们实际生活中的例子,我们的电风扇为什么扭一下按扭,风扇的转速就会发生变化;调一下收音机的声音按钮,声音的大小就会发生变化;还有待会儿我们要讲的蜂鸣器也会根据不同的输入值而发出不同频率的叫声等等!!这些都是PWM的应用,都是通过PWM输出的频率信号进行控制的。
②ARM Linux中的PWM根据S3C2440的手册介绍,S3C2440A内部有5个16位的定时器,定时器0、1、2、3都带有脉冲宽度调制功能(PWM),定时器4是一个没有输出引脚的内部定时器,定时器0有一个用于大电流设备的死区生成器。
看下图解释吧!!由S3C2440的技术手册和上面这幅结构图,我们来总结一下2440内部定时器模块的特性吧:1)共5个16位的定时器,定时器0、1、2、3都带有脉冲宽度调制功能(PWM);2)每个定时器都有一个比较缓存寄存器(TCMPB)和一个计数缓存寄存器(TCNTB);3)定时器0、1共享一个8位的预分频器(预定标器),定时器2、3、4共享另一个8位的预分频器(预定标器),其值范围是0~255;4)定时器0、1共享一个时钟分频器,定时器2、3、4共享另一个时钟分频器,这两个时钟分频器都能产生5种不同的分频信号值(即:1/2、1/4、1/8、1/16和TCLK);5)两个8位的预分频器是可编程的且根据装载的值来对PCLK进行分频,预分频器和钟分频器的值分别存储在定时器配置寄存器TCFG0和TCFG1中;6)有一个TCON控制寄存器控制着所有定时器的属性和状态,TCON的第0~7位控制着定时器0、第8~11位控制着定时器1、第12~15位控制着定时器2、第16~19位控制着定时器3、第20~22位控制着定时器4。
还是根据S3C2440手册的描述和上图的结构,要开始一个PWM定时器功能的步骤如下(假设使用的是第一个定时器):1)分别设置定时器0的预分频器值和时钟分频值,以供定时器0的比较缓存寄存器和计数缓存寄存器用;2)设置比较缓存寄存器TCMPB0和计数缓存寄存器TCNTB0的初始值(即定时器0的输出时钟频率);3)关闭定时器0的死区生成器(设置TCON的第4位);4)开启定时器0的自动重载(设置TCON的第3位);5)关闭定时器0的反相器(设置TCON的第2位);6)开启定时器0的手动更新TCNTB0&TCMPB0功能(设置TCON的第1位);7)启动定时器0(设置TCON的第0位);8)清除定时器0的手动更新TCNTB0&TCMPB0功能(设置TCON的第1位)。
由此可以看到,PWM的输出频率跟比较缓存寄存器和计数缓存寄存器的取值有关,而比较缓存寄存器和计数缓存寄存器的值又跟预分频器和时钟分频器的值有关;要使用PWM功能其实也就是对定时器的相关寄存器进行操作。
手册上也有一个公式:定时器输出频率= PCLK / {预分频器值+ 1} / 时钟分频值。
下面我们来通过一个蜂鸣器的实例来说明PWM功能的使用。
3.需求:要实现PC与mini2440开发板的通信,要求在PC机上的VMware Workstation 软件的Red Hat Enterprise Linux 5 环境下编写程序,包含蜂鸣器驱动程序和测试文件。
利用交叉编译器arm-linux-gcc-4.3.2生成目标文件,最后讲目标文件下载到开发板,并且驱动蜂鸣器根据按键的不同完成启动或者停止的操作。
二.总体设计1.处理流程:2.模块介绍:①按键模块:通过按键来操作蜂鸣器的启动与停止。
②蜂鸣器模块:通过加载蜂鸣器驱动模块到内核,驱动蜂鸣器。
①按键模块:A.正确驱动住设备号和次设备号B.实现字符设备驱动程序C.实现file-operation结构D.实现初始化函数,注册字符设备E.实现卸载函数,释放字符设备F.创建文件节点②按键模块:G.正确驱动住设备号和次设备号H.实现字符设备驱动程序I.实现file-operation结构J.实现初始化函数,注册字符设备K.实现卸载函数,释放字符设备L.创建文件节点各个模块设计:三.PWM蜂鸣器字符设备驱动3.模块介绍:蜂鸣器模块介绍及结构图在S3C2440开发板的芯片上有多种端口和引脚,比如说GPIO口,这是一种既可以作为输入,又可以作为输出的端口,即是一种复用端口,在芯片上有多种分类,分别是GPB、GPC、GPD、GPE、GPF、GPG、GPH、GPJ。
GPA0至GPA22是仅仅只能作为输出的端口,GPB0至GPB10是既可以作为输出又可以作为输入的端口,GPC0至GPC15也是既可以作为输入,也可以作为输入的端口,GPD (16个引脚),GPE(16个引脚),GPF(8个引脚),GPG(16个引脚),GPH (11个引脚),GPJ(13个引脚)都是复用端口。
要让蜂鸣器发声,需要两大要素:①将蜂鸣器接到正确的端口并且设置为输出口,②将端口设置为高电平(蜂鸣器接入原理如图1)图1有图1可知:蜂鸣器接在S3C2440芯片的GPB0口,且根据电路基本原理是当GPB0口为高电平时,蜂鸣器开始工作。
GPB0端口的高电平的控制在之后作详细的介绍。
图2 GPB系列管脚由查表可知,在GPB0口是一个复用的既可以输入又可以输出的端口如图2,并且通过查找S3C2440芯片的原理图可以找到GPB0所在的位置如图3和图4所示图3 S3C2440芯片引脚端口总图图4 GPB0引脚图当蜂鸣器正确接入芯片的时候就要开始对GPB0进行设置了,通过查询S3C2440的数据手册可以发现当GPB0为01时,这个端口即作为输出端口,具体介绍如图5所示:图5 GPB0引脚状态介绍综上所述,要使蜂鸣器发声,就是要让GPB0作为输出端,同时该端口要设为高电平。
也就是说GPB0设置为01为输出,让GPBDAT的最后一位设置为1则该端口就置成了高电平。
1.2模块代码分析:2.1打开设备模块static int BUZZER_open(struct inode *inode, struct file *file){if (!down_trylock(&lock))return 0;elsereturn -EBUSY;}此函数实现了怎么去打开设备,在设备文件上的第一个操作,并不要求驱动程序一定要实现这个方法。
如果该项为NULL,设备的打开操作永远成功。
Open方法是驱动程序用来为以后的操作完成初始化准备工作的。
在大部分驱动程序中,open完成如下工作:初始化设备,标明次设备号。
2.2关闭设备模块static int BUZZER_close(struct inode *inode, struct file *file){BUZZER_Stop();up(&lock);return 0;}当设备文件被关闭时调用这个操作。
与open相仿,release也可以没有,此处关闭函数为BUZZER_close。
Release方法的作用正好与open相反。
这个设备方法有时也称为close,它应该:关闭设备。
注意:本驱动程序要进行读和写。
2.3 开启蜂鸣器并设置蜂鸣器频率/* freq: pclk/50/16/65536 ~ pclk/50/16* if pclk = 50MHz, freq is 1Hz to 62500Hz* human ear : 20Hz~ 20000Hz*/static void BUZZER_Start( unsigned long freq ){unsigned long tcon;unsigned long tcnt;unsigned long tcfg1;unsigned long tcfg0;struct clk *clk_p;unsigned long pclk;//set GPB0 as tout0, pwm outputs3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);//设置gpio的工作模式,是输入,输出还是其他的, 就是设置GPB0为输出模式tcon = __raw_readl(S3C2410_TCON);tcfg1 = __raw_readl(S3C2410_TCFG1); //读取定时器配置寄存器1的值tcfg0 = __raw_readl(S3C2410_TCFG0); //读取定时器配置寄存器0值//prescaler = 50tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;tcfg0 |= (50 - 1); //fg0的值为49//mux = 1/16tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; //设置tcfg1的值为0x0011即:1/16 __raw_writel(tcfg1, S3C2410_TCFG1); //将值tcfg1写入定时器配置寄存器1中__raw_writel(tcfg0, S3C2410_TCFG0); //将值tcfg0写入定时器配置寄存器0中clk_p = clk_get(NULL, "pclk");pclk = clk_get_rate(clk_p); //从系统平台时钟队列中获取pclk的时钟频率,在include/linux/clk.h中定义tcnt = (pclk/50/16)/freq; //计算定时器0的输出时钟频率(pclk/{prescaler0 + 1}/divider value)__raw_writel(tcnt, S3C2410_TCNTB(0)); //设置定时器0计数缓存寄存器的值__raw_writel(tcnt/2, S3C2410_TCMPB(0)); //设置定时器0比较缓存寄存器的值tcon &= ~0x1f;tcon |= 0xb; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0__raw_writel(tcon, S3C2410_TCON); //设置定时器控制寄存器的0-4位,即对定时器0进行控制tcon &= ~2; //clear manual update bit__raw_writel(tcon, S3C2410_TCON); //清除定时器0的手动更新位}对GPB0复用口进行复用功能设置,设置为TOUT0 PWM输出,置GPIO口为输出功能,往相应的控制寄存器写值,并向相应的数据寄存器写值实现输出低电平还是高电平,控制蜂鸣器的开启与关闭。