基於S3C2440芯片的蜂鳴器驅動開發

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章