<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > PWM在ARM Linux中的原理和蜂鳴器驅(qū)動(dòng)實(shí)例開(kāi)發(fā)

          PWM在ARM Linux中的原理和蜂鳴器驅(qū)動(dòng)實(shí)例開(kāi)發(fā)

          作者: 時(shí)間:2016-11-09 來(lái)源:網(wǎng)絡(luò) 收藏
          1. 什么是PWM

          PWM(脈沖寬度調(diào)制)簡(jiǎn)單的講是一種變頻技術(shù)之一,是靠改變脈沖寬度來(lái)控制輸出電壓,通過(guò)改變周期來(lái)控制其輸出頻率。如果還不是很清楚,好吧,來(lái)看看我們實(shí)際生活中的例子,我們的電風(fēng)扇為什么扭一下按扭,風(fēng)扇的轉(zhuǎn)速就會(huì)發(fā)生變化;調(diào)一下收音機(jī)的聲音按鈕,聲音的大小就會(huì)發(fā)生變化;還有待會(huì)兒我們要講的蜂鳴器也會(huì)根據(jù)不同的輸入值而發(fā)出不同頻率的叫聲等等??!這些都是PWM的應(yīng)用,都是通過(guò)PWM輸出的頻率信號(hào)進(jìn)行控制的。

          本文引用地址:http://www.ex-cimer.com/article/201611/318018.htm

          2. ARM Linux中的PWM

          根據(jù)S3C2440的手冊(cè)介紹,S3C2440A內(nèi)部有5個(gè)16位的定時(shí)器,定時(shí)器0、1、2、3都帶有脈沖寬度調(diào)制功能(PWM),定時(shí)器4是一個(gè)沒(méi)有輸出引腳的內(nèi)部定時(shí)器,定時(shí)器0有一個(gè)用于大電流設(shè)備的死區(qū)生成器。看下圖解釋吧??!


          由S3C2440的技術(shù)手冊(cè)和上面這幅結(jié)構(gòu)圖,我們來(lái)總結(jié)一下2440內(nèi)部定時(shí)器模塊的特性吧:

          1)共5個(gè)16位的定時(shí)器,定時(shí)器0、1、2、3都帶有脈沖寬度調(diào)制功能(PWM);
          2)每個(gè)定時(shí)器都有一個(gè)比較緩存寄存器(TCMPB)和一個(gè)計(jì)數(shù)緩存寄存器(TCNTB);
          3)定時(shí)器0、1共享一個(gè)8位的預(yù)分頻器(預(yù)定標(biāo)器),定時(shí)器2、3、4共享另一個(gè)8位的預(yù)分頻器(預(yù)定標(biāo)器),其值范圍是0~255;
          4)定時(shí)器0、1共享一個(gè)時(shí)鐘分頻器,定時(shí)器2、3、4共享另一個(gè)時(shí)鐘分頻器,這兩個(gè)時(shí)鐘分頻器都能產(chǎn)生5種不同的分頻信號(hào)值(即:1/2、1/4、1/8、1/16和TCLK);
          5)兩個(gè)8位的預(yù)分頻器是可編程的且根據(jù)裝載的值來(lái)對(duì)PCLK進(jìn)行分頻,預(yù)分頻器和鐘分頻器的值分別存儲(chǔ)在定時(shí)器配置寄存器TCFG0和TCFG1中;
          6)有一個(gè)TCON控制寄存器控制著所有定時(shí)器的屬性和狀態(tài),TCON的第0~7位控制著定時(shí)器0、第8~11位控制著定時(shí)器1、第12~15位控制著定時(shí)器2、第16~19位控制著定時(shí)器3、第20~22位控制著定時(shí)器4。

          還是根據(jù)S3C2440手冊(cè)的描述和上圖的結(jié)構(gòu),要開(kāi)始一個(gè)PWM定時(shí)器功能的步驟如下(假設(shè)使用的是第一個(gè)定時(shí)器):

          1)分別設(shè)置定時(shí)器0的預(yù)分頻器值和時(shí)鐘分頻值,以供定時(shí)器0的比較緩存寄存器和計(jì)數(shù)緩存寄存器用;
          2)設(shè)置比較緩存寄存器TCMPB0和計(jì)數(shù)緩存寄存器TCNTB0的初始值(即定時(shí)器0的輸出時(shí)鐘頻率);
          3)關(guān)閉定時(shí)器0的死區(qū)生成器(設(shè)置TCON的第4位);
          4)開(kāi)啟定時(shí)器0的自動(dòng)重載(設(shè)置TCON的第3位);
          5)關(guān)閉定時(shí)器0的反相器(設(shè)置TCON的第2位);
          6)開(kāi)啟定時(shí)器0的手動(dòng)更新TCNTB0&TCMPB0功能(設(shè)置TCON的第1位);
          7)啟動(dòng)定時(shí)器0(設(shè)置TCON的第0位);
          8)清除定時(shí)器0的手動(dòng)更新TCNTB0&TCMPB0功能(設(shè)置TCON的第1位)。

          由此可以看到,PWM的輸出頻率跟比較緩存寄存器和計(jì)數(shù)緩存寄存器的取值有關(guān),而比較緩存寄存器和計(jì)數(shù)緩存寄存器的值又跟預(yù)分頻器和時(shí)鐘分頻器的值有關(guān);要使用PWM功能其實(shí)也就是對(duì)定時(shí)器的相關(guān)寄存器進(jìn)行操作。手冊(cè)上也有一個(gè)公式:定時(shí)器輸出頻率 = PCLK / {預(yù)分頻器值 + 1} / 時(shí)鐘分頻值。下面我們來(lái)通過(guò)一個(gè)蜂鳴器的實(shí)例來(lái)說(shuō)明PWM功能的使用。

          三、蜂鳴器驅(qū)動(dòng)實(shí)例

          1. 蜂鳴器的種類和工作原理

          蜂鳴器主要分為壓電式蜂鳴器和電磁式蜂鳴器兩種類型。

          壓電式蜂鳴器主要由多諧振蕩器、壓電蜂鳴片、阻抗匹配器及共鳴箱、外殼等組成。有的壓電式蜂鳴器外殼上還裝有發(fā)光二極管。多諧振蕩器由晶體管或集成電路構(gòu)成。當(dāng)接通電源后(1.5~15V直流工作電壓),多諧振蕩器起振,輸出1.5~2.5kHZ的音頻信號(hào),阻抗匹配器推動(dòng)壓電蜂鳴片發(fā)聲。

          電磁式蜂鳴器由振蕩器、電磁線圈、磁鐵、振動(dòng)膜片及外殼等組成。接通電源后,振蕩器產(chǎn)生的音頻信號(hào)電流通過(guò)電磁線圈,使電磁線圈產(chǎn)生磁場(chǎng)。振動(dòng)膜片在電磁線圈和磁鐵的相互作用下,周期性地振動(dòng)發(fā)聲。

          有源蜂鳴器和無(wú)源蜂鳴器的區(qū)別:這個(gè)“源”字是不是指電源,而是指震蕩源,即有源蜂鳴器內(nèi)有振蕩源而無(wú)源蜂鳴器內(nèi)部沒(méi)有振蕩源。有振蕩源的通電就可以發(fā)聲,沒(méi)有振蕩源的需要脈沖信號(hào)驅(qū)動(dòng)才能發(fā)聲。

          額外知識(shí):簡(jiǎn)單蜂鳴器的制作方法
          1)制備電磁鐵M:在長(zhǎng)約6厘米的鐵螺栓上繞100圈導(dǎo)線,線端留下5厘米作引線,用透明膠布把線圈粘好,以免線圈松開(kāi),再用膠布把它粘在一個(gè)盒子上,電磁鐵就做好了;
          2)制備彈片P:從鐵罐頭盒上剪下一條寬約2厘米的長(zhǎng)鐵片,彎成直角,把電磁鐵的一條引線接在彈片上,再用膠布把彈片緊貼在木板上;
          3)用曲別針做觸頭Q,用書(shū)把曲別針墊高,用膠布粘牢,引出一條導(dǎo)線,如圖連接好電路;
          4)調(diào)節(jié)M與P之間的距離(通過(guò)移動(dòng)盒子),使電磁鐵能吸引彈片,調(diào)節(jié)觸點(diǎn)與彈片之間的距離,使它們能恰好接觸,通電后就可以聽(tīng)到蜂鳴聲。

          2. 開(kāi)發(fā)板上蜂鳴器原理圖分析

          由原理圖可以得知,蜂鳴器是通過(guò)GPB0 IO口使用PWM信號(hào)驅(qū)動(dòng)工作的,而GPB0口是一個(gè)復(fù)用的IO口,要使用它得先把他設(shè)置成TOUT0 PWM輸出模式。

          3. 編寫(xiě)合適開(kāi)發(fā)板的蜂鳴器驅(qū)動(dòng)程序,文件名:my2440_pwm.c

          /*
          ================================================
          Name : my2440_pwm.c
          Author : Huang Gang
          Date : 25/11/09
          Copyright : GPL
          Description : my2440 pwm driver
          ================================================
          */

          #include
          #include
          #include
          #include
          #include
          #include
          #include
          #include
          #include
          #include
          #include

          #definePWM_MAJOR 0//主設(shè)備號(hào)
          #definePWM_NAME"my2440_pwm"http://設(shè)備名稱

          staticintdevice_major=PWM_MAJOR;//系統(tǒng)動(dòng)態(tài)生成的主設(shè)備號(hào)

          //打開(kāi)設(shè)備
          staticintpwm_open(structinode*inode,structfile*file)
          {
          //對(duì)GPB0復(fù)用口進(jìn)行復(fù)用功能設(shè)置,設(shè)置為TOUT0 PWM輸出
          s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_TOUT0);

          return0;
          }

          //關(guān)閉設(shè)備
          staticintpwm_close(structinode*inode,structfile*file)
          {
          return0;
          }

          //對(duì)設(shè)備進(jìn)行控制
          staticintpwm_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg)
          {
          if(cmd<=0)//如果輸入的參數(shù)小于或等于0的話,就讓蜂鳴器停止工作
          {
          //這里又恢復(fù)GPB0口為IO口輸出功能,由原理圖可知直接給低電平可讓蜂鳴器停止工作
          s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_OUTP);
          s3c2410_gpio_setpin(S3C2410_GPB0,0);
          }
          else//如果輸入的參數(shù)大于0,就讓蜂鳴器開(kāi)始工作,不同的參數(shù),蜂鳴器的頻率也不一樣
          {
          //定義一些局部變量
          unsignedlongtcon;
          unsignedlongtcnt;
          unsignedlongtcfg1;
          unsignedlongtcfg0;

          structclk*clk_p;
          unsignedlongpclk;

          //以下對(duì)各寄存器的操作結(jié)合上面講的開(kāi)始一個(gè)PWM定時(shí)器的步驟和2440手冊(cè)PWM寄存器操作部分來(lái)看就比較容易理解
          tcfg1=__raw_readl(S3C2410_TCFG1);//讀取定時(shí)器配置寄存器1的值
          tcfg0=__raw_readl(S3C2410_TCFG0);//讀取定時(shí)器配置寄存器0的值

          tcfg0&=~S3C2410_TCFG_PRESCALER0_MASK;
          tcfg0|=(50-1);//設(shè)置tcfg0的值為49

          tcfg1&=~S3C2410_TCFG1_MUX0_MASK;
          tcfg1|=S3C2410_TCFG1_MUX0_DIV16;//設(shè)置tcfg1的值為0x0011即:1/16

          __raw_writel(tcfg1,S3C2410_TCFG1);//將值tcfg1寫(xiě)入定時(shí)器配置寄存器1中
          __raw_writel(tcfg0,S3C2410_TCFG0);//將值tcfg0寫(xiě)入定時(shí)器配置寄存器0中

          clk_p=clk_get(NULL,"pclk");
          pclk=clk_get_rate(clk_p);//從系統(tǒng)平臺(tái)時(shí)鐘隊(duì)列中獲取pclk的時(shí)鐘頻率,在include/linux/clk.h中定義
          tcnt=(pclk/50/16)/cmd;//計(jì)算定時(shí)器0的輸出時(shí)鐘頻率(pclk/{prescaler0 + 1}/divider value)

          __raw_writel(tcnt,S3C2410_TCNTB(0));//設(shè)置定時(shí)器0計(jì)數(shù)緩存寄存器的值
          __raw_writel(tcnt/2,S3C2410_TCMPB(0));//設(shè)置定時(shí)器0比較緩存寄存器的值

          tcon=__raw_readl(S3C2410_TCON);//讀取定時(shí)器控制寄存器的值

          tcon&=~0x1f;
          tcon|=0xb;//關(guān)閉死區(qū)、自動(dòng)重載、關(guān)反相器、更新TCNTB0&TCMPB0、啟動(dòng)定時(shí)器0
          __raw_writel(tcon,S3C2410_TCON);//設(shè)置定時(shí)器控制寄存器的0-4位,即對(duì)定時(shí)器0進(jìn)行控制

          tcon&=~2;
          __raw_writel(tcon,S3C2410_TCON);//清除定時(shí)器0的手動(dòng)更新位
          }

          return0;
          }

          //設(shè)備操作結(jié)構(gòu)體
          staticstructfile_operations pwm_fops=
          {
          .owner=THIS_MODULE,
          .open=pwm_open,
          .release=pwm_close,
          .ioctl=pwm_ioctl,
          };

          //定義一個(gè)設(shè)備類
          staticstructclass*pwm_class;

          staticint__init pwm_init(void)
          {
          //注冊(cè)為字符設(shè)備,主設(shè)備號(hào)為0讓系統(tǒng)自動(dòng)分配,設(shè)備名為my2440_pwm,注冊(cè)成功返回動(dòng)態(tài)生成的主設(shè)備號(hào)
          device_major=register_chrdev(PWM_MAJOR,PWM_NAME,&pwm_fops);

          if(device_major<0)
          {
          printk(PWM_NAME" register falid!/n");
          returndevice_major;
          }

          //注冊(cè)一個(gè)設(shè)備類,使mdev可以在/dev/目錄下自動(dòng)建立設(shè)備節(jié)點(diǎn)
          pwm_class=class_create(THIS_MODULE,PWM_NAME);

          if(IS_ERR(pwm_class))
          {
          printk(PWM_NAME" register class falid!/n");
          return-1;
          }

          //創(chuàng)建一個(gè)設(shè)備節(jié)點(diǎn),設(shè)備名為PWM_NAME,即:my2440_pwm
          device_create(pwm_class,NULL,MKDEV(device_major,0),NULL,PWM_NAME);

          return0;
          }

          staticvoid__exit pwm_exit(void)
          {
          //注銷設(shè)備
          unregister_chrdev(device_major,PWM_NAME);

          //刪除設(shè)備節(jié)點(diǎn)
          device_destroy(pwm_class,MKDEV(device_major,0));

          //注銷設(shè)備類
          class_destroy(pwm_class);
          }

          module_init(pwm_init);
          module_exit(pwm_exit);

          MODULE_LICENSE("PGL");
          MODULE_AUTHOR("Huang Gang");
          MODULE_DESCRIPTION("my2440 pwm driver");

          4. 將PWM蜂鳴器驅(qū)動(dòng)代碼部署到內(nèi)核中。

          #cp -f my2440_pwm.c /linux-2.6.30.4/drivers/char //把驅(qū)動(dòng)源碼到內(nèi)核驅(qū)動(dòng)的字符設(shè)備下

          #gedit /linux-2.6.30.4/drivers/char/Kconfig //添加PWM蜂鳴器設(shè)備配置

          config MY2440_PWM_BEEP
          tristate"My2440 PWM Beep Device"
          dependsonARCH_S3C2440
          default y
          ---help---
          My2440 PWM Beep

          #gedit /linux-2.6.30.4/drivers/char/Makefile //添加PWM蜂鳴器設(shè)備配置

          obj-$(CONFIG_MY2440_PWM_BEEP) +=my2440_pwm.o


          5.配置內(nèi)核,選擇PWM蜂鳴器設(shè)備選項(xiàng)

          #make menuconfig

          Device Drivers --->
          Character devices --->
          <*> My2440 PWM Beep Device (NEW)


          6. 編譯內(nèi)核并下載到開(kāi)發(fā)板上。這里要注意,現(xiàn)在我們不需要手動(dòng)的在開(kāi)發(fā)板上創(chuàng)建設(shè)備的節(jié)點(diǎn)了,因?yàn)槲覀儸F(xiàn)在使用了mdev進(jìn)行管理了(使用方法請(qǐng)看:設(shè)備文件系統(tǒng)剖析與使用),在驅(qū)動(dòng)程序中也添加了對(duì)類設(shè)備接口的支持。之前講的一些驅(qū)動(dòng)都沒(méi)有,以后我們都使用這種方法?,F(xiàn)在可以查看到/dev目錄下自動(dòng)創(chuàng)建好的my2440_pwm設(shè)備節(jié)點(diǎn),就直接可以使用它了。

          7. 編寫(xiě)PWM蜂鳴器驅(qū)動(dòng)的測(cè)試程序。文件名:pwm_test.c

          /*
          ==============================================
          Name : pwm_test.c
          Author : Huang Gang
          Date : 25/11/2009
          Copyright : GPL
          Description : my2440 pwm driver test
          ==============================================
          */

          #include
          #include
          #include
          #include

          intmain(intargc,char**argv)
          {
          inttmp;
          intfd;
          inti;

          //打開(kāi)蜂鳴器設(shè)備
          fd=open("/dev/my2440_pwm",O_RDWR);

          if(fd<0)
          {
          printf("Open PWM Device Faild!/n");
          exit(1);
          }

          //提示用戶輸入一個(gè)參數(shù)來(lái)對(duì)蜂鳴器進(jìn)行調(diào)頻,0表示停止工作
          printf("please enter the times number(0 is stop):/n");

          while(1)
          {
          //輸入?yún)?shù)
          scanf("%d",&tmp);
          printf("times = %d/n",tmp);

          //IO控制
          ioctl(fd,tmp);

          if(tmp<=0)
          {
          break;
          }
          }

          //關(guān)閉設(shè)備
          close(fd);

          return0;
          }


          8. 在開(kāi)發(fā)主機(jī)上交叉編譯測(cè)試應(yīng)用程序,并到文件系統(tǒng)的/usr/sbin目錄下,然后重新編譯文件系統(tǒng)下載到開(kāi)發(fā)板上。

          #arm-linux-gcc -o pwm_test pwm_test.c


          9. 在開(kāi)發(fā)板上運(yùn)行測(cè)試程序??梢钥吹礁鶕?jù)你輸入?yún)?shù)的大小,蜂鳴器也會(huì)發(fā)生不同頻率的叫聲,輸入0蜂鳴器停止鳴叫。



          關(guān)鍵詞: PWMARMLinux中蜂鳴器驅(qū)

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();