ARM嵌入式学习--第八天(PWM)
PWM
-PWM介绍
PWM(pulse Width Modulation)简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在测量,通信,工控等方面
PWM的频率
是指在1秒钟内,信号从高电平到低电平在回到高电平的次数,也就是说1秒钟PWM有多少个周期,单位HZ
PWM的周期
T=1/f,T是周期,f是频率,即如果频率为50HZ,也就是说一个周期是20ms,那么1秒钟就有50个PWM周期
占空比
是一个脉冲周期内,高电平的时间与整个周期时间的比例(0%~100%)
总结
1.脉冲周期(T),单位是时间,比如纳秒(ns),微秒(us),毫秒(ms)等
2.脉冲频率(f),单位是HZ,KHZ等,与脉冲周期成倒数关系,f=1/T
3.脉冲宽度(W),简称“脉宽”,是脉冲高电平持续的时间,单位是时间
4.占空比(D),脉宽除以脉冲周期的值,百分比表示,比如50%,也常有小数或分数表示的,比如0.5或1/2
以上之间的关系如图所列的公式:
-PWM的工作原理分析(IMX6ull)
脉宽调制(PWM)有一个16位计数器,经过优化,可以从存储的样本音频图像中生成声音,还可以生成音调,它使用16位分辨率(指的就是16位计数器)4 x 16数据FIF0[缓存]
工作原理
PWM的输出是一个切换信号,其频率和占空比可以通过编程相应的寄存器来调制,它有一个16位向上计数器,从0x0000开始计数,直到计数器值等于PWM_PR+1,匹配发生后,计数器重置为0x0000(PWM_PR是周期寄存器)
在计数周期的开始,PWM0引脚设置为1(默认),计数器从0x0000开始向上计数,采样值在采样FIF0中,它的值在每个时钟周期和计数器的值比较,当采样值和计数器匹配时,PWM0信号被清除为0(默认),计数器继续计数,直到周期匹配发生,随后另一个周期开始
当PWM被启用时,计数器开始运行,并使用周期和采样寄存器中的重置值生成输出,建议在启用PWM之前完成这些寄存器的编程
硬件复位导致所有PWM计数和采样寄存器被清除,FIF0被刷新,控制寄存器显示FIF0为空,可以写入,PWM被禁用,软件复位具有相同的结果,但是控制寄存器中DBGEN,STOPEN,DOZEN和WAITEN位的状态不受影响,只有PWM处于禁用状态,才可以进行软件复位
FIF0
数字采样值可以作为16位字加载到脉冲调制器中,可以使用控制器的BCTR和HCTR位来改变字节序,4字(16位)FIF0最大限度地减少了中断开销。当数据字的数量低于控制寄存器的FWM字段设置的水位时,会产生可屏蔽中断。
如果FIF0未满,对PWM_SAR采样寄存器的写入会导致该值被存储到FIF0中,FIF0已满时的写入会设置状态寄存器中的FWE(FIF0写入错误)位,并且FIF0内容保持不变,FIF0可以随时写入,但只有在启用PWM时,才能读取,PWM_SR[FIF0AV]字段显示FIF0中当前包含多少数据字以及是否可以写入
-PWM重点寄存器介绍
PWM Control Register (PWMx_PWMCR)
PWM Counter Register (PWMx_PWMCNR)
只读脉冲宽度调制器计数器寄存器(PWM_PWMCNR)包含当前计数值,可以随时读取而不会干扰计数器
PWM Period Register(PWMx_PWMPR)
PWM周期寄存器(PWM_PWMPR)确定PWM输出信号的周期,计时器值匹配PERIOD+1后,计数器复位以开始另一个周期(PWMO[Hz] = PLCK[Hz]/period+2)
(由于写入PWM_PWMPR导致的周期值的变化会导致计数器重置为零并开始新的计数周期)
PWM Sample Register(PWMx_PWMSAR)
PWM采样寄存器(PWM_PWMSAR)是FIF0的输入,16位字被加载带FIF0的输入。FIF0可以随时写入,但只有启用PWM时才能读取
-PWM驱动蜂鸣器
原理图分析
原理图通过GPIO_9这个IO来控制蜂鸣器,当GPIO_9输出低电平的时蜂鸣器发声。设置GPIO1_9的MUX mod为PWM的工作模式,不同的占宽比让蜂鸣器发出的响声不一样
编程思路
1.使能GPIO和PWM时钟信号
2.管脚设置为PWM功能模式
3.复位PWM控制器
4.选择时钟信号确定PWM的输入时钟信号
5.设置PWM周期值和采样值
6.开启PWM,然后延时一段时间,最后关闭PWM
示例代码
pwm.c
#include "pwm.h"
void pwm_gpio_init(){
//开启时钟
CCM_CCGR1 |= (0x3 << 26);
// 设置复用器
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09 &=~(0xf<<0);
//设置方向
GPIO1->GDIR |= (0x1<<9);
}
//pwm的初始化
void pwm_init(){
//开启时钟
CCM->CCGR4 |= (0x3 << 18);
//禁用PWM
PWM2->PWMCR &= ~(0x1 <<0);
//软件复位
PWM2->PWMCR |= (0x1<<3);
while (PWM2->PWMCR & (0x1 << 3)){
}
//选择时钟源
PWM2->PWMCR &= ~(0x3<<16);
PWM2->PWMCR |= (0x1 << 16);
// 设置pwm的时钟分频器
PWM2->PWMCR &= ~(0xfff << 4);
PWM2->PWMCR |= (0x41 << 4);
//设置周期
PWM2->PWMPR = PERIOD - 2;
}
//打开PWM
void pwm_on(){
// 使能pwm
PWM2->PWMCR |= (0x1 << 0);
}
//关闭PWM
void pwm_off(){
// 关闭pwm
PWM2->PWMCR &= ~(0x1 << 0);
}
// 设置采样值
void pwm_set_sample_val(int val){
PWM2->PWMSAR = val;
}
//测试
void pwm_test(){
pwm_gpio_init();
pwm_init();
pwm_on();
int i=0;
for(;i<=10;i++){
pwm_set_sample_val(i*100);
gpt_delay_mseconds(500);
}
pwm_off();
}
pwm.h
#ifndef __PWM_HEAD_
#define __PWM_HEAD_
#include "../../include/imx6ull.h"
#include "../driver/gpt/gpt.h"
#include <stdio.h>
#define PERIOD 1000
extern void pwm_test();
#endif