1、首先說一下,我使用的開發板是Tiny210的開發板,蜂鳴器的電路原理圖和控制引腳圖如下:
2、S3C2440的控制寄存器和數據寄存器
(1)控制寄存器
(2)數據寄存器
(3)參考代碼:
1)buzzer.c
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/types.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<asm/io.h>
#include<asm/uaccess.h>
#define DEV_NAME "buzzer"
#define BUZZER_STOP 0
#define BUZZER_START 1
#defien GPD0_CON_ADDR 0xE02000A0
static struct cdev buzzer_dev ;//定義一個設備驅動結構體
static int buzzer_major = 0 ; //定義主設備號
dev_t dev_num ; //定義一個設備號變量
static int *map = NULL ; //定義一個map指針,在下面記錄轉換的地址
MODULE_LICENSE("Dual BSD/GPL"); //模塊遵從的協議GPL
void buzzer_start(void) //啓動蜂鳴器
{
unsigned int data;
data = ioread32(map+0x01); //
data = data|0x01; // 將data和1相或得1,即高電平
iowrite32(data, map+0x01); //
}
void buzzer_stop(void) //關閉蜂鳴器
{
unsigned int data;
data = ioread32(map+0x01); //
data&=~0x01; //將data與0相與得到0,即低電平
iowrite32(data, map+0x01); //
}
/* 打開操作 */
int buzzer_open(struct inode *node, struct file *fp)
{
unsigned int data;
request_mem_region(GPD0_CON_ADDR, 4, DEV_NAME); //實現物理地址到虛擬地址的映射
map = ioremap(GPD0_CON_ADDR, 8); //ioremap主要是檢查傳入地址的合法性,建立頁表(包括訪問權限),完成物理地址到虛擬地址的轉換。
data = ioread32(map); //
data = data&(~0x01<<1); //
data = data&(~0x01<<2); //
data = data&(~0x01<<3); //
data = data|0x01; //
iowrite32(data,map); //
return 0;
}
/* 關閉操作 */
int buzzer_release(struct inode *node, struct file *fp)
{
printk("buzzer_release...\n");
return 0;
}
/* 讀寫操作 */
ssize_t buzzer_read(struct file *fp, char __user* buf, size_t size, loff_t *offp)
{
return 0;
}
ssize_t buzzer_write(struct file *fp, const char __user* buf, size_t size, loff_t *offp)
{
return 0;
}
/* IO端口控制 */
int buzzer_ioctl(struct inode *node, struct file *fp, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case BUZZER_STOP: buzzer_stop(); break;
case BUZZER_START: buzzer_start(); break;
default:break;
}
return 0;
}
/*定義並初始化設備文件操作結構體*/
struct file_operations buzzer_ops={
.owner = THIS_MODULE,
.read = buzzer_read,
.write = buzzer_write,
.open = buzzer_open,
.release = buzzer_release,
.ioctl = buzzer_ioctl
};
static int __init buzzer_init(void) //初始化函數
{
int ret;
cdev_init(&buzzer_dev, &buzzer_ops); //初始化設備,參數分別爲設備驅動結構體和設備文件操作結構體
if(buzzer_major)
{
ret = register_chrdev_region(dev_num, 1, DEV_NAME);
}
else
{
alloc_chrdev_region(&dev_num, 0, 1, DEV_NAME); //此函數的功能是動態分配設備編號,該函數需要傳遞給它指定的第一個次設備號firstminor(一般爲0)和要分配的設備數count,以及設備名,調用該函數後自動分配得到的設備號保存在dev中。
buzzer_major = MAJOR(dev_num); //通過宏MAJOR獲取主設備號
printk("major %d\n", buzzer_major);
}
if(ret < 0)
{
printk("get dev_num error\n");
return ret;
}
buzzer_dev.owner = THIS_MODULE; //初始化設備主
buzzer_dev.ops = &buzzer_ops; //初始化設備文件操作結構體
cdev_add(&buzzer_dev, dev_num, 1); //向內核註冊設備字符驅動,參數本別爲:設備驅動結構體,設備號,設備數量
return 0;
}
static void __exit buzzer_exit(void) //設備卸載函數
{
printk("buzzer_exit...\n");
unregister_chrdev_region(dev_num, 1); //釋放字符設備設備號
cdev_del(&buzzer_dev); //註銷字符設備
}
module_init(buzzer_init); //設備驅動模塊從這裏加載
module_exit(buzzer_exit); //卸載設備驅動
2)Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?=/home/cf/ARM/linux-2.6.35.7
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
obj-m :=buzzer.o
endif
3) test.c
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#define BUZZER_STOP 0
#define BUZZER_START 1
int main()
{
int dev_fd;
dev_fd=open("/dev/test", O_RDWR); //打開設備驅動
if(dev_fd<0) //檢測設備能否正常打開
{
printf("cannot open buzzer_dev...\n");
return -1;
}
while(1)
{
ioctl(dev_fd,BUZZER_START,0); //打開蜂鳴器
sleep(1);
ioctl(dev_fd,BUZZER_STOP,0); //關閉蜂鳴器
sleep(1);
}
close(dev_fd); //關閉設備驅動
return 0;
}