PWM控制蜂鸣器实验(附源代码)

时间:2024-02-19 22:52:49

一、实验目的

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 仅仅是一个内部定时器,没有输出引脚。开发板定时器结构框图如下:

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 时,定时器中断打开,同时将寄存器数据更新,从而继续上一次操作。从而形成了下图的波形图,此时报警器会根据所设置的频率发出不同大小的声音,已基本实现所要功能。

3.5 蜂鸣器接口电路

系统的报警器电路就是由平台将S3C2440 的定时器0 的脉冲输出端口(TOUT0)GPB0与报警器的脉冲输入端口相连。在系统初始化时,就要进行I/O 端口初始化,设置端口控制寄存器(将再下面讲到),将GPB0 设置为工作方式1,并设置为输出状态。控制电路如图所示,

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