一、PWM介绍
PWM是指脉冲宽度调制,它是一种模拟控制方式。通过改变晶体管或MOS管的导通时间来实现开关稳压电源的控制,广泛应用于功率控制与变换的许多领域。
1、pwm的频率
是指在1秒钟内,信号从高电平到低电平再回到高电平的次数,也就是说一秒钟PWM有多少个周期,单位HZ.
2、pwm的周期
T=1/f,T是周期,f是频率
如果频率为50Hz,也就是说一个周期是20ms,那么一秒钟就有 50次PWM周期。
3、pwm的占空比
是一个脉冲周期内,高电平的时间与整个周期时间的比例(0%-100%)
二、PWM工作原理分析
三、I.MX6ull PWM介绍
脉宽调制(PWM)有一个16位计数器,经过优化,可以从存储的样本音频图像中生成声音,还可以生成音调。它使用16位分辨率和4x16数据FIFO。
内部寄存器
1、时钟信号
(1) High-frequancy reference clock (ipg_ clk_ highfreq) pat_ref
This is a high frequency clock, provided by the Clock Control Module (CCM). This clock should be on in the lowpower mode when the ipg_clk is turned of.
这是一个高频时钟,由时钟控制模块(CCM)提供。当ipg_cik关闭时,处于低功耗模式,该时钟应打开。
(2) Low-frequency reference clock (ipg _ clk 32k CKIL)
This is the 32 KHz low reference clock which is provided by the CCM. This clock should be on in the low powermode when ipg,_ clk is turned off. Thus, PwM can be run on this clock in the low power mode.
这是CCM提供的32 KHz低参考时钟。当ipg_ck关闭时,该时钟应该在低功耗模式下打开。因此,PWM在低功耗模式下使用该时钟运行。
(3) Peripheral clock (ipg_clk)
This clock should be on in normal operations. In low power mode, it can be switched off.
该时钟在正常运行时应为开启状态。在低功耗模式下,可将其关闭。
(4) Peripheral access clock (ipg_clk_s)
This clock is used for register read/write.
该时钟用于寄存器的读/写。
2、工作原理
The output of the PWM is a toggling signal whose frequency and duty cycle can be modulated by programmingthe appropriate registers. It has a 16-bit up counter which counts from 0x0000 until the counter value equalsthe PWM PR + 1. After this match occurs the counter is reset to 0x0000.
PWM的输出是一个切换信号,其频率和占空比可以通过编程相应的寄存器来调制。它有一个16位向上计数器,从0x0000开始计数,直到计数器值等于PWM_PR+1。匹配发生后,计数器重置为0x0000。
At the beginning of a count period cycle, the PWMO pin is set to one (default) and the counter beginscounting up from 0x0000. The sample value in the sample FIf0 is compared on each count of prescaler clock.When the sample and count values match, the PWMO signal is cleared to zero (default). The countercontinues counting until the period match occurs and subsequently another period cycle begins.
在计数周期周期的开始,PWMO引脚设置为1(默认),计数器从0x0000开始向上计数。采样值在采样FIFO中,它的值在每个时钟周期和计数器的值比较。当采样值和计数值匹配时,PWMO信号被清除为零(默认)。计数器继续计数,直到周期匹配发生,随后另一个周期周期开始。
When the PWM is enabled, the counter starts running and generates an output with the reset values in theperiod and sample registers. It is recommended that the programming of these registers be done before PWMis enabled.
当PWM被启用时,计数器开始运行,并使用周期和采样寄存器中的重置值生成输出。建议在启用PWM之前完成这些寄存器的编程。
A hardware reset results in all the PWM count and sample registers being cleared and the FIF0 being flushed.The control register shows that FIF0 is empty and it can be written into, and the PWM is disabled. A softwarereset has the same results, however the state of the DBGEN, STOPEN, DOZEN, and WAITEN bits in the controregister are not affected. Software reset can be asserted even when the PWM is in disabled state.
硬件复位导致所有PWM计数和采样寄存器被清除,FIFO被刷新。控制寄存器显示FIFO为空,可以写入,PWM被禁用。软件复位具有相同的结果,但是控制寄存器中DBGEN、STOPEN、DOZEN和WAITEN位的状态不受影响。即使PWM处于禁用状态,也可以断言软件复位。
3、FIFO
Digital sample values can be loaded into the pulse-width modulator as 16-bit words. The endianess can bechanged using the BCTR and HCTR bits of the control register. A 4-word (16-bit) FIF0 minimizes interruptoverhead. A maskable interrupt is generated when the number of data words fall below the water level set bythe FWM field in the control register.
数字采样值可以作为16位字加载到脉宽调制器中。可以使用控制寄存器的BCTR和HCTR位来改变字节序。4字(16位)FIFO最大限度地减少了中断开销。当数据字的数量低于控制寄存器中FWM字段设置的水位时,会产生可屏蔽中断。
A write to the PWM SAR sample register results in the value being stored into the FIFO if it is not ful. A writewhen the FIFO is full sets FWE (FIFO write error) bit in the status register and the FIF0 contents remainunchanged. The FIFO can be written at any time, but can be read only when the PWM is enabled. The PWM_SR[FIFOAV] field shows how many data words are currently contained in the FIFO and whether or not itcan be written into.
如果FIFO未满,对PWM_SAR样本寄存器的写入会导致该值被存储到FIFO中。FIFO已满时的写入会设置状态寄存器中的FWE(FIFO写入错误)位,并且FIFO内容保持不变。FIFO可以随时写入,但只有在启用PWM时才能读取。PWM_SR[FIFOAV]字段显示FIFO中当前包含多少数据字以及是否可以写入。
四、PWM寄存器介绍
1.PWM Control Register(PWMx_PWMCR)
控制寄存器
2.PWM Counter Register (PWMx_PWMCNR)
计数器寄存器
3.PWM Period Register(PWMx_PWMPR)
周期寄存器
4.PWM Sample Register(PWMx_PWMSAR)
采样寄存器
五、PWM驱动蜂鸣器
1.原理图分析
如上图可知:蜂鸣器的控制管脚是CPU的GPIO1的第9管脚
2.编程思想
(1)使能GPIO和PWM时钟信号
/*Enable clock*/
CCM_CCGR1 |= (0x30 << 26);//打开GPIO管脚的时钟信号
CCM_CCGR4 |= (0x30 << 18);//打开PWM2管脚的时钟信号
(2)管脚设置为PWM功能模式
/*
0000 ALT0 — Select mux mode: ALT0 mux port: PWM2_OUT of instance: pwm2
*/
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09 &= ~(0xf << 0);//复用为PWM模式
(3)复位PWM控制器
/*Reset PWM*/
PWM2->PWMCR |= (1 << 3);
while(PWM2->PWMCR & (1 << 3))
{
}
(4)选择时钟信号确定PWM的输入时钟信号
PWM2->PWMCR = (1 << 16) | (65 << 4);
(5)设置PWM周期值的采用值
PWM2->PWMPR = period -2 ;//周期值
PWM2->PWMSAR = sample;//采样值
(6)开启PWM,然后延时一段时间,最后关闭PWM
/*开启蜂鸣器*/
void beep_start(void)
{
PWM2->PWMCR |= (1 << 0);//使能PWM
}
/*关闭蜂鸣器*/
void beep_stop(void)
{
PWM2->PWMCR &= ~(1 << 0);//使能PWM
}
/*pwm测试代码*/
void beep_test(void)
{
int i;
/*PWM Output Signal HZ : 1MHZ/1000 = 1KHZ*/
beep_init(500,1000);//PWM初始化
beep_start();
for(i=0;i<100;i++)
{
set_sample_value(i*10);//设置采样值
gpt_delay_ms(500);
}
beep_stop();
return ;
}
3.代码实现
beep.c
#include "imx6ull.h"
/*PWM初始化函数*/
void beep_init(uint32_t sample,uint32_t period)
{
/*Enable clock*/
CCM_CCGR1 |= (0x30 << 26);//打开GPIO管脚的时钟信号
CCM_CCGR1 |= (0x30 << 18);//打开PWM2管脚的时钟信号
/*
0000 ALT0 — Select mux mode: ALT0 mux port: PWM2_OUT of instance: pwm2
*/
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09 &= ~(0xf << 0);//复用为PWM模式
/*Reset PWM*/
PWM2->PWMCR |= (1 << 3);
while(PWM2->PWMCR & (1 << 3))
{
}
/*
PWM Input Clock = IPG_CLK / Pre
= 66MHZ /(65 + 1)
= 1MHZ
*/
PWM2->PWMCR = (1 << 16) | (65 << 4);
PWM2->PWMPR = period -2 ;//周期值
PWM2->PWMSAR = sample;//采样值
return ;
}
/*开启蜂鸣器*/
void beep_start(void)
{
PWM2->PWMCR |= (1 << 0);//使能PWM
}
/*关闭蜂鸣器*/
void beep_stop(void)
{
PWM2->PWMCR &= ~(1 << 0);//使能PWM
}
/*设置采样值*/
void set_sample_value(uint32_t value)
{
PWM2->PWMSAR = value;//采样值
}
/*pwm测试代码*/
void beep_test(void)
{
int i;
/*PWM Output Signal HZ : 1MHZ/1000 = 1KHZ*/
beep_init(500,1000);//PWM初始化
beep_start();
for(i=0;i<100;i++)
{
set_sample_value(i*10);//设置采样值
gpt_delay_ms(500);
}
beep_stop();
return ;
}
main.c
void beep_test(void);
void led_test(void);
int main(void)
{
beep_test();
return 0;
}