一、什么是 PWM

PWM,英文名 Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是 50%.

 

 

二、PWM 信号输出输出和作用

1. 如果要实现 PWM 信号输出如何输出呢?

1)可以直接通过芯片内部模块输出 PWM 信号,前提是这个 I/O 口要有集成的 pwm 控制器,只需要通过对应的寄存器即可,这种自带有 PWM 输出的功能模块在程序设计更简便,同时数据更精确。

 

2)但是如果 IC 内部没有 PWM 功能模块,或者要求不是很高的话可以利用 I/O 口设置一些参数来输出 PWM 信号,因为 PWM 信号其实就是一高一低的一系列电平组合在一起。具体方法是给 I/O 加一个定时器,对于你要求输出的 PWM 信号频率与你的定时器一致,用定时器中断来计数,但是这种方法一般不采用,除非对于精度、频率等要求不是很高可以这样实现。

 

2. PWM 信号应用

PWM 信号把模拟信号转化为数字电路所需要的编码,现在基本是采用数字电路,因此在很多场合都采用 PWM 信号。

 

我们经常见到的就是交流调光电路,也可以说是无级调速,高电平占多一点,也就是占空比大一点亮度就亮一点,占空比小一点亮度就没有那么亮,前提是 PWM 的频率要大于我们人眼识别频率,要不然会出现闪烁现象。

 

除了在调光电路应用,还有在直流斩波电路、蜂鸣器驱动、电机驱动、逆变电路、加湿机雾化量等都会有应用。

 

三、蜂鸣器

蜂鸣器广泛用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。

 

 

蜂鸣器分为压电式及电磁式的二大类:

压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。它是以压电陶瓷的压电效应,来带动金属片的振动而发声;

电磁式的蜂鸣器,由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。通电时将金属振动膜吸下,不通电时依振动膜的弹力弹回。

 

有源蜂鸣器, 只要给它加上恒定的电压, 就能发声;无源蜂鸣器, 必须给它加上一定频率的方波或正弦波才能发声

有源蜂鸣器内部带震荡源,所以一通电就会叫。而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。

 

有源蜂鸣器往往比无源的贵,就是因为里面多个震荡电路。

 

【优点】无源蜂鸣器的优点是:

便宜声音频率可控,可以做出“多来米发索拉西”的效果。在一些特例中,可以和 LED 复用一个控制口有源蜂鸣器的优点是:程序控制方便 。

 

应用:电风扇、收音机的声音按钮、任何模拟值都可以使用 PWM 进行编码

 

四、fs4412 电路图

本例采用 fs4412 开发板,pwm 外接了一个蜂鸣器 BUZZER,电路图如下:

 

 

从上面电路图可知:

该 BUZZER 是无源蜂鸣器,如果要想发出声音,需要正负极产生电流变化,我们通过生成方波,从而实现图中三极管 1->2 周期性导通和关闭来让 BUZZER 俩边电压产生变化,从而实现电流变化;三极管的基极连接的是 SOC 的 GPD0_0 引脚;产生方波我们借助的是 PWM,标号为 MOTOR_PWM。

 

继续查找 MOTOR_PWM:

 

 

由上图可知,MOTOR_PWM 连接的是 PWM 的 XpwmTOUT0,和 LCD 一起复用引脚 GPD0_0,

去 datasheet 继续查看 GPD0_0 说明,

 

 

由上图可知,GPD0_0 配置由寄存器的 GPD0CON[3:0]位控制,要想作为 PWM 输出,要设置为 TOUT_0 即 0x2。

 

同时也可以看到,该引脚还可以设置为外部中断信号[EXT_INT6]功能即 0xF。

 

五、Exynos 4412 PWM 概述

Exynos 4412 SCP 有五个 32 位脉冲宽度调制(PWM)定时器。这些定时器产生内部中断对于 ARM 子系统。此外,定时器 0、1、2 和 3 包括驱动外部 I/O 的 PWM 功能信号。定时器 0 中的 PWM 有一个可选的死区发生器功能,以支持大量的设备。定时器 4 是一个没有输出引脚的内部定时器。

 

定时器使用 APB-PCLK 作为源时钟。定时器 0 和 1 共享可编程 8 位预分频器为 PCLK 提供第一级分频。定时器 2、3 和 4 共享不同的 8 位预分频器。每个计时器都有它自己的专用时钟分频器,提供第二级时钟划分频(预分频器除以 2、4、8 或 16)。

 

每个定时器都有它的 32 位递减计数器;定时器时钟驱动这个计数器。定时器计数缓冲寄存器(TCNTBn)加载递减计数器的初始值。如果递减计数器达到零,它将生成计时器中断请求,通知 CPU 定时器操作完成。如果定时器下降计数器达到零,相应 TCNTBn 的值自动重新加载到下一个循环开始。但是,如果定时器停止,例如,在定时器运行模式下,通过清除 TCONn 的定时器使能位,TCNTBn 的值将不会重新加载到计数器中。

 

PWM 功能使用 TCMPBn 寄存器的值。定时器控制逻辑改变输出电平下计数器值与定时器控制逻辑中比较寄存器的值相匹配。因此,比较寄存器决定 PWM 输出的开启时间或关闭时间。

 

每个定时器都是双缓冲结构,带有 TCNTBn 和 TCMPBn 寄存器,允许定时器参数在周期中更新。新值在当前计时器周期完成之前不会生效。

 

Exynos PWM定时器的特性

1)5个32位定时器;

2)2个8位 PCLK 分频器提供一级预分,5个2级分频器用来预分外部时钟;3)可编程选择 PWM 独立通道。

4)4个独立的可编程的控制及支持校验的PWM通道。

5)静态配置:PWM 停止;

6)动态配置:PWM 启动;

7)支持自动重装模式及触发脉冲模式;

8)一个外部启动引脚。

9)两个 PWM 输出可带 Dead-Zone 发生器。

10)中断发生器。

 

PWM 内部模块图

 

 

工作的步骤:

当时钟 PCLK 被使能后,定时器计数缓冲寄存器(TCNTBn)把计数器初始值下载到递减计数器中。定时器比较缓冲寄存器(TCMPBn)把其初始值下载到比较寄存器中,并将该值与递减计数器的值进行比较。当递减计数器和比较寄存器值相同时,输出电平翻转。递减计数器减至 0 后,输出电平再次翻转,完成一个输出周期。这种基于 TCNTBn 和 TCMPBn 的双缓冲特性使定时器在频率和占空比变化时能产生稳定的输出。每个定时器都有一个专用的由定时器时钟驱动的 16 位递减计数器。当递减计数器的计数值达到 0 时,就会产生定时器中断请求来通知CPU定时器操作完成。当定时器递减计数器达到0的时候,如果设置了 Auto-Reload 功能,相应的 TCNTBn 的值会自动重载到递减计数器中以继续下次操作。然而,如果定时器停止了,比如在定时器运行时清除 TCON 中定时器使能位,TCNTBn 的值不会被重载到递减计数器中。TCMPBn 的值用于脉冲宽度调制。当定时器的递减计数器的值和比较寄存器的值相匹配的时候,定时器控制逻辑将改变输出电平。因此,比较寄存器决定了 PWM 输出的开关时间。举例

 

下面我们举个实例来看下,

 

 

初始化寄存器 TCNTBn = 159 (50 + 109) ,TCMPBn =109.开启定时器: 通过设置 TCON 的开启位.寄存器 TCNTBn 的值 159 将自动加载到递减寄存器 down-counter, 同时输出引脚 TOUTn 设置为低电平.当 down-counter 的值递减打破和寄存器 TCMPBn 的值 109 相同时, 输出引脚将从低拉到高.当 down-counter 递减到 0 时, 产生一个中断请求.如果我们设置成 autoreload 模式,那么 down-counter 会自动加载 TCNTBn 的值到 down-counter,开启新的一个周期。

 

我们可以通过设置 TCNTBn、TCMPBn 来控制占空比,而每个 pwm 周期后都可以重新设置新的值到 TCNTBn、TCMPBn,我们通过精确的计算来设置 TCNTBn、TCMPBn 的值并通过设置 dead zone 我们可以设计出各种复杂的矩形波。

 

如下图所示:

 

 

本例我们只需要产生规则的举行方波即可,所以我们只需要设置占空比为 50%即可。

 

六、寄存器

由第四章可知,我们使用 PWM 控制器的 timer 0,对应的寄存器组如下图所示:

 

 

1、TFCG0

定时器配置寄存器 0(TFCG0) ,主要用于预分频设置。

 

 

我们是 timer 0,所以只需要设置该寄存器的 bite【7:0】即可,最终的输出频率和 value 的公式如下:

 

 

参考 24.3.1 节:

其中方波的频率必须在音频范围内,也就是 20Hz 到 20KHZ 之间, 但是 20Hz 到 20KHZ 的频率送给蜂鸣器后, 只有某一点的频率是最响的, 这个频率称为蜂鸣器的谐振频率, 离它越远, 蜂鸣器发出的声音越轻。

 

所以 Prescaler 0 value 值应该设置为 255,divider value 应该是 1/16,值由 TCFG1 设置。

 

PWM.TCFG0 = PWM.TCFG0 & (~(0xff))|0xf9;

 

2、TCFG1

定时器配置寄存器 1(TCFG1)   主要用于 PWM 定时器的 divider value 设置。

 

 

由上一节分析,秩序设置 TCFG1 bite【3:0】为 0100 即 0x2 即可。

PWM.TCFG1 = PWM.TCFG1 & (~(0xf)) | 0x2;

 

3、TCON

timer 控制寄存器 TCON

 

 

bite[3] : 设置定时器是只执行一个周期(One-shot)还是周期执行(auto-reload)bite[1]: 置为 1,则更新 TCNTB0 、TCMPB0 的值 bit[0]:开启或者停止定时器

 

针对不同操作,我们可以设置不同的值:

装载 PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 1) ;

开启定时器,蜂鸣器响 PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 3) ;

关闭定时器,蜂鸣器灭 PWM.TCON = PWM.TCON & (~(1 << 0)) ;

 

4、TCNTB0

定时器计数缓冲寄存器(TCNTB0)根据测算,设置为 100

 

 

TCNTB0 PWM.TCNTB0 = 100;

 

5、TCMPB0

定时器比较缓冲寄存器(TCMPB0 )设置为 50,占空比为 50%

 

 

PWM.TCMPB0 = 50;

 

七、代码

完整代码后台回复**【armprintf】**。

#include "exynos_4412.h"
void  delay_ms(unsigned int num)
{   int i,j;
   for(i=num; i>0;i--)
for(j=1000;j>0;j--);

void pwm_init(void)

GPD0.CON = GPD0.CON & (~(0xf))| 0x2;
PWM.TCFG0 = PWM.TCFG0 & (~(0xff))|0xf9;
PWM.TCFG1 = PWM.TCFG1 & (~(0xf)) | 0x2;
PWM.TCMPB0 = 50;
PWM.TCNTB0 = 100;
PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 1) ;

void beep_on(void)

PWM.TCON = PWM.TCON & (~(0xff)) | (1 << 0) | (1 << 3) ;

void beep_off(void)

PWM.TCON = PWM.TCON & (~(1 << 0)) ;

#define SYS_SET_FREQUENCE 25000
void beep_set_frequence( unsigned int fre )
{ //若蜂鸣器的发声频率为 0 则返回
if( 0==fre )
 return ;
PWM.TCMPB0 =  SYS_SET_FREQUENCE/(fre+fre);//根据设定频率重新设定计数器比较的值
PWM.TCNTB0 =  SYS_SET_FREQUENCE/fre; //根据频率重新调整计数值

int main (void)
{ pwm_init();
while(1)
{  beep_on();   //发出一个音
  delay_ms(100);
  beep_off();         //关闭蜂鸣器, 每个音播放完成后有间隔感
  delay_ms(100);

  return 0;

我们也可以通过修改频率和音响的时间来播放音乐。