《OK6410-蜂鸣器驱动程序设计》之阻塞型字符设备
来源:互联网 发布:网络配线架 编辑:程序博客网 时间:2024/05/31 20:51
蜂鸣器是通过I/O 口GPF15来间接控制的,为了增加驱动能力,增加了三级管驱动电路。当三极管的基极(B)为高电平即GPF15 为高电平时,蜂鸣器会鸣叫,反之则不响。通过设置两者之间的时间(即改变频率)可以使蜂鸣器发出不同的声音,甚至播放乐曲。
OK6410蜂鸣器原理图:
通过I/O 口GPF15来控制:
查看s3c6410芯片手册,端口M对应的三个寄存器地址:
实验相应寄存器
端口配置寄存器
端口数据寄存器
代码:
been_wait.c
#include <linux/module.h>//内核模块相关宏定义,必须有#include <linux/init.h>//__init 和 __exit宏定义所在头文件#include <linux/miscdevice.h>// 混杂设备所需的头文件#include <linux/fs.h>// file_operations结构的定义所在的头文件#include <linux/ioport.h>// ioremap映射所需的头文件#include <asm/io.h>//io内存所需的头文件#include <linux/wait.h>//阻塞型IO所需的头文件#include <linux/sched.h>//进程调度所需的头文件#define GPFCON 0x7F0080A0 //蜂鸣器的控制端口的物理地址#define GPFDAT 0x7F0080A4 //蜂鸣器的数据端口的物理地址static volatile unsigned long* gpfcon_addr;//经过ioremap映射后的虚拟地址static volatile unsigned long* gpfdat_addr;void been_port_init(void){//设置GPF15寄存器为输出模式*gpfcon_addr &= (~(0x1<<(31)));*gpfcon_addr |= (0x1<<(2*15));//设置GPF[15]为低电平,不响*gpfdat_addr &= 0x7fff;}//开启蜂鸣器void been_start(void){*gpfdat_addr |= 0x8000;}//关闭蜂鸣器void been_stop(void){*gpfdat_addr &= 0x7fff;}DECLARE_WAIT_QUEUE_HEAD(wq);//初始化等待队列头static volatile int flag=0; //设置条件标志ssize_t my_read(struct file* filp,char __user* buf, size_t size,loff_t* ppos){if(filp->f_flags & O_NONBLOCK)//非阻塞的读取{if(flag !=0)been_stop();return -EAGAIN;}else{been_start();wait_event_interruptible(wq,flag!=0);flag=0;been_stop();}return 0;}ssize_t my_write(struct file* filp,const char __user* buf,size_t size,loff_t* ppos){flag=1;wake_up_interruptible(&wq); return 0;}struct file_operations my_fops={.owner = THIS_MODULE,.read = my_read,.write = my_write,};struct miscdevice mymisc={.minor = MISC_DYNAMIC_MINOR,//MISC_DYNAMIC_MINOR=10,动态的获得次设备号.name = "my_been",.fops = &my_fops,};static int __init been_wait_init(void){int ret;//申请IO内存,不是必须的。if(!request_mem_region(GPFCON,1,"been")){ret = -EBUSY;goto request_mem_failed;}gpfcon_addr = ioremap(GPFCON,1);//将物理地址映射为虚拟地址if(NULL==gpfcon_addr){ret = -EIO;printk("gpfcon remap failed\n");goto con_map_failed;}gpfdat_addr = ioremap(GPFDAT,1);if(NULL==gpfdat_addr){ret = -EIO;printk("gpfdat remap failed\n");goto dat_map_failed;}printk("gpfcon_addr remap on %p\n",gpfcon_addr);printk("gpfdat_addr remap on %p\n",gpfdat_addr);been_port_init();//初始化beenret=misc_register(&mymisc);//注册一个混杂设备驱动,主设备号为10if(ret){printk("misc_register failed\n");goto failed;}printk("been init\n");return 0;failed:iounmap(gpfdat_addr);dat_map_failed:iounmap(gpfcon_addr);con_map_failed:release_mem_region(GPFCON,1);request_mem_failed:return ret;}static void __exit been_wait_exit(void){iounmap(gpfdat_addr); //取消映射iounmap(gpfcon_addr);release_mem_region(GPFCON, 1); //释放I/O内存misc_deregister(&mymisc); printk("been exit\n");}module_init(been_wait_init);module_exit(been_wait_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("liye");方案2:
#include <linux/module.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/gpio.h>#include <linux/io.h>#include <plat/gpio-core.h>#include <plat/gpio-cfg.h>#include <plat/gpio-cfg-helpers.h>void been_port_init(void){s3c_gpio_cfgpin(S3C64XX_GPF(15),S3C_GPIO_OUTPUT); //设置端口为输出gpio_set_value(S3C64XX_GPF(15),0); //设置端口值为低电平}void been_start(void){gpio_set_value(S3C64XX_GPF(15),1);}void been_stop(void){gpio_set_value(S3C64XX_GPF(15),0);}DECLARE_WAIT_QUEUE_HEAD(wq);static volatile int flag=0;ssize_t my_read(struct file* filp,char __user* buf, size_t size,loff_t* ppos){if(filp->f_flags & O_NONBLOCK){if(flag !=0)been_stop();return -EAGAIN;}else{been_start();wait_event_interruptible(wq,flag!=0);flag=0;been_stop();}return 0;}ssize_t my_write(struct file* filp,const char __user* buf,size_t size,loff_t* ppos){flag=1;wake_up_interruptible(&wq);return 0;}struct file_operations my_fops={.owner = THIS_MODULE,.read = my_read,.write = my_write,};struct miscdevice mymisc={.minor = MISC_DYNAMIC_MINOR,//MISC_DYNAMIC_MINOR=10.name = "my_been",.fops = &my_fops,};static int __init been_wait_init(void){int ret;been_port_init();ret=misc_register(&mymisc);if(ret){printk("misc_register failed\n");return -1;}printk("been init\n");return 0;}static void __exit been_wait_exit(void){misc_deregister(&mymisc);}module_init(been_wait_init);module_exit(been_wait_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("liye");
测试代码:
read.c
#include <stdio.h>#include <fcntl.h>int main(){int fd;char buf;fd=open("/dev/my_been",O_RDWR);read(fd,buf,1);return 0;}
write.c
#include <stdio.h>#include <fcntl.h>int main(){int fd;char buf='a';fd=open("/dev/my_been",O_RDWR);write(fd,buf,1);return 0;}
Makefile
ifneq ($(KERNELRELEASE),)obj-m := been_wait.oelse KDIR := /home/liye/forlinux/linux-2.6.36all:make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-install:cp been_wait.ko write read /home/liye/forlinux/rootfs/courseclean:rm -f *.o *.ko *.mod.c *.mod.o *.order *.symversendif
- 《OK6410-蜂鸣器驱动程序设计》之阻塞型字符设备
- OK6410之ADC驱动程序 字符设备驱动
- OK6410之蜂鸣器buzzer字符驱动
- ok6410之lcd驱动程序设计
- 字符设备驱动程序之同步互斥阻塞
- 字符设备驱动程序设计
- 字符设备驱动程序设计
- 和菜鸟一起学OK6410之蜂鸣器buzzer字符驱动
- OK6410之ADC驱动程序 混杂设备
- Linux3.6.7在OK6410平台的移植(五)字符设备驱动程序之LED
- 字符设备驱动程序的设计
- Linux设备驱动程序——高级字符驱动程序操作(阻塞型I/O)
- Linux 驱动程序笔记3--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志
- linux字符设备驱动程序的设计之休眠
- 阻塞型字符设备
- ok6410学习笔记(19.块设备驱动程序设计)
- Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]
- Linux驱动程序设计--字符设备设备号
- 什么是社会主义 (2012-08-06 07:58:24)
- 怎样写一个解释器 (2012-08-01 12:47:50)
- 输入textbox查找listbox 内容符合项
- 论研究 (2012-07-30 05:19:42)
- Android学习笔记(21)---使用Service后台播放MediaPlayer的音乐
- 《OK6410-蜂鸣器驱动程序设计》之阻塞型字符设备
- 理解redo(6)日志却的流程和直接路径加载的REDO分析
- 一个中国人的反省 (2012-07-28 09:42:30)
- SQL外连接
- uva 10026 - Shoemaker's Problem
- 什么是语义学 (2012-07-25 12:51:58)
- Feynman物理学讲座视频 (2012-07-21 11:21:52)
- GTF: Great Teacher Friedman (2012-07-04 22:34:38)
- 如何掌握程序语言 (2012-05-25 14:19:58)