
目录一.背景PWM原理二.寄存器PWMCRFWM(bit27:26)POUTC(bit19:18)CLKSRC(bit17:16)PRESCALER(bit15:4)REPEAT(bit2:1)EN(bit0)PWMSRFE(bit3)PWMIRFIE(bit0)PWMSARPWMPR三.代码实现一.背景不管是使用显示器还是手机其屏幕背光都是可以调节的通过调节背光就可以控制屏幕的亮度。在户外阳光强烈的时候可以通过调高背光来看清屏幕在光线比较暗的地方可以调低背光防止伤眼睛并且省电。 我们使用的开发板LCD 有一个背光控制引脚给这个背光控制引脚输入高电平就会点亮背光输入低电平就会关闭背光。假如我们不断的打开和关闭背光当速度足够快的时候就不会感觉到背光关闭这个过程了。这个正好可以使用 PWM 来完成PWM 全称是 Pulse Width Modulation也就是脉冲宽度调制本质上来说PWM的目的就是产生一个方波。PWM 信号有两个关键的术语频率和占空比频率就是开关速度把一次开关算作一个周期那么频率就是 1 秒内进行了多少次开关。占空比就是一个周期内高电平时间和低电平时间的比例一个周期内高电平时间越长占空比就越大反之占空比就越小。占空比用百分之表示如果一个周期内全是低电平那么占空比就是 0%如果一个周期内全是高电平那么占空比就是100%。我们给 LCD 的背光引脚输入一个 PWM 信号这样就可以通过调整占空比的方式来调整LCD 背光亮度了。提高占空比就会提高背光亮度降低占空比就会降低背光亮度。重点就在于PWM 信号的产生和占空比的控制很幸运的是I.MX6U 提供了 PWM 外设因此我们可以配置 PWM 外设来可以方便地产生PWM 信号。imx6ull将PWM封装为外设PWM原理此图有三个中断周期寄存器的回滚中断采样寄存器的比较中断以及FIFO缓冲区的空槽中断。此处只用FIFO中断每次从FIFO中取数到采样寄存器决定了占空比该FIFO深度为4即存放4个16位数当FIFO缓冲区的数据被取到空的阈值时产生中断在中断处理函数中再往FIFO里重新装入数据以下实现的代码基于此。计数寄存器自增到和采样寄存器比较相等则将PWM电平翻转后续再和周期寄存器的值比较相等则翻转电平同时从0开始重新计数自增重复此过程和采样寄存器比较再和周期寄存器的值比较相等就翻转电平并回滚为0.二.寄存器PWMCRFWM(bit27:26)FIFO 水位线用来设置 FIFO 空余位置为多少的时候表示 FIFO 为空。设置为 0 的时候表示 FIFO 空余位置大于等于 1 的时候 FIFO 为空设置为 1 的时候表示 FIFO 空余位置大于等于 2 的时候 FIFO 为空以此类推。队列有四个数设置FWM位为01当队列有两个空槽时置1POUTC(bit19:18)00表示回滚点高电平比较点低电平01相反即设置起始的默认电平。我们设置为 0也就是一开始输出高电平当计数器值和采样值相等的话就改为低电平这样采样值越大高电平时间就越长占空比就越大如下图CLKSRC(bit17:16)PWM 时钟源选择为 0 的话关闭为 1 的话选择 ipg_clk 为时钟源为 2 的话选择 ipg_clk_highfreq 为时钟源为 3 的话选择 ipg_clk_32k 为时钟源。我们设置为 1也就是选择ipg_clk 为 PWM 的时钟源因此 PWM 时钟源频率为 66MHzPRESCALER(bit15:4)分频值可设置为 0~4095对应着 1~4096 分频。我们设置为65就是66分频PWM实际工作频率为1MHzREPEAT(bit2:1)重复采样设置此位用来设置 FIFO 中的每个数据能用几次。可设置 0~3分别表示 FIFO中的每个数据能用 1~4 次。本章我们设置为 3即 FIFO 中的每个数据用8次EN(bit0)PWM 使能位为 1 的时候使能 PWM为 0 的时候关闭 PWMPWMSR这个寄存器是状态及标志寄存器FE(bit3)FIFO 到达水位线标志为 1 的时候表示 FIFO 已到达水位线。我们主要在中断中关注这个标志并及时清零PWMIR这个是 PWM 的中断控制寄存器FIE(bit0)FIFO 空中断为 1 的时候使能为 0 的时候关闭。我们需要使能这个中断PWMSAR设置PWM的占空比即采样寄存器PWMPR设置PWM周期即周期寄存器三.代码实现float global_ratio 1.0; // 设置占空比 void set_ratio(void) { int i 0 ; for (i 0; i 4; i) { PWM1-PWMSAR PWM1-PWMPR * global_ratio; } } void pwm1_interrupt_handler(void) { if ((PWM1-PWMSR (1 3)) ! 0) { set_ratio(); PWM1-PWMSR | (1 3); } } // pwm1初始化 void pwm1_init(void) { // 1. pwm引脚复用 IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT, 0); // 2. pwm引脚电气属性 IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT, 0xB9); PWM1-PWMCR 0; PWM1-PWMCR | (1 26) | (1 16) | (65 4) | (3 1); PWM1-PWMIR | (1 0); PWM1-PWMPR 998; set_ratio(); // 注册pwm中断 system_interrupt_register(PWM1_IRQn, pwm1_interrupt_handler); // 设置pwm中断优先级 GIC_SetPriority(PWM1_IRQn, 0); // 使能pwm中断 GIC_EnableIRQ(PWM1_IRQn); // 使能PWM PWM1-PWMCR | (1 0); }