蜂鸣器作为简单的发声器件在电路中是个常用的元器件,它的控制比较简单,搭配简单的驱动电路,通过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\r\n");
return 0;
}
//关闭函数
static int misc_close(struct inode *node, struct file *fp)
{
printk("this dev is close\r\n");
return 0;
}
//读函数
ssize_t misc_read(struct file *fp, char __user *buf, size_t size, loff_t *loff)
{
printk("this dev is read\r\n");
return 0;
}
//写函数
ssize_t misc_write(struct file *fp, const char __user *buf, size_t size, loff_t *loff)
{
printk("this dev is write\r\n");
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\r\n");
return -1;
}
printk("this module is success\r\n");
return 0;
}
//驱动卸载
static void __exit misc_exit(void)
{
printk("this module is exit\r\n");
}
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\r\n");
return 0;
}
//关闭函数
static int misc_close(struct inode *node, struct file *fp)
{
printk("this dev is close\r\n");
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\r\n");
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\r\n");
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\r\n");
return -1;
}
printk("this module is success\r\n");
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\r\n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
#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;
}
#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]#