最新ARM蜂鸣器驱动汇总.docx
《最新ARM蜂鸣器驱动汇总.docx》由会员分享,可在线阅读,更多相关《最新ARM蜂鸣器驱动汇总.docx(10页珍藏版)》请在冰豆网上搜索。
最新ARM蜂鸣器驱动汇总
ARM蜂鸣器驱动
在linux-2.6.32.2/drivers/char/目录下,增加一个驱动程序文件mini2440_pwm.c,内容如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineDEVICE_NAME"pwm"//设备名
#definePWM_IOCTL_SET_FREQ1//定义宏变量,用于后面的ioctl中的switchcase
#definePWM_IOCTL_STOP0//定义信号量lock
staticstructsemaphorelock;
/*freq:
pclk/50/16/65536~pclk/50/16
*ifpclk=50MHz,freqis1Hzto62500Hz
*humanear:
20Hz~20000Hz
*/
staticvoidPWM_Set_Freq(unsignedlongfreq)//设置pwm的频率,配置各个寄存器
{
unsignedlongtcon;
unsignedlongtcnt;
unsignedlongtcfg1;
unsignedlongtcfg0;
structclk*clk_p;
unsignedlongpclk;
//setGPB0astout0,pwmoutput设置GPB0为tout0,pwm输出
s3c2410_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPB0_TOUT0);
tcon=__raw_readl(S3C2410_TCON);//读取寄存器TCON到tcon
tcfg1=__raw_readl(S3C2410_TCFG1);//读取寄存器TCFG1到tcfg1
tcfg0=__raw_readl(S3C2410_TCFG0);//读取寄存器TCFG0到tcfg0
//prescaler=50
tcfg0&=~S3C2410_TCFG_PRESCALER0_MASK;//S3C2410_TCFG_PRESCALER0_MASK定时器0和1的预分频值的掩码,TCFG[0~8]
tcfg0|=(50-1);//预分频为50
//mux=1/16
tcfg1&=~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");//得到pclk
pclk=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;//disabledeadzone,auto-reload,inv-off,updateTCNTB0&TCMPB0,starttimer0
__raw_writel(tcon,S3C2410_TCON);//把tcon写到计数器控制寄存器S3C2410_TCON中
tcon&=~2;//clearmanualupdatebit
__raw_writel(tcon,S3C2410_TCON);
}
staticvoidPWM_Stop(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPIO_OUTPUT);//设置GPB0为输出
s3c2410_gpio_setpin(S3C2410_GPB(0),0);//设置GPB0为低电平,使蜂鸣器停止
}
staticints3c24xx_pwm_open(structinode*inode,structfile*file)
{
if(!
down_trylock(&lock))//是否获得信号量,是down_trylock(&lock)=0,否则非0
return0;
else
return-EBUSY;//返回错误信息:
请求的资源不可用
}
staticints3c24xx_pwm_close(structinode*inode,structfile*file)
{
PWM_Stop();
up(&lock);//释放信号量lock
return0;
}
/*cmd是1,表示设置频率;cmd是2,表示停止pwm*/
staticints3c24xx_pwm_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg)
{
switch(cmd){
casePWM_IOCTL_SET_FREQ:
//ifcmd=1即进入casePWM_IOCTL_SET_FREQ
if(arg==0)//如果设置的频率参数是0
return-EINVAL;//返回错误信息,表示向参数传递了无效的参数
PWM_Set_Freq(arg);//否则设置频率
break;
casePWM_IOCTL_STOP:
//ifcmd=2即进入casePWM_IOCTL_STOP
PWM_Stop();//停止蜂鸣器
break;
}
return0;//成功返回
}
/*初始化设备的文件操作的结构体*/
staticstructfile_operationsdev_fops={
.owner=THIS_MODULE,
.open=s3c24xx_pwm_open,
.release=s3c24xx_pwm_close,
.ioctl=s3c24xx_pwm_ioctl,
};
staticstructmiscdevicemisc={
.minor=MISC_DYNAMIC_MINOR,
.name=DEVICE_NAME,
.fops=&dev_fops,
};
staticint__initdev_init(void)
{
intret;
init_MUTEX(&lock);//初始化一个互斥锁
ret=misc_register(&misc);//注册一个misc设备
printk(DEVICE_NAME"\tinitialized\n");
returnret;
}
staticvoid__exitdev_exit(void)
{
misc_deregister(&misc);//注销设备
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARMInc.");
MODULE_DESCRIPTION("S3C2410/S3C2440PWMDriver");
这里不说明怎么修改Makefile和Kconfig,将其编译进内核之后,下载到板子上,下面直接给出应用程序pwm.c:
#include//标准输入输出定义
#include//POSIX终端控制定义
#include//Unix标准函数定义
#include//标准函数库定义
#definePWM_IOCTL_SET_FREQ1
#definePWM_IOCTL_STOP0
#defineESC_KEY0x1b//定义ESC_KEY为ESC按键的键值
staticintgetch(void)//定义函数在终端上获得输入,并把输入的量(int)返回
{
structtermiosoldt,newt;//终端结构体structtermios
intch;
if(!
isatty(STDIN_FILENO)){//判断串口是否与标准输入相连
fprintf(stderr,"thisproblemshouldberunataterminal\n");
exit
(1);
}
//saveterminalsetting
if(tcgetattr(STDIN_FILENO,&oldt)<0){//获取终端的设置参数
perror("savetheterminalsetting");
exit
(1);
}
//setterminalasneed
newt=oldt;
newt.c_lflag&=~(ICANON|ECHO);//控制终端编辑功能参数ICANON表示使用标准输入模式;参数ECH0表示显示输入字符
if(tcsetattr(STDIN_FILENO,TCSANOW,&newt)<0){//保存新的终端参数
perror("setterminal");
exit
(1);
}
ch=getchar();
//restoretermialsetting
if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt)<0){//恢复保存旧的终端参数
perror("restorethetermialsetting");
exit
(1);
}
returnch;
}
staticintfd=-1;
staticvoidclose_buzzer(void);
staticvoidopen_buzzer(void)//打开蜂鸣器
{
fd=open("/dev/pwm",0);//打开pwm设备驱动文件
if(fd<0){
perror("openpwm_buzzerdevice");//打开错误,则终止进程。
退出参数为1
exit
(1);
}
//anyfunctionexitcallwillstopthebuzzer
atexit(close_buzzer);//退出回调close_buzzer
}
staticvoidclose_buzzer(void)//关闭蜂鸣器
{
if(fd>=0){
ioctl(fd,PWM_IOCTL_STOP);//停止蜂鸣器
close(fd);//关闭设备驱动文件
fd=-1;
}
}
staticvoidset_buzzer_freq(intfreq)
{
//thisIOCTLcommandisthekeytosetfrequency
intret=ioctl(fd,PWM_IOCTL_SET_FREQ,freq);//设置频率
if(ret<0){//如果输入的频率错误
perror("setthefrequencyofthebuzzer");
exit
(1);//退出,返回1
}
}
staticvoidstop_buzzer(void)
{
intret=ioctl(fd,PWM_IOCTL_STOP);//关闭蜂鸣器
if(ret<0){//如果无法关闭蜂鸣器
perror("stopthebuzzer");
exit
(1);//退出返回1
}
}
intmain(intargc,char**argv)
{
intfreq=1000;
open_buzzer();//打开蜂鸣器
printf("\nBUZZERTEST(PWMControl)\n");
printf("Press+/-toincrease/reducethefrequencyoftheBUZZER\n");
printf("Press'ESC'keytoExitthisprogram\n\n");
while
(1)
{
intkey;
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;
caseESC_KEY:
caseEOF:
stop_buzzer();
exit(0);
default:
break;
}
}
}
使用#arm-linux-gcc–opwmpwm.c生成pwm可执行文件,将其下载到板子上,运行如下图,可以通过小键盘上的+-键调整蜂鸣器的屏率。