mini2440蜂鸣器

来源:互联网 发布:iphoto链接网络吗 编辑:程序博客网 时间:2024/04/29 23:44
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/uaccess.h>#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <plat/regs-timer.h>#include <mach/regs-irq.h>#include <asm/mach/time.h>#include <linux/clk.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/miscdevice.h>#define DEVICE_NAME "pwm" //设备名#define PWM_IOCTL_SET_FREQ 1 //定义宏变量,用于后面的ioctl 中的switch case#define PWM_IOCTL_STOP 0 //定义信号量 lockstatic struct semaphore lock;/* freq: pclk/50/16/65536 ~ pclk/50/16* if pclk = 50MHz, freq is 1Hz to 62500Hz* human ear : 20Hz~ 20000Hz*/static void PWM_Set_Freq( unsigned long freq ) //设置pwm 的频率,配置各个寄存器{unsigned long tcon;unsigned long tcnt;unsigned long tcfg1;unsigned long tcfg0;struct clk *clk_p;unsigned long pclk;//set GPB0 as tout0, pwm output 设置GPB0 为tout0,pwm 输出s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);tcon = __raw_readl(S3C2410_TCON); //读取寄存器TCON 到tcontcfg1 = __raw_readl(S3C2410_TCFG1); //读取寄存器TCFG1 到tcfg1tcfg0 = __raw_readl(S3C2410_TCFG0); //读取寄存器TCFG0 到tcfg0//prescaler = 50tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; // S3C2410_TCFG_PRESCALER0_MASK定时器0 和1 的预分频值的掩码,TCFG[0~8]tcfg0 |= (50 - 1); // 预分频为50//mux = 1/16tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; //S3C2410_TCFG1_MUX0_MASK 定时器0 分割值的掩码:TCFG1[0~3]tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; //定时器0 进行16 分割__raw_writel(tcfg1, S3C2410_TCFG1); //把tcfg1 的值写到分割寄存器S3C2410_TCFG1 中__raw_writel(tcfg0, S3C2410_TCFG0); //把tcfg0 的值写到预分频寄存器S3C2410_TCFG0 中clk_p = clk_get(NULL, "pclk"); //得到pclkpclk = clk_get_rate(clk_p);tcnt = (pclk/50/16)/freq; //得到定时器的输入时钟,进而设置PWM 的调制频率__raw_writel(tcnt, S3C2410_TCNTB(0)); //PWM 脉宽调制的频率等于定时器的输入时钟__raw_writel(tcnt/2, S3C2410_TCMPB(0)); //占空比是50%tcon &= ~0x1f;tcon|= 0xb; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0__raw_writel(tcon, S3C2410_TCON); //把tcon 写到计数器控制寄存器S3C2410_TCON 中tcon &= ~2; //clear manual update bit__raw_writel(tcon, S3C2410_TCON);}static void PWM_Stop(void){s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT); //设置GPB0 为输出s3c2410_gpio_setpin(S3C2410_GPB(0), 0); //设置GPB0 为低电平,使蜂鸣器停止}static int s3c24xx_pwm_open(struct inode *inode, struct file *file){if (!down_trylock(&lock)) //是否获得信号量,是down_trylock(&lock)=0,否则非0return 0;elsereturn -EBUSY; //返回错误信息:请求的资源不可用}static int s3c24xx_pwm_close(struct inode *inode, struct file *file){PWM_Stop();up(&lock); //释放信号量lockreturn 0;}/*cmd 是1,表示设置频率;cmd 是2 ,表示停止pwm*/static int s3c24xx_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){switch (cmd) {case PWM_IOCTL_SET_FREQ: //if cmd=1 即进入case PWM_IOCTL_SET_FREQif (arg == 0) //如果设置的频率参数是0return -EINVAL; //返回错误信息,表示向参数传递了无效的参数PWM_Set_Freq(arg); //否则设置频率break;case PWM_IOCTL_STOP: // if cmd=2 即进入case PWM_IOCTL_STOPPWM_Stop(); //停止蜂鸣器break;}return 0; //成功返回}/*初始化设备的文件操作的结构体*/static struct file_operations dev_fops = {.owner = THIS_MODULE,.open = s3c24xx_pwm_open,.release = s3c24xx_pwm_close,.ioctl = s3c24xx_pwm_ioctl,};static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,};static int __init dev_init(void){int ret;init_MUTEX(&lock); //初始化一个互斥锁ret = misc_register(&misc); //注册一个misc 设备printk (DEVICE_NAME"\tinitialized\n");return ret;}static void __exit dev_exit(void){misc_deregister(&misc); //注销设备}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("FriendlyARM Inc.");MODULE_DESCRIPTION("S3C2410/S3C2440 PWM Driver");



app:



#include <stdio.h> //标准输入输出定义#include <termios.h> //POSIX 终端控制定义#include <unistd.h> //Unix 标准函数定义#include <stdlib.h> //标准函数库定义#define PWM_IOCTL_SET_FREQ 1#define PWM_IOCTL_STOP 0#define ESC_KEY 0x1b //定义ESC_KEY 为ESC 按键的键值static int getch(void) //定义函数在终端上获得输入,并把输入的量(int)返回{struct termios oldt,newt; //终端结构体struct termiosint ch;if (!isatty(STDIN_FILENO)) { //判断串口是否与标准输入相连fprintf(stderr, "this problem should be run at a terminal\n");exit(1);}// save terminal settingif(tcgetattr(STDIN_FILENO, &oldt) < 0) { //获取终端的设置参数perror("save the terminal setting");exit(1);}// set terminal as neednewt = oldt;newt.c_lflag &= ~( ICANON | ECHO ); //控制终端编辑功能参数ICANON 表示使用标准输入模式;参数ECH0 表示显示输入字符if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) { //保存新的终端参数perror("set terminal");exit(1);}ch = getchar();// restore termial settingif(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) { //恢复保存旧的终端参数perror("restore the termial setting");exit(1);}return ch;}static int fd = -1;static void close_buzzer(void);static void open_buzzer(void) //打开蜂鸣器{fd = open("/dev/pwm", 0); //打开pwm 设备驱动文件if (fd < 0) {perror("open pwm_buzzer device"); //打开错误,则终止进程。退出参数为1exit(1);}// any function exit call will stop the buzzeratexit(close_buzzer); //退出回调close_buzzer}static void close_buzzer(void) //关闭蜂鸣器{if (fd >= 0) {ioctl(fd, PWM_IOCTL_STOP); //停止蜂鸣器close(fd); //关闭设备驱动文件fd = -1;}}static void set_buzzer_freq(int freq){// this IOCTL command is the key to set frequencyint ret = ioctl(fd, PWM_IOCTL_SET_FREQ, freq); //设置频率if(ret < 0) { //如果输入的频率错误perror("set the frequency of the buzzer");exit(1); //退出,返回1}}static void stop_buzzer(void){int ret = ioctl(fd, PWM_IOCTL_STOP); //关闭蜂鸣器if(ret < 0) { //如果无法关闭蜂鸣器perror("stop the buzzer");exit(1); //退出返回1}}int main(int argc, char **argv){int freq = 1000 ;open_buzzer();//打开蜂鸣器printf( "\nBUZZER TEST ( PWM Control )\n" );printf( "Press +/- to increase/reduce the frequency of the BUZZER\n" ) ;printf( "Press 'ESC' key to Exit this program\n\n" );while( 1 ){int key;set_buzzer_freq(freq); //设置蜂鸣器频率printf( "\tFreq = %d\n", freq );key = getch();switch(key) {case '+':if( freq < 20000 )freq += 10;break;case '-':if( freq > 11 )freq -= 10 ;break;case ESC_KEY:case EOF:stop_buzzer();exit(0);default:break;}}}