tiny4412开发板蜂鸣器驱动

简介

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

采用的驱动模型

由于该驱动只涉及简单的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
tiny4412开发板蜂鸣器驱动_第3张图片
GPD0数据寄存器,输出时相应位赋值0/1,可以输出高低电平,引脚配置为输入,读取相应引脚可以获取IO状态,地址为0x11400000+0x000000A4=0x114000A4
tiny4412开发板蜂鸣器驱动_第4张图片

示例代码

驱动代码

#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");

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]#

你可能感兴趣的:(linux,tiny4412,个人笔记,随笔)