《嵌入式硬件(二十一):基于IMX6ULL的脉冲宽度调制(PWM)操作》
一、PWM
        不管是使用显示器还是手机,其屏幕背光都是可以调节的,通过调节背光就可以控制屏幕的亮度。在户外阳光强烈的时候可以通过调高背光来看清屏幕,在光线比较暗的地方可以调低背光,防止伤眼睛并且省电。 我们使用的开发吧LCD 有一个背光控制引脚,给这个背光控制引脚输入高电平就会点亮背光,输入低电平就会关闭背光。假如我们不断的打开和关闭背光,当速度足够快的时候就不会感觉到背光关闭这个过程了。这个正好可以使用 PWM 来完成,PWM 全称是 Pulse Width Modulation,也就是脉冲宽度调制,本质上来说PWM的目的就是产生一个方波。
PWM 信号有两个关键的术语:频率和占空比,频率就是开关速度,把一次开关算作一个周期,那么频率就是 1 秒内进行了多少次开关。占空比就是一个周期内高电平时间和低电平时间的比例,一个周期内高电平时间越长占空比就越大,反之占空比就越小。占空比用百分之表示,如果一个周期内全是低电平那么占空比就是 0%,如果一个周期内全是高电平那么占空比就是100%。 
我们给 LCD 的背光引脚输入一个 PWM 信号,这样就可以通过调整占空比的方式来调整LCD 背光亮度了。提高占空比就会提高背光亮度,降低占空比就会降低背光亮度。重点就在于PWM 信号的产生和占空比的控制,很幸运的是,I.MX6U 提供了 PWM 外设,因此我们可以配置 PWM 外设来可以方便地产生 PWM 信号。
二、寄存器
1.引脚设置




2.控制寄存器(PWMCR)



3.状态寄存器(PWMSR)


4.中断寄存器(PWMIR)

5.采样寄存器(PWMSAR)

6.周期寄存器(PWMPR)

三、代码
1.pwm.h
#ifndef _PWM_H_
#define _PWM_H_extern void init_pwm1(void);
extern void set_ratio(void);
extern float global_ratio;#endif
2.pwm.c
#include "pwm.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "led.h"
#include "interrupt.h"
#include "core_ca7.h"float global_ratio = 1.0;void set_ratio(void)
{int i;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);}}void init_pwm1(void)
{IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT, 0);IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT, 0xB090);PWM1->PWMCR = 0;PWM1->PWMCR |= (1 << 26) | (1 << 16) | (65 << 4) | (3 << 1);PWM1->PWMIR |= (1 << 0);PWM1->PWMPR = 998;set_ratio();system_interrupt_register(PWM1_IRQn, pwm1_interrupt_handler);GIC_EnableIRQ(PWM1_IRQn );PWM1->PWMCR |= (1 << 0);
}3.main.c
#include "string.h"
#include "led.h"
#include "beep.h"
#include "MCIMX6Y2.h"
#include "key.h"
#include "interrupt.h"
#include "clock.h"
#include "epit.h"
#include "gpt.h"
#include "delay.h"
#include "uart.h"
#include "stdio.h"
#include "i2c.h"
#include "lm75.h"
#include "adc.h"
#include "spi.h"
#include "adxl345.h"
#include "lcd.h"
#include "framebuffer.h"
#include "pwm.h"
#include "ts.h"int main(void)
{init_clock();system_interrupt_init();init_led();init_beep();// init_key();
//    init_epit1();init_gpt1();init_uart1(); init_i2c1();init_i2c2();init_adc1_channle1();init_spi3();
//    init_adxl345();init_lcd();lcd_clear(0x00FFFFFF);init_pwm1();while(1){     char buffer[32];float f;f = lm75_get_temperature();int k = f * 10;int m = k / 10;int n = k % 10;sprintf(buffer, "%d.%d", m, n);lcd_show_string(100, 100, 16 * strlen(buffer), 32, 32, buffer);delays(100);global_ratio += 0.05;if(global_ratio > 1){global_ratio = 0;}set_ratio();}return 0;
}4.start.S
修改bug,stmfd sp!, {r0-r12, lr}往前放
.global _start_start:ldr pc, =_reset_handlerldr pc, =_undefine_handlerldr pc, =_svc_handlerldr pc, =_prefetch_abort_handlerldr pc, =_data_abort_handlerldr pc, =_reserved_handlerldr pc, =_irq_handlerldr pc, =_fiq_handler_undefine_handler:ldr pc, =_undefine_handler_svc_handler:ldr pc, =_svc_handler_prefetch_abort_handler:ldr pc, =_prefetch_abort_handler_data_abort_handler:ldr pc, =_data_abort_handler_reserved_handler:ldr pc, =_reserved_handler_irq_handler:subs lr, lr, #4stmfd sp!, {r0-r12, lr}mrc p15, 4, r1, c15, c0, 0add r1, r1, #0x2000ldr r0, [r1, #0x0C]stmfd sp!, {r0, r1}cps #0x1Fstmfd sp!, {lr}bl system_interrupt_handlerldmfd sp!, {lr}cps #0x12ldmfd sp!, {r0, r1}str r0, [r1, #0x10]ldmfd sp!, {r0-r12, pc}^_fiq_handler:ldr pc, =_fiq_handler_reset_handler:cps #0x12ldr sp, =0x86000000cps #0x1F  cpsie ildr sp, =0x84000000bl _enable_icahcebl _set_vbarbl _bss_clearbl _enable_fpub main_enable_fpu:// 1. 设置CPACR寄存器使能FPU访问mrc     p15, 0, r0, c1, c0, 2   // 读取CPACRorr     r0, r0, #(0xF << 20)    // 设置CP10和CP11为完全访问mcr     p15, 0, r0, c1, c0, 2   // 写回CPACR// 2. 使能FPUmov     r0, #0x40000000         // 设置FPEXC的EN位vmsr    fpexc, r0               // 写入FPEXC// 3. 配置FPSCRmov     r0, #0x00000000         // 清除所有标志位vmsr    fpscr, r0               // 写入FPSCRbx      lr                      // 返回_enable_icahce:mrc p15, 0, r0, c1, c0, 0bic r0, r0, #(1 << 13)orr r0, r0, #(1 << 12)mcr p15, 0, r0, c1, c0, 0bx lr_set_vbar:ldr r0, =0x87800000mcr p15, 0, r0, c12, c0, 0bx lr_bss_clear:ldr r0, =__bss_startldr r2, =__bss_end
loop:mov r1, #0str r1, [r0]add r0, r0, #4cmp r0, r2blt loopbx lrfinished:b finished