天天看點

PWM控制蜂鳴器實驗(附源代碼)

通過PWM控制蜂鳴器,點選鍵盤的“+”号提高蜂鳴器頻率,點選“-”号則降低頻率

一、實驗目的

1 了解ARM 處理器PWM接口的處理機制

2 掌握在S3C2440A 平台下進行PWM 接口應用程式設計

二、實驗裝置

1 硬體:SinoSys-EA2440a 實驗平台,PC 機

2 軟體:ADS1.2 開發工具,DNW 工具

三、實驗任務

實作功能:

1 點選鍵盤的“+”号提高蜂鳴器頻率,點選“-”号則降低頻率。

2 通過ADS1.2 建立工程,編譯。程式通過ICE 仿真器調試。調試完成後通過DNW 直接下載下傳到實驗闆上運作。

實驗原理:

3.1概述

脈沖寬度調制(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調制,其廣泛應用在從測量、通信到功率控制與變換的許多領域中,是利用微處理器的數字輸出來對模拟電路進行控制的一種非常有效的技術。脈沖寬度調制是一種模拟控制方式,從實體意義上說,其根據相應載荷的變化來調制半導體栅極或基極的偏置,來實作開關穩壓電源輸出半導體或半導體導通時間的改變,從實際使用上說,其通過高分辨率計數器,将方波的占空比來編碼一個具體的模拟信号。這種方式能使電源的輸出電壓在工作條件變化時保持恒定,是利用微處理器的數字輸出來對模拟電路進行控制的一種非常有效的技術。PWM 控制技術以其控制簡單,靈活和動态響應好的優點而成為電力電子技術最廣泛應用的控制方式,也是人們研究的熱點。由于當今科學技術的發展已經沒有了學科之間的界限,結合現代控制理論思想或實作無諧振軟開關技術将會成為PWM 控制技術發展的主要方向之一。

3.2 S3C2440 的PWM

由于PWM 的實際應用和相關寄存器非常之多,是以本文僅僅介紹和使用本系統所使用的相關概念和使用方法。PWM 控制器主要有4 個特征:1、由5 個16 位定時器、2 個8 位預分頻器以及2 個4 位分割器組成;2、擁有自動重載模式或者單擊脈沖模式;3、可程式設計控制輸出波形;4、死區發生器。其中除了定時器4 以外,其餘三個均具有脈寬調制(PWM)功能,定時器4 僅僅是一個内部定時器,沒有輸出引腳。開發闆定時器結構框圖如下:

PWM控制蜂鳴器實驗(附源代碼)

3.3 PWM 相關寄存器介紹

PWM 的寄存器共有17 個,相應的寄存器分為5 組,分别為配置和模式選擇寄存器(TCFG0~TCFG1),定時器計數緩存寄存器(TCNTB0~ TCNTB4),定時器比較緩存寄存器(TCMPB0~ TCMPB3),定時器控制寄存器(TCON),定時器計數觀測寄存器(TCNTO0~TCNTO4)。

由于PWM 寄存器相對較多,不需要全部使用,隻需要使用系統需要的即可。本系統中最為重要的是TCNTB0 和TCMPB0,TCNTB0 決定着PWM 的脈沖頻率,而PWM 的寬度則由TCMPB0 決定。一般來說,如果要得到一個較高的PWM 的輸出值,就需要增加TCMPB0的值,如果說輸出反轉器被時能,那麼增加和減少的結果也是反轉的。基于雙緩沖器的特性,下一個PWM 周期的TCMPB0 的值可以通過中斷或者其他手段在目前PWM 周期中任何一點寫入。

3.4設定占空比和輸出頻率

報警器采用TOUT0 作為其脈沖輸入信号,通過修改TCFG0 和TCFG1 設定預分頻值和計時器分割器的選擇(可查詢表3.2),占空比(rate)由TCNTB0 和TCMPB0 決定

其值的計算公式如下:

div=PCLK/{pre value+1}/{div value}/freq

{pre value+1}=0~255 由TCFG0 決定

{div value}=2,4,6,8,16,32 由TCFG1 決定

rate={cmp value}/{tcn value}

最終的value 由div 和rate 生成,即

value=div*rate //rate<1;

實驗流程圖(簡化)分析如下,設定TCNTB0 為180(70+110),設定TCMPB0 為110,設定人工加載位、配置極性轉換位。同時設定下一次TCNTB0 為80(40+40),設定TCMPB0為40 作為下一次定時的參數。定時器延遲一定時間後定時器下降計數器開始計數,當TCNTB0 和TCMPB0 數值一緻時,TOUT0 的邏輯将由低變高。當TCNTB0 計數為0 時,定時器中斷打開,同時将寄存器資料更新,進而繼續上一次操作。進而形成了下圖的波形圖,此時報警器會根據所設定的頻率發出不同大小的聲音,已基本實作所要功能。

PWM控制蜂鳴器實驗(附源代碼)

3.5 蜂鳴器接口電路

系統的報警器電路就是由平台将S3C2440 的定時器0 的脈沖輸出端口(TOUT0)GPB0與報警器的脈沖輸入端口相連。在系統初始化時,就要進行I/O 端口初始化,設定端口控制寄存器(将再下面講到),将GPB0 設定為工作方式1,并設定為輸出狀态。控制電路如圖所示,

PWM控制蜂鳴器實驗(附源代碼)

3.6 源代碼分析

首先是main_beep.c程式

#define    GLOBAL_CLK        1
#include <stdlib.h>
#include <string.h>

#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
void Main(void)
{        
    int i;
    U8 key;
    U32 mpll_val = 0 ;

    Port_Init();  //端口初始化
    Isr_Init();   //中斷初始化
    
    i = 2 ;    //設定系統時鐘 400M
    switch ( i ) {
    case 0:    //200
        key = 12;
        mpll_val = (92<<12)|(4<<4)|(1);
        break;
    case 1:    //300
        key = 13;
        mpll_val = (67<<12)|(1<<4)|(1);
        break;
    case 2:    //400
        key = 14;
        mpll_val = (92<<12)|(1<<4)|(1);
        break;
    case 3:    //440!!!
        key = 14;
        mpll_val = (102<<12)|(1<<4)|(1);
        break;
    default:
        key = 14;
        mpll_val = (92<<12)|(1<<4)|(1);
        break;
    }
    
    //init FCLK=400M, so change MPLL first
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
    ChangeClockDivider(key, 12);    //設定分頻 1:4:8,即HCLK=100M  PCLK=50M
    cal_cpu_bus_clk();     //計算總線頻率

    Uart_Init(0,115200);  //序列槽初始化 波特率為115200
    Uart_Select(0);  //選者序列槽0

    Clk0_Disable();
    Clk1_Disable();

i=0;
Uart_Printf("\nBegin to start BEEP test,OK? (Y/N)\n");

get_key:    key = Uart_Getch();
    
    if(key==\'y\'||key==\'Y\')
    {
        beep_test();
    }
    else if(key==\'n\'||key==\'N\')
    {
        Uart_Printf("\nOh! You quit the test!\n");
    }
    else goto get_key;
}
      

接下來是beep.c程式

#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
/* freq 為頻率    */
void Beep( U32 freq )
{
rGPBCON&=~0x3;
rGPBCON|=0X2; //設定B口為TOUT0模式

rTCFG0&=~0XFF;
rTCFG0|=0XF;  //預分頻15+1 PCLK
rTCFG1&=~0XF;
rTCFG1|=0X3;  //再16分頻 計數頻率等于PCLK/256
//因為定時器的選擇PCLK作為源時鐘頻率,但是定時器不可能工作在這麼高的頻率下,是以我們要通過二次分頻來降低定時器的工作頻率,上面這四句就是起設定分頻值的作用。

rTCNTB0=(PCLK>>8)/freq;; //右移8位即除以256。若freq=1,則定時周期正好為1s 
rTCMPB0=rTCNTB0>>1;  //定時器0比較緩沖器的值,PWM輸出占空比50%
rTCON&=~0X1F;
rTCON|=0XB;   //自動重載,關閉變相,手動更新,開啟定時器0 
rTCON&=~2;      //清除手動更新位  
}

void beep_test(void)
{
    U8 key;
    U16 freq=200;
    rGPBCON|=0xffffff&0x01;  //set GPB0 as output
   
   while(1)
   {
       key=Uart_Getch();
          if(key==\'+\')
            {  if ( freq < 20000 )
                 {   freq += 100 ;
                    Uart_Printf( "Press +to increase/reduce the frequency of beep !\n" ) ;
}
            }
           else    if( key == \'-\' )
                  {   if( freq > 100 )
                        {    freq -= 100 ;    
                            Uart_Printf( "Press - to increase/reduce the frequency of beep !\n" ) ;
}
                  }
      Beep(freq) ;
   }
}      

2013-04-02  17:03:30