tiny4412开发板蜂鸣器驱动

2019-07-13 03:47发布

简介

蜂鸣器作为简单的发声器件在电路中是个常用的元器件,它的控制比较简单,搭配简单的驱动电路,通过CPU I/O引脚的电平变化就可以控制它的发声与否。在高级控制中可以利用PWM波对蜂鸣器进行调音,这里只演示蜂鸣器是否发声,在tiny4412开发板上蜂鸣器驱动电路如下:
这里写图片描述
与蜂鸣器连接的引脚通过逐级查找,可以看到它的引脚与CPU GPD0引脚连接,分析蜂鸣器驱动电路可以得出这样的结论:CPU I/O输出高电平三极管导通,蜂鸣器通电会发出响声,CPU I/O输出低电平三极管截止,蜂鸣器不通电不会发出响声。
这里写图片描述

采用的驱动模型

由于该驱动只涉及简单的I/O口电平变化,驱动比较简单。这里采用杂项设备驱动模型写出该驱动,杂项设备驱动能自动创建设备文件,比起其余两种驱动类型要省事不少。
下面列出前面书写的杂项设备驱动模板(没有必要的安全检测,只有大概框架),蜂鸣器驱动将在下面的例子中改动: #include #include #include #include #include #define MISC_MINOR 255 //打开函数 static int misc_open(struct inode *node, struct file *fp) { printk("this dev is open "); return 0; } //关闭函数 static int misc_close(struct inode *node, struct file *fp) { printk("this dev is close "); return 0; } //读函数 ssize_t misc_read(struct file *fp, char __user *buf, size_t size, loff_t *loff) { printk("this dev is read "); return 0; } //写函数 ssize_t misc_write(struct file *fp, const char __user *buf, size_t size, loff_t *loff) { printk("this dev is write "); return 0; } struct file_operations fops={ .owner=THIS_MODULE, .open=misc_open, .read=misc_read, .write=misc_write, .release=misc_close, }; struct miscdevice mymisc={ .minor=MISC_MINOR, .name="mymisc", .fops=&fops, }; //驱动初始化 static int __init misc_init(void) { if(misc_register(&mymisc)) { printk("this module is insmod fail "); return -1; } printk("this module is success "); return 0; } //驱动卸载 static void __exit misc_exit(void) { printk("this module is exit "); } module_init(misc_init); module_exit(misc_exit); MODULE_LICENSE("GPL");

调用函数解释

  • ioremap
    函数原型:void* ioremap(unsigned long phys_addr,unsigned long size)
    作用:将实际物理地址映射到地址管理单元
    参数:phys_addr实际物理地址,size映射地址大小
    返回值:返回该物理地址在地址管理单元中地址,操作改地址等效于操作实际物理地址
  • iounmap
    函数原型:void iounmap(volatile void *addr)
    作用:取消地址映射
    参数:addr地址管理单元分配的地址
    返回值:无

为什么需要地址映射

CPU与单片机不同,单片机几乎所有资源都集中在一个片内,外设较少,存储空间不大一般地址均固化在单片机内部,在对相应地址进行操作时,只需要直接操作相应地址就可以。但是CPU不同,CPU构成复杂,寄存器较多,而且存储单元全部外置,属于扩展元件。一般内存较大。由于CPU扩展具有相当大的灵活性,因此CPU在设计时是不可能把所有可能用到的地址空间都固化在CPU内部(寻址区占用体积,消耗成本,只能向最大化设计,万一设计地址单元过小造成应用受限影响市场份额)。有时外设地址格式不统一,还需要考虑兼容性的问题。因此CPU设计者摒弃了这种实际预留物理地址的方法,而采用MMU地址管理的方式,只开辟一小块空间,当需要用到某个地址时只需要拿到MMU内部,MMU自动分配一块地址与实际地址对应,操作该地址就相当于操作实际物理地址。

查看手册配置相应的寄存器

GPD0功能配置寄存器,地址为0x11400000+0x000000A0=0x114000A0,每四位控制一个引脚,0输入,1输出等等,这里我们用到的是输出功能,相应位(GPDCON[1])配置为1
这里写图片描述
GPD0数据寄存器,输出时相应位赋值0/1,可以输出高低电平,引脚配置为输入,读取相应引脚可以获取IO状态,地址为0x11400000+0x000000A4=0x114000A4
这里写图片描述

示例代码

驱动代码

#include #include #include #include #include #include #include #include #define GPD0CON_ADDR 0x114000a0 #define GPD0DAT_ADDR 0x114000a4 static volatile unsigned long *gpd0con=NULL; static volatile unsigned long *gpd0dat=NULL; #define GPD0CON *gpd0con #define GPD0DAT *gpd0dat //打开函数 static int misc_open(struct inode *node, struct file *fp) { printk("this dev is open "); return 0; } //关闭函数 static int misc_close(struct inode *node, struct file *fp) { printk("this dev is close "); return 0; } //读函数 ssize_t misc_read(struct file *fp, char __user *buf, size_t size, loff_t *loff) { GPD0CON |= (0x1<<0); GPD0DAT &= 0x0; GPD0DAT |= (0x1<<0); printk("this dev is read "); return 0; } //写函数 ssize_t misc_write(struct file *fp, const char __user *buf, size_t size, loff_t *loff) { GPD0DAT &= ~(0x1<<0); printk("this dev is write "); return 0; } struct file_operations fops={ .owner=THIS_MODULE, .open=misc_open, .read=misc_read, .write=misc_write, .release=misc_close, }; struct miscdevice mymisc={ .minor=255, .name="mymisc", .fops=&fops, }; //驱动初始化 static int __init misc_init(void) { if(misc_register(&mymisc)) { printk("this module is insmod fail "); return -1; } printk("this module is success "); gpd0con=ioremap(GPD0CON_ADDR,4); gpd0dat=ioremap(GPD0DAT_ADDR,4); return 0; } //驱动卸载 static void __exit misc_exit(void) { iounmap(gpd0dat); iounmap(gpd0con); printk("this module is exit "); } module_init(misc_init); module_exit(misc_exit); MODULE_LICENSE("GPL");

app代码

#include #include #include #include #include #include int main(int argc,char *argv[]) { int fd,i; char buf[8]; fd=open(argv[1],O_RDWR); for(i=0;i<3;i++) { read(fd,buf,0); sleep(1); write(fd,buf,0); sleep(1); } close(fd); return 0; }

Makefile

#include #include #include #include #include #include int main(int argc,char *argv[]) { int fd,i; char buf[8]; fd=open(argv[1],O_RDWR); for(i=0;i<3;i++) { read(fd,buf,0); sleep(1); write(fd,buf,0); sleep(1); } close(fd); return 0; }

验证

安装驱动模块 [root@ZC/zhangchao]#ls Makefile misc.c misc.mod.c misc.o modules.order Module.symvers misc.ko misc.mod.o misc_app.c [root@ZC/zhangchao]#insmod misc.ko [ 25.585000] this module is success [root@ZC/zhangchao]#ls /dev/mymisc -l crw-rw---- 1 root root 10, 47 Jan 1 12:34 /dev/mymisc [root@ZC/zhangchao]# 运行app [root@ZC/zhangchao]#ls Makefile app misc.ko misc.mod.o misc_app.c Module.symvers misc.c misc.mod.c misc.o modules.order [root@ZC/zhangchao]#./app /dev/mymisc [ 194.775000] this dev is open [ 194.775000] this dev is read [ 195.775000] this dev is write [ 196.775000] this dev is read [ 197.775000] this dev is write [ 198.775000] this dev is read [ 199.775000] this dev is write [ 200.775000] this dev is close [root@ZC/zhangchao]#