安徽省质量提升工程建设网站,h5设计制作是什么意思,临夏州建设厅官方网站,系统集成PWM(Pulse Width Modulation)——脉宽调制#xff0c;它是利用微控制器的数字输出来对模拟电路进行控制的一种非常有效的技术#xff0c;广泛应用于测量、通信、功率控制与变换等许多领域。s3c2440芯片中一共有5个16位的定时器#xff0c;其中有4个定时器(定时器0~定时器3)具…PWM(Pulse Width Modulation)——脉宽调制它是利用微控制器的数字输出来对模拟电路进行控制的一种非常有效的技术广泛应用于测量、通信、功率控制与变换等许多领域。s3c2440芯片中一共有5个16位的定时器其中有4个定时器(定时器0~定时器3)具有脉宽调制功能因此用s3c2440可以很容易地实现PWM功能。载有s3c2440芯片的Mini2440 板子带有一个蜂鸣器,它是由 PWM 控制的,下面是它的连接原理图:操控PWM主要分以下四步1、PWM是通过引脚TOUT0~TOUT3输出的而这4个引脚是与GPB0~GPB3复用的因此要实现PWM功能首先要把相应的引脚配置成TOUT输出。2、再设置定时器的输出时钟频率它是以PCLK为基准再除以用寄存器TCFG0配置的prescaler参数和用寄存器TCFG1配置的divider参数。3、然后设置脉冲的具体宽度它的基本原理是通过寄存器TCNTBn来对寄存器TCNTn(内部寄存器)进行配置计数TCNTn是递减的如果减到零则它又会重新装载TCNTBn里的数重新开始计数而寄存器TCMPBn作为比较寄存器与计数值进行比较当TCNTn等于TCMPBn时TOUTn输出的电平会翻转而当TCNTn减为零时电平会又翻转过来就这样周而复始。因此这一步的关键是设置寄存器TCNTBn和TCMPBn前者可以确定一个计数周期的时间长度而后者可以确定方波的占空比。由于s3c2440的定时器具有双缓存因此可以在定时器运行的状态下改变这两个寄存器的值它会在下个周期开始有效。4、最后就是对PWM的控制它是通过寄存器TCON来实现的一般来说每个定时器主要有4个位要配置(定时器0多一个死区位)启动/终止位用于启动和终止定时器手动更新位用于手动更新TCNTBn和TCMPBn这里要注意的是在开始定时时一定要把这位清零否则是不能开启定时器的输出反转位用于改变输出的电平方向使原先是高电平输出的变为低电平而低电平的变为高电平自动重载位用于TCNTn减为零后重载TCNTBn里的值当不想计数了可以使自动重载无效这样在TCNTn减为零后不会有新的数加载给它那么TOUTn输出会始终保持一个电平(输出反转位为0时是高电平输出输出反转位为1时是低电平输出)这样就没有PWM功能了因此这一位可以用于停止PWM。因此,我们需要在驱动程序中按照上述的操控序列就可以控制 PWM 的输出频率了。#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME pwm //设备名#define PWM_IOCTL_SET_FREQ 1 //定义宏变量,用于后面的 ioctl 中的控制命令#define PWM_IOCTL_STOP 0 //定义宏变量,用于后面的 ioctl 中的控制命令//定义信号量 lock用于互斥因此改驱动程序只能同时有一个进程使用static struct semaphore lock;/* freq: pclk/50/16/65536 ~ pclk/50/16* if pclk 50MHz, freq is 1Hz to 62500Hz* human ear : 20Hz~ 20000Hz*///设置 pwm 的频率,配置各个寄存器static void PWM_Set_Freq( unsigned long freq ){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//设置TCFG0寄存器prescaler 50tcfg0 ~S3C2410_TCFG_PRESCALER0_MASK; // S3C2410_TCFG_PRESCALER0_MASK 定时器 0 和1 的预分频值的掩码,清除TCFG[0~8]tcfg0 | (50 - 1); // 设置预分频为 50//设置TCFG1寄存器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; //清空低5位其中TCON[4] --Dead zone enable, TCON[3] -- Timer 0 auto reload on/off, TCON[2] -- Timer 0 output inverter on/off, TCON[1] -- Timer 0 manual update, TCON[0] -- Timer 0 start/stop /** 0xb: 0000 1011* disable dead zone, auto reload for Timer 0, output inverter off, Update TCNTB0TCMPB0, start for Timer 0*/tcon | 0xb;__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 cmd1 即进入 case PWM_IOCTL_SET_FREQif (arg 0) //如果设置的频率参数是 0return -EINVAL; //返回错误信息,表示向参数传递了无效的参数PWM_Set_Freq(arg); //否则设置频率break;case PWM_IOCTL_STOP: // if cmd2 即进入 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);测设程序如下#include #include #include #include #define PWM_IOCTL_SET_FREQ 1#define PWM_IOCTL_STOP 2#define ESC_KEY 0x1bstatic int getch(void){struct termios oldt,newt;int 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 );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);if (fd 0) {perror(open pwm_buzzer device);exit(1);}// any function exit call will stop the buzzeratexit(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);}}static void stop_buzzer(void){int ret ioctl(fd, PWM_IOCTL_STOP);if(ret 0) {perror(stop the buzzer);exit(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;}}}