一、PWD简介
1.1 蜂鸣器工作原理
有源蜂鸣器
有源蜂鸣器只要接上额定电源就可以发出声音
无源蜂鸣器
无源蜂鸣器利用电磁感应原理,为音圈接入交变电流后形成的电磁铁与永磁铁相吸或相斥而推动振膜发声
1.2 使用GPIO控制
while(1)
{
GPX2.DAT=GPX2.DAT | (1 << 7);
Delay(1000000);
GPX2.DAT=GPX2.DAT & (~(1 << 7));
Delay(1000000);
}
这样虽然可以控制,但是太浪费CPU资源了。
1.3PWM控制
PWM(Pulse Width Modulation)即脉冲宽度调制,通过对脉冲的宽度进行调制,来获得所需要波形
1.4 PWM参数
周期
占空比
一个周期中高电平时间与整个周期的比例称为占空比
二、Exynos4412下的PWM控制器
有五个PWM定时器。可以产生中断。0-3可以通过引脚把信号传送到CPU之外,第0个有死区可以支持大电流.。4是内部定时器没有输出引脚(4412的PWM定时器和看门狗都是递减的)
PWM使用PCLK(100MHz)作为时钟源,timer 0和1共用一个8位的一级预分频器(1-256倍)。timer2,3,4共用另外一个8位一级分频器 然后每个timer都有一个自己的二级分频器(2,4,8,16倍)
举例:
5、把周期也就是这个159写进TCNTB,把109写进TCMTB,用于设置占空比
6、给计数器使能,需要手动关闭
7、TCNTB把159写进递减计数器,对外的输出引脚开始输出低电平(以前可能输出的是高电平,只要PWM开始工作,就输出低电平)
8、递减计数器减到109,就开始输出高电平
9、如果递减计数器到0,则会产生中断请求
10、递减计数器自动重加载,也就是递减计数器的值会重新编程159,然后一直循环
脉冲信号的周期除了跟TCNTB里的值有关,还跟递减计数器的频率有关。
PWM内部框架图:
反向输出功能:
三、PWM寄存器详解
TCFG0:用于设置8位的预分频器和死区的宽度的(死区的功能时是保护大功率的设备)
TCFG1:用于设置二级分频
TCON:控制寄存器,用于控制PWM的一些细节功能
TCNTB0、1、2、3、4:用于设置PWM寄存器产生的脉冲信号的周期
TCMPB0、1、2、3、4:用于设置一个周期脉冲信号中高电平的时间的,即设置PWM信号的占空比
TCNTO0、1、2、3、4:用于存储递减计数器中的值(只读)
(0、1、2、3、4表示分别用于设置不同的PWM寄存器)
TCFG0:[23:16]用于设置死区宽度(本次实验不使用)
PWM2、3、4公用一个分频器,通过[15:8]设置分频
PWM0、1公用一个分频器,通过[7:0]设置分频
TCFG1:二级分频器,每个PWM寄存器都有一个私有的二级分频器
(本次实验实验PWM0,所以只需要设置[3:0]就可以了)
TCON寄存器可以管理PWM0、1、2、3、4的功能,本次实验使用PWM0,所以只看PWM0相关的
[4]用于设置死区功能的开和关。(本次实验不使用)
[3]用于设置PWM0的自动重装载功能的开和关,如果设置成0,只能产生一次脉冲信号。(本实验设置成1)
[2]用于设置反向功能的开和关,0是关闭,1是打开。
[1]用于设置手动更新,写1会自动把TCNTB的值赋值到递减计数器(先设置TCNTB的值,再把这位置1)
[0]用于设置整个PWM0寄存器的开和关
用于设置PWM0寄存器产生的脉冲信号的周期(必须比TCMPB0的值大)
用于设置一个周期脉冲信号中高电平的时间的,即设置PWM0信号的占空比
用于存储递减计数器中的值(只读)
四、PWM编程
我们把本次实验蜂鸣器配置频率为500Hz
我们首先需要配置引脚GPD0_0,在[3:0]写0x2,配置成PWM TOUT_0功能
#include "exynos_4412.h"
int main()
{
/*1.将GPD0_0引脚设置成PWM0的输出引脚*/
GPD0.CON = GPD0.CON & (~(0xF)) | (0x2);
/*2.设置PWM的一级分频,一级分频倍数为100倍*/
PWM.TCFG0 = PWM.TCFG0 & (~(0xFF)) | 99;
/*3.设置PWM的二级分频,二级分频倍数为1倍,递减计数器递减频率 = PLCK / (99+1) / 1 = 1M*/
PWM.TCFG1 = PWM.TCFG1 & (~(0xF));
/*4.设置PWM0为连续重装载*/
PWM.TCON = PWM.TCON | (1 << 3);
/*5.设置PWM0的频率为500Hz*/
PWM.TCNTB0 = 2000;
/*6.设置PWM0的占空比为50%*/
PWM.TCMPB0 = 1000;
/*7.将TCNTB0中的值手动装载到递减计数器*/
PWM.TCON = PWM.TCON | (1 << 1);
/*8.关闭手动更新*/
PWM.TCON = PWM.TCON & (~(1 << 1));
/*9.使能PWM0,递减计数器开始递减*/
PWM.TCON = PWM.TCON | 1;
while(1)
{
}
return 0;
}
我们还可以让他间断响
#include "exynos_4412.h"
void Delay(unsigned int Time)
{
while(Time--);
}
int main()
{
/*1.将GPD0_0引脚设置成PWM0的输出引脚*/
GPD0.CON = GPD0.CON & (~(0xF)) | (0x2);
/*2.设置PWM的一级分频,一级分频倍数为100倍*/
PWM.TCFG0 = PWM.TCFG0 & (~(0xFF)) | 99;
/*3.设置PWM的二级分频,二级分频倍数为1倍,递减计数器递减频率 = PLCK / (99+1) / 1 = 1M*/
PWM.TCFG1 = PWM.TCFG1 & (~(0xF));
/*4.设置PWM0为连续重装载*/
PWM.TCON = PWM.TCON | (1 << 3);
/*5.设置PWM0的频率为500Hz*/
PWM.TCNTB0 = 2000;
/*6.设置PWM0的占空比为50%*/
PWM.TCMPB0 = 1000;
/*7.将TCNTB0中的值手动装载到递减计数器*/
PWM.TCON = PWM.TCON | (1 << 1);
/*8.关闭手动更新*/
PWM.TCON = PWM.TCON & (~(1 << 1));
/*9.使能PWM0,递减计数器开始递减*/
PWM.TCON = PWM.TCON | 1;
while(1)
{
PWM.TCON = PWM.TCON | 1;
Delay(1000000);
PWM.TCON = PWM.TCON & (~(1));
Delay(1000000);
}
return 0;
}
五、作业
调成PWM的频率1000HZ,占空比%60
#include "exynos_4412.h"
void Delay(unsigned int Time)
{
while(Time--);
}
int main()
{
/*1.将GPD0_0引脚设置成PWM0的输出引脚*/
GPD0.CON = GPD0.CON & (~(0xF)) | (0x2);
/*2.设置PWM的一级分频,一级分频倍数为100倍*/
PWM.TCFG0 = PWM.TCFG0 & (~(0xFF)) | 99;
/*3.设置PWM的二级分频,二级分频倍数为1倍,递减计数器递减频率 = PLCK / (99+1) / 1 = 1M*/
PWM.TCFG1 = PWM.TCFG1 & (~(0xF));
/*4.设置PWM0为连续重装载*/
PWM.TCON = PWM.TCON | (1 << 3);
/*5.设置PWM0的频率为1000Hz*/
PWM.TCNTB0 = 1000;
/*6.设置PWM0的占空比为60%*/
PWM.TCMPB0 = 600;
/*7.将TCNTB0中的值手动装载到递减计数器*/
PWM.TCON = PWM.TCON | (1 << 1);
/*8.关闭手动更新*/
PWM.TCON = PWM.TCON & (~(1 << 1));
/*9.使能PWM0,递减计数器开始递减*/
PWM.TCON = PWM.TCON | 1;
while(1)
{
PWM.TCON = PWM.TCON | 1;
Delay(1000000);
PWM.TCON = PWM.TCON & (~(1));
Delay(1000000);
}
return 0;
}