脉宽调制器

本文详细介绍了如何利用Exynos_4412平台的PWM功能,通过配置预分频和固定分频来驱动蜂鸣器以500Hz的频率发出50%占空比的方波,同时演示了如何模拟音律并实现中断和看门狗管理。
摘要由CSDN通过智能技术生成

1.  pwm脉宽调制器

脉宽调制器:   一种硬件设备, 用于 动态调制  方波 的 一些属性, 方波的周期,频率,占空比 

占空比? :     有效电平占 整个周期的比值  

可以使用PWM 控制功率, 控制频率 用于 开关电源 或 逆变器 

1.1 原理

PWM原理: 如图所示

本质就是一个定时器:  

由原理可知: 

输出波形的 频率 = 总线时钟 / (分频值+1) / 重载值 ;

输出波形的 占空比 = 比较值 / 重载值 

1.2 pwm标准时钟的频率

100Mhz

2. 实验:使用pwm驱动蜂鸣器 以500hz 占空比50% 发出声响

输出定时器信号的 频率 =  总线时钟 /固定分频/ (分频值+1) / 重载值 ;

占空比 = 比较寄存器/重载值

实现功能  输出一个 500hz 方波  占空比  50%

500hz  = 100M / (分频值+1) / 重载值 ;   //这里不固定分频

500hz  = 100M / (99+1) / 重载值 ;

500hz  = 1M / 重载值 ;

重载值 = 2K

0.5    = 比较值 / 重载值 ;

比较直 = 1K

2.1 看原理图

1292页

我们走红色线路

1. 硬件 : 蜂鸣器 

2. 电路图    

芯片管脚  PD0_0  ----  XpwmTOUT0  PWM输出

3. pwm控制器   芯片手册  

5个 pwm  

0-3  有 PWM 输出 

0 pwm 有 死区控制 

4 pwm 没有输出 

死区控制:  主要用于控制 半H桥电路  或 全H桥电路 有用 

控制器 结构框图   1292 页  

2.2 配置寄存器

TCFG0  两路预分频

TCFG0 :  两路预分频  死区配置 

[7:0]  = 预分频 

TCFG1 5路固定分频

TCFG1 :  5路 固定分频 配置 

[3:0]  =  0-4   分别对应 1/1 1/2 1/4 1/8 1/16

TCNTB0:  PWM0 重载寄存器     32bit  0 - 2^32-1

TCMPB0:  PWM0 比较寄存器 

TCNTO0:  PWM0 计数寄存器  只读

TCON  :  总控 

TCON  :  总控 

[4] = 0  不使能死区 

[3] = 0  单次模式   1 自动重装 

[2] = 1  打开输出  

[1] = 1  装载   重载寄存器   比较寄存器

[0] = 1  启动pwm0 

2.3 写代码

pwm_test----main.c

#include"exynos_4412.h"
#include"uart.h"
//使用pwm驱动蜂鸣器 以500hz 占空比50% 发出声响
//pwm 初始化
void pwm_init(){

    //配置GPD0_0 为pwm功能
    GPD0.CON = (GPD0.CON & ~(0xf<<0)) | (2<<0);

    //配置pwm控制器,五路固定分频 TCFG1 [3:0] = 0  这里蛇蛇不固定分频
    PWM.TCFG1 &= ~(0xf);
    //两路预分频 TCFG0 [7:0] = 99  100M/(99+1) = 1M
    PWM.TCFG0 = (PWM.TCFG0 & ~(0xff<<0)) | (99<<0);
    //重载值
    PWM.TCNTB0 = 2000;
    //比较寄存器
    PWM.TCMPB0 = 1000;

    //配置总控
    //不使能死区
    PWM.TCON &= ~(1<<4);
    //自动重装
    PWM.TCON |= 1<<3;
    //打开输出
    PWM.TCON |= 1<<2;
    //装载TCNTB0  TCMPB0
    PWM.TCON |= 1<<1;
    //关闭装载
    PWM.TCON &= ~(1<<1);
    //启动pwm
    PWM.TCON |= 1;


}

int main()
{
    int a = 100;
    uart_init();
    printf("hello!a=%d\r\n",a);

    pwm_init();

    while(1);
    return 0;
}


3. 使用蜂鸣器调出音律

这里我们调制 高音即可

输出定时器信号的 频率 =  总线时钟 /固定分频/ (分频值+1) / 重载值 ;

占空比 = 比较寄存器/重载值

pwm_muisc-----main.c

#include"exynos_4412.h"
#include"uart.h"

//pwm 模拟音律播放

volatile unsigned int count = 0;//毫秒级变量

//延时  ms
void delay(unsigned short ms){

    unsigned int tmp = count;//存放刚进入delay函数时 count 的数值

    // while(count <= tmp+ms);//这种算法没有规避溢出问题

    while(count-tmp < ms);//这种算法规避了溢出问题,不必纠结算法,用就完事了

}


//中断初始化
exit_init(){

    //GIC 面向中断源
    //开启总中断
    ICDDCR = 1;

    //配置端口中断使能
    //中断模式:  wdt中断 id 75
    //75/32=2   75%32=11
    ICDISER.ICDISER2 |= 1<<11;

    //配置端口优先级 优先级设置为5
    //75/4= 18    75%4=3  ----  [15:8]
    ICDIPR.ICDIPR18 = (ICDIPR.ICDIPR18 & ~(0xff<<24)) | (5<<24);

    //配置中断源送去哪个cpu处理 0x1表示直送cpu0
    //寄存器分步格局 与ICDIPR 完全一样 
    ICDIPTR.ICDIPTR18 = (ICDIPTR.ICDIPTR18 & ~(0xff<<24)) | (0x1<<24);
    
    //GIC 面向cpu
    //cpu响应中断使能  =1 使能  =0 不使能
    CPU0.ICCICR = 1;

    //配置cpu过滤优先级
    CPU0.ICCPMR = 255;

}

//中断响应,c语言入口函数,在汇编汇总调用,当irq异常触发时
void do_irq(){
    //获取中断号
    int id = CPU0.ICCIAR;

    //根据中断id来处理对应的事件
    switch(id){
        case 75:

        count++;

        //先清除中断 源头的挂起 看门狗的中断
        //写入任何值清除
        WDT.WTCLRINT = 8;

        //在清除GIC分配器层中断挂起 与ICDISER_CPU 结构一样 id:57
        //置为1  清除
        ICDICPR.ICDICPR2 |= 1<<11;

        break;

    }

    //最后清除cpu中断挂起
    //写入中断id清除对应中断挂起
    CPU0.ICCEOIR = id;

}

//看门狗初始化
void dog_init(){
    //预分频
    WDT.WTCON = (WDT.WTCON &~(0xff<<8)) | (24<<8);
    //固定分频
    WDT.WTCON = (WDT.WTCON &~(0x3<<3)) | (0<<3);
    //触发中断信号  [2] 时间到,是否触发中断信号  = 1 触发中断 
    WDT.WTCON |= 1<<2;

    //重载寄存器
    WDT.WTDAT = 250;
    //计数寄存器
    WDT.WTCNT =250;

    //开启看门狗
    WDT.WTCON |= 1<<5;
}

//pwm 初始化
void pwm_init(){

    //配置GPD0_0 为pwm功能
    GPD0.CON = (GPD0.CON & ~(0xf<<0)) | (2<<0);

    //配置pwm控制器,五路固定分频 TCFG1 [3:0] = 0  这里设不固定分频
    PWM.TCFG1 &= ~(0xf);

    //频率 =  总线时钟 /固定分频/ (分频值+1) / 重载值 ;
    //两路预分频 TCFG0 [7:0] = 99  100M/(99+1) = 1M
    PWM.TCFG0 = (PWM.TCFG0 & ~(0xff<<0)) | (99<<0);

    //重载值
    PWM.TCNTB0 = 2000;
    //比较寄存器  占空比 = 比较寄存器/重载值
    PWM.TCMPB0 = 1000;

    //配置总控
    //不使能死区
    PWM.TCON &= ~(1<<4);
    //自动重装
    PWM.TCON |= 1<<3;
    //打开输出
    PWM.TCON |= 1<<2;
    //装载TCNTB0  TCMPB0
    PWM.TCON |= 1<<1;
    //关闭装载
    PWM.TCON &= ~(1<<1);

}

//启动pwm
void pwm_start(){
    //启动pwm
    PWM.TCON |= 1;
}

//关闭pwm
void pwm_stop(){
    //启动pwm
    PWM.TCON &= ~1;
}

//改变音色
void chanage_pinlv(unsigned int hz){

    //重载值
    PWM.TCNTB0 = 1000000/hz;
    //比较寄存器 //占空比我们设为50%
    PWM.TCMPB0 = 1000000/hz/2;

    //装载TCNTB0  TCMPB0
    PWM.TCON |= 1<<1;
    //关闭装载
    PWM.TCON &= ~(1<<1);
    //打开pwm
    pwm_start(); //因为我们在播放音律函数时 停止了pwm 所以每次改变音色 都要重新开启pwm
}

//定义音符频率
#define H1  1046
#define H2  1175
#define H3  1318
#define H4  1397
#define H5  1568
#define H6  1760
#define H7  1976
#define ST  0

//播放音律
void play(){
    
    chanage_pinlv(H1);
    delay(1000);//响一秒
    pwm_stop();
    delay(500);//停一秒
    chanage_pinlv(H2);
    delay(1000);//响一秒
    pwm_stop();
    delay(500);//停一秒
    chanage_pinlv(H3);
    delay(1000);//响一秒
    pwm_stop();
    delay(500);//停一秒
    chanage_pinlv(H4);
    delay(1000);//响一秒
    pwm_stop();
    delay(500);//停一秒
    chanage_pinlv(H5);
    delay(1000);//响一秒
    pwm_stop();
    delay(500);//停一秒
    chanage_pinlv(H6);
    delay(1000);//响一秒
    pwm_stop();
    delay(500);//停一秒
    chanage_pinlv(H7);
    delay(1000);//响一秒
    pwm_stop();
    delay(500);//停一秒
}

int main()
{
    uart_init();
    printf("music!!!\r\n");
    //看门狗初始化
    dog_init();
    //中断初始化
    exit_init();
    //pwm初始化
    pwm_init();
    //开启pwm
    pwm_start();

    int i=0;

    while(1){
        play();
        delay(2000);//所有音律播放完成总体停2秒
    }

    return 0;
}

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值