ARM接口技术——PWM

PWM简介

PWM(Pulse Width Modulation)即脉冲宽度调制,通过对脉冲的宽度进行调制,来获得所需要的波形。

以有源蜂鸣器的控制为例,GPIO加延时可以实现控制,这实际上就是使用GPIO模拟了PWM,但是在延迟中消耗了大量的CPU资源。

使用一个PWM控制器(定时器实现)可以节约CPU资源。

PWM的参数:

  • 周期
  • 占空比

PWM无源蜂鸣器实验

实验设计和分析

蜂鸣器电路原理图:

无源蜂鸣器BUZZER正极连到了电源,负极连接到一个三极管,我们只需要给三极管输入一个高电平就可以导通蜂鸣器;

三极管的输入端所连接的引脚是GPD0_0,我们需要控制该引脚输出高低变化的电平。

Exynos4412核心板GPD0_0原理图:

GPD0_0可以设置为pwm工作模式,用到的是pwmTOUT0。

芯片手册说明:

它使用了一个时钟源,经过两次分频后再传到PWM定时器,分频原理图:

PWM0和PWM1共用一个一级分频器,PWM2 3 4共用一个一级分频器;

而二级分频器只有一个,PWM0-4共用。

 


 

PWM Timer执行过程:

 1). 首先需要配置两个寄存器TCNTB和TCMPB的值,它举例是159和109,分别为周期和占空比;

 2). 启动定时器;

 3). TCNTB会加载到递减计数器,TOUT会输出低电平;

 4). 当递减计数器为TCMPB的值时,TOUT会输出高电平,也就是每次递减实际上会对比递减计数器和             TCMPB的值;

 5). 当递减计数器减到0时,它会产生中断的请求,不使用它的中断功能,不管;

 6). 与此同时递减计数器会重新把TCNTB的值载入(这个需要配置,后面会提到如何配置),意味着会从第二步循环。

需要注意的是以上的描述没有使用到时钟源,时钟源经过分频之后主要是自减计数器使用,它控制了自减的速率,刚才配置的周期再结合自减的速率,共同决定了高低电平变化的快慢。

以实验为例,100MHz经过两次分频后变成1MHz,即自减的频率就是1MHz;周期设置为1000。那么高低电平变化的频率就是1MHz/1000 = 1000Hz。


 

此外它还提供反向输出的功能,即把原来输出低电平的时间输出高电平,原来输出高电平的输出低电平。


 

PWM相关寄存器设置:

我们使用的是PWM0,所以主要设置以下寄存器:


 

 1). TCFG0:

PWM0和PWM1的一级分频设置共用TCFG0寄存器,PWM0需要设置低8位,所以TCFG0[7:0] = 。


 

 2). TCFG1:

 TCFG1是PWM01234共用的,PWM0需设置低4位:TCFG1[3:0] = 。


 

 3). TCON:

设置PWM0只需要看低5位:

[4]:死区设置,用于高电压控制,这里用不到,不管;

[3]:自动重装载,前面提到一次电平变化,自减计数器会减到0,如果要进行下一个周期的高低电平变化,需要自减计数器需要重装载;

[2]:反向功能,前面提到就是高低电平做了一个反转,这里不用反转;

[1]:更新TCNTB和TCMPB的值,前面提到[3]写1它会自动重装载,但是在第一个周期的时候需要写1手动装载;

[0]:启动PWM。


 

 4). TCNTB和TCMPB:

 TCNTB和TCMPB分别设置PWM的周期和高电平占空比,需要注意的是TCNTB必须比TCMPB要大。


 5). TCNTO0

 这个寄存器就是自减计数器当前的值,这个值只能读。


 

GPD0CON:

除了PWM配置的寄存器之外,还需要把GPD0_0引脚配置成PWM功能。

GPD0CON[3:0] = 0x2。


PWM实验编程

#include "exynos_4412.h"

void PWM0_Init()
{
    /* GPD0_0设为PWM输出功能 */
    GPD0.CON = GPD0.CON & (~0xF) | 0x2;

    /* 一级分频设为100倍 */
    PWM.TCFG0 = PWM.TCFG0 & (~0xFF) | 99;

    /* 二级分频设为1倍 */
    PWM.TCFG1 = PWM.TCFG1 & (~0xF);

    /* 设置PWM0自减计数器 自动重装载 */
    PWM.TCON = PWM.TCON | (1<<3);

    /* 设置PWM0周期1000Hz, 1MHz / 1000Hz = 1000 */
    PWM.TCNTB0 = 1000;
    /* 设置PWM0占空比 */
    PWM.TCMPB0 = 600;

    /* 手动装载一次周期 */
    PWM.TCON |= (1<<1);
    /* 手动关闭更新,因为后续用到自动重装载*/
    /* 如果不关闭它可能会一直手动装载,没法自减 */
    PWM.TCON &= (~(1<<1));
}

void PWM0_start()
{
    /* PWM0开始工作 */
    PWM.TCON |= 1;
}

void PWM0_stop()
{
    /* PWM0停止工作 */
    PWM.TCON &= (~1);
}

void delay(int i)
{
    while(i--);
}
int main()
{
    PWM0_Init();
    while(1)
    {
        PWM0_start();
        delay(1000000);
        PWM0_stop();
        delay(1000000);
    }
    return 0;
}

实验现象

蜂鸣器发出滴滴的声音。


 

END

posted @ 2022-04-28 19:22  zj城城城城  阅读(994)  评论(0编辑  收藏  举报