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

          新聞中心

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

          PWM在ARM Linux中的原理和蜂鳴器驅(qū)動實例開發(fā)

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

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

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

          2. ARM Linux中的PWM

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


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

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

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

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

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

          三、蜂鳴器驅(qū)動實例

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

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

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

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

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

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

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

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

          3. 編寫合適開發(fā)板的蜂鳴器驅(qū)動程序,文件名: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è)備號
          #definePWM_NAME"my2440_pwm"http://設(shè)備名稱

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

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

          return0;
          }

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

          //對設(shè)備進行控制
          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,就讓蜂鳴器開始工作,不同的參數(shù),蜂鳴器的頻率也不一樣
          {
          //定義一些局部變量
          unsignedlongtcon;
          unsignedlongtcnt;
          unsignedlongtcfg1;
          unsignedlongtcfg0;

          structclk*clk_p;
          unsignedlongpclk;

          //以下對各寄存器的操作結(jié)合上面講的開始一個PWM定時器的步驟和2440手冊PWM寄存器操作部分來看就比較容易理解
          tcfg1=__raw_readl(S3C2410_TCFG1);//讀取定時器配置寄存器1的值
          tcfg0=__raw_readl(S3C2410_TCFG0);//讀取定時器配置寄存器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寫入定時器配置寄存器1中
          __raw_writel(tcfg0,S3C2410_TCFG0);//將值tcfg0寫入定時器配置寄存器0中

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

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

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

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

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

          return0;
          }

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

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

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

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

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

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

          //創(chuàng)建一個設(shè)備節(jié)點,設(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é)點
          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ū)動代碼部署到內(nèi)核中。

          #cp -f my2440_pwm.c /linux-2.6.30.4/drivers/char //把驅(qū)動源碼到內(nèi)核驅(qū)動的字符設(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è)備選項

          #make menuconfig

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


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

          7. 編寫PWM蜂鳴器驅(qū)動的測試程序。文件名: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;

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

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

          //提示用戶輸入一個參數(shù)來對蜂鳴器進行調(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. 在開發(fā)主機上交叉編譯測試應(yīng)用程序,并到文件系統(tǒng)的/usr/sbin目錄下,然后重新編譯文件系統(tǒng)下載到開發(fā)板上。

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


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



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

          評論


          技術(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); })();