PWM在ARM Linux中的原理和蜂鳴器驅動實例開發

2021-01-08 電子產品世界

1. 什麼是PWM

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

本文引用地址:http://www.eepw.com.cn/article/201611/318018.htm

2. ARM Linux中的PWM

根據S3C2440的手冊介紹,S3C2440A內部有5個16位的定時器,定時器0、1、2、3都帶有脈衝寬度調製功能(PWM),定時器4是一個沒有輸出引腳的內部定時器,定時器0有一個用於大電流設備的死區生成器。看下圖解釋吧!!


由S3C2440的技術手冊和上面這幅結構圖,我們來總結一下2440內部定時器模塊的特性吧:

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

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

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

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

三、蜂鳴器驅動實例

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

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

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

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

有源蜂鳴器和無源蜂鳴器的區別:這個「源」字是不是指電源,而是指震蕩源,即有源蜂鳴器內有振蕩源而無源蜂鳴器內部沒有振蕩源。有振蕩源的通電就可以發聲,沒有振蕩源的需要脈衝信號驅動才能發聲。


額外知識:簡單蜂鳴器的製作方法
1)製備電磁鐵M:在長約6釐米的鐵螺栓上繞100圈導線,線端留下5釐米作引線,用透明膠布把線圈粘好,以免線圈鬆開,再用膠布把它粘在一個盒子上,電磁鐵就做好了;

2)製備彈片P:從鐵罐頭盒上剪下一條寬約2釐米的長鐵片,彎成直角,把電磁鐵的一條引線接在彈片上,再用膠布把彈片緊貼在木板上;

3)用曲別針做觸頭Q,用書把曲別針墊高,用膠布粘牢,引出一條導線,如圖連接好電路;

4)調節M與P之間的距離(通過移動盒子),使電磁鐵能吸引彈片,調節觸點與彈片之間的距離,使它們能恰好接觸,通電後就可以聽到蜂鳴聲。

2. 開發板上蜂鳴器原理圖分析


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

3. 編寫合適開發板的蜂鳴器驅動程序,文件名: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//主設備號
#definePWM_NAME"my2440_pwm"//設備名稱

staticintdevice_major=PWM_MAJOR;//系統動態生成的主設備號

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

return0;
}

//關閉設備
staticintpwm_close(structinode*inode,structfile*file)
{
return0;
}

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

structclk*clk_p;
unsignedlongpclk;

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

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

tcfg1&=~S3C2410_TCFG1_MUX0_MASK;
tcfg1|=S3C2410_TCFG1_MUX0_DIV16;//設置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);//從系統平臺時鐘隊列中獲取pclk的時鐘頻率,在include/linux/clk.h中定義
tcnt=(pclk/50/16)/cmd;//計算定時器0的輸出時鐘頻率(pclk/{prescaler0 + 1}/divider value)

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

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

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

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

return0;
}

//設備操作結構體
staticstructfile_operations pwm_fops=
{
.owner=THIS_MODULE,
.open=pwm_open,
.release=pwm_close,
.ioctl=pwm_ioctl,
};

//定義一個設備類
staticstructclass*pwm_class;

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

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

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

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

//創建一個設備節點,設備名為PWM_NAME,即:my2440_pwm
device_create(pwm_class,NULL,MKDEV(device_major,0),NULL,PWM_NAME);

return0;
}

staticvoid__exit pwm_exit(void)
{
//註銷設備
unregister_chrdev(device_major,PWM_NAME);

//刪除設備節點
device_destroy(pwm_class,MKDEV(device_major,0));

//註銷設備類
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蜂鳴器驅動代碼部署到內核中。

#cp -f my2440_pwm.c /linux-2.6.30.4/drivers/char //把驅動源碼到內核驅動的字符設備下

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

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蜂鳴器設備配置

obj-$(CONFIG_MY2440_PWM_BEEP) +=my2440_pwm.o


5.配置內核,選擇PWM蜂鳴器設備選項

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


6. 編譯內核並下載到開發板上。這裡要注意,現在我們不需要手動的在開發板上創建設備的節點了,因為我們現在使用了mdev進行管理了(使用方法請看:設備文件系統剖析與使用),在驅動程序中也添加了對類設備接口的支持。之前講的一些驅動都沒有,以後我們都使用這種方法。現在可以查看到/dev目錄下自動創建好的my2440_pwm設備節點,就直接可以使用它了。

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

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

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

//提示用戶輸入一個參數來對蜂鳴器進行調頻,0表示停止工作
printf("please enter the times number(0 is stop):/n");

while(1)
{
//輸入參數
scanf("%d",&tmp);
printf("times = %d/n",tmp);

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

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

//關閉設備
close(fd);

return0;
}


8. 在開發主機上交叉編譯測試應用程式,併到文件系統的/usr/sbin目錄下,然後重新編譯文件系統下載到開發板上。

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


9. 在開發板上運行測試程序。可以看到根據你輸入參數的大小,蜂鳴器也會發生不同頻率的叫聲,輸入0蜂鳴器停止鳴叫。


相關焦點

  • 「正點原子FPGA連載」第二十八章Linux蜂鳴器驅動實驗
    蜂鳴器驅動實驗上一章實驗中我們藉助gpio子系統編寫了LED燈驅動,領航者開發板上還有一個蜂鳴器,從軟體的角度考慮,蜂鳴器驅動和LED燈驅動其實是一摸一樣的,都是控制IO輸出高低電平。本章我們就來學習編寫蜂鳴器的Linux驅動,也算是對上一章講解的gpio子系統的鞏固。28.1有源蜂鳴器簡介蜂鳴器常用於計算機、印表機、報警器、電子玩具等電子產品中,常用的蜂鳴器有兩種:有源蜂鳴器和無源蜂鳴器,這裡的有「源」不是電源,而是震蕩源,有源蜂鳴器內部帶有震蕩源,所以有源蜂鳴器只要通電就會叫。無源蜂鳴器內部不帶震蕩源,直接用直流電是驅動不起來的,需要2K-5K的方波去驅動。
  • 嵌入式Linux設備驅動開發之:GPIO驅動程序實例
    在此主要以發光二極體(LED)和蜂鳴器為例,討論GPIO設備的驅動程序。它們的硬體驅動電路的原理圖如圖11.4所示。圖11.4LED(左)和蜂鳴器(右)的驅動電路原理圖在圖11.4中,可知使用S3C2410處理器的通用I/O口GPF4、GPF5、GPF6和GPF7分別直接驅動LEDD12、D11、D10以及D9,而使用GPB0埠驅動蜂鳴器。4個LED分別在對應埠(GPF4~GPF7)為低電平時發亮,而蜂鳴器在GPB0為高電平時發聲。
  • 嵌入式Linux設備驅動開發之:按鍵驅動程序實例
    本文引用地址:http://www.eepw.com.cn/article/257107.htm11.6.1按鍵工作原理LED和蜂鳴器是最簡單的GPIO的應用,都不需要任何外部輸入或控制。
  • 嵌入式Linux之我行——LED驅動在2440上的實例開發
    一、開發環境主機:VMWare--Fedora 9開發板:Mini2440--64MB Nand編譯器:arm-linux-gcc-4.3.2二、實現步驟
  • 單片機驅動蜂鳴器原理與設計
    蜂鳴器是一種一體化結構的電子訊響器,本文介紹如何用單片機驅動蜂鳴器,他廣泛應用於計算機、印表機、複印機、報警器、電話機等電子產品中作發聲器件。   蜂鳴器主要分為壓電式蜂鳴器和電磁式蜂鳴器兩種類型。
  • ARM-Linux開發與MCU開發的區別
    開發arm應用程式有兩種方法:一種是直接在arm晶片上開發應用程式,而不使用作業系統,也稱為裸機編程。這種開發方法主要應用於一些低端的arm晶片,其開發過程與單片機的開發過程非常相似,本文不作介紹。另一種是在ARM晶片上運行作業系統。對於硬體的操作,需要編寫相應的驅動程序。
  • 周立功:深入理解AMetal——蜂鳴器接口和溫度採集接口
    周立功教授新書《面向AMetal框架與接口的編程(上)》,對AMetal框架進行了詳細介紹,通過閱讀這本書,你可以學到高度復用的軟體設計原則和面向接口編程的開發思想,聚焦自己的「核心域」,改變自己的編程思維,實現企業和個人的共同進步。
  • 蜂鳴器驅動電路設計原理圖講解
    以下介紹的幾種蜂鳴器驅動電路是針對單片機I/O口的驅動電路,適用於現行的壓電式蜂鳴器。
  • arm驅動Linux內核開發之阻塞非阻塞IO輪詢操作
    《[arm驅動]Linux內核開發之阻塞非阻塞IO----輪詢操作》涉及內核驅動函數二個,內核結構體零個,分析了內核驅動函數二個;可參考的相關應用程式模板或內核驅動模板二個,可參考的相關應用程式模板或內核驅動一個一、概念:Poll是非阻塞IO----
  • 如何設計低成本蜂鳴器
    在實際的應用中,雖然有源蜂鳴器控制簡單,缺陷是成本比較高,在潮溼的環境用久了,容易損壞。而無源蜂鳴器彌補了有源蜂鳴器缺點,但問題是無源蜂鳴器需要PWM驅動。
  • 蜂鳴器驅動電路圖解_有源蜂鳴器原理_有源蜂鳴器和無源蜂鳴器如何...
    打開APP 蜂鳴器驅動電路圖解_有源蜂鳴器原理_有源蜂鳴器和無源蜂鳴器如何區分 發表於 2017-08-25 09:12:49
  • 蜂鳴器是什麼_蜂鳴器報警工作原理
    消耗電流: 電磁式的依電壓的不同,從幾十到上百毫安培都有,壓電式的就省電的多,幾毫安培就可以正常的動作, 且在蜂鳴器啟動時,瞬間需消耗約三倍的電流,驅動方式: 二種蜂鳴器都有自激式的,只要接上直流電(DC)即可發聲,因為已內建了驅動線路在蜂鳴器中了,因為動作原理的不同,電磁式蜂鳴器要用1/2方波來驅動,壓電的用方波,才能有較好的聲音輸出。
  • 蜂鳴器原理
    導讀:本文主要介紹的是蜂鳴器的原理,感興趣的盆友們快來學習一下吧~~~很漲姿勢的哦~~~本文引用地址:http://www.eepw.com.cn/article/277228.htm1.蜂鳴器原理--簡介  蜂鳴器其實就是一種一體化結構的電子訊響器
  • 利用PWM原理,實現呼吸燈功能
    除了在調光電路應用,還有在直流斬波電路、蜂鳴器驅動、電機驅動、逆變電路、加溼機霧化量等都會有應用。PWM信號如何輸出呢?1)可以直接通過晶片內部模塊輸出PWM信號,前提是這個I/O口要有PWM集成模塊,自帶PWM功能的晶片只需要簡單幾步操作即可實現PWM功能。
  • ARM和Linux交叉開發環境的搭建過程
    摘要:交叉開發環境是嵌入式Linux開發的基礎.後續的開發過程幾乎都是基於此環境的。而ARM作為一種高性能、低成本的嵌入式RISC微處理器。已成為應用最廣泛的嵌入式處理器。本文內容包括基於32位ARM920T核「GEC2410」開發板的硬體結構和嵌入式Linux交叉開發環境的概念和配置.開發工具的使用以及交叉調試器製作的方法。
  • 淺析gcc、arm-linux-gcc和arm-elf-gcc的關係
    Binutils:它是一組開發工具,包括連接器,彙編器和其他用於目標文件和檔案的工具。關於 Binutils 的介紹可以參考 Binutils 簡單介紹。這個軟體包依賴於不同的目標機的平臺。因為不同目標機的指令集是不一樣的,比如 arm 跟 x86 就不一樣。
  • 如何在Linux系統中手動安裝arm-linux-gcc交叉編譯工具
    嵌入式開發少不了arm開發平臺。要編譯出能在arm平臺上運行的程序,必須使用交叉編譯工具arm-linux-gcc、arm-linux-ld、arm-linux-objcopy、arm-linux-objdump等。arm-linux-gcc是幹什麼的?gcc是linux系統下面用來將代碼編譯成一個可執行程序的手段。
  • 「正點原子FPGA連載」第二十二章Linux LED驅動開發
    1)摘自【正點原子】領航者 ZYNQ 之linux驅動開發指南2)實驗平臺:正點原子領航者ZYNQ開發板3)平臺購買地址:https://item.taobao.com/item.htm?上一章我們詳細的講解了字符設備驅動開發步驟,並且用一個虛擬的chrdevbase設備為例帶領大家完成了第一個字符設備驅動的開發。
  • 用單只微控制器引腳的大電壓驅動壓電蜂鳴器
    往期的一篇設計實例,描述了如何用一隻微控制器以大交流電壓驅動一個壓電蜂鳴器,它使用了一個四MOSFET的電路,與微控制器的兩個I/O引腳連接(參考文獻1)。本文是這個電路的修改擴充,能節省下一隻微控制器的I/O引腳。
  • arm linux 系統調用實現
    ).我們將從bionic中的open函數開始追溯arm linux的系統調用實現(使用gnu eabi)。在arm中,這個過程是通過swi(或者和它等價的指令)來實現模式轉換的。本文引用地址:http://www.eepw.com.cn/article/201611/318015.htm從bionic libc中的open函數追溯系統調用實現相關文件:bionic/libc/unistd/open.cbionic/libc/arch-arm/syscalls/__open.Slinux/arch/arm/kernel/