众所周知,PWM输出在我们的工程应用中是一个十分基础的模块,具有很强大的功用。在正点原子的官方教程中,也有专门的实验来进行教学。下面,我将将把实验过程中的笔记和我的个人的一些想法分享给大家。
一、PWM简介 1、6ULL的PWM是16位计数器, 2、有4个16位的FIFO。 3、一个12位的分频器 4、正点原子LCD屏幕的背光IO连接到了GPIO1_IO08上。GPIO1_IO08可以复用位PWM1_OUT信号。 PWM计数器从0X0000开始计数,当计数器的值等于PWMPR+1的时候定时器就会重新开始下一个周期的运行,因此PWMPR寄存器控制着PWM频率。 FIFO保存着采样值,当我们向PWMSAR寄存器写采样值的时候会写道FIFO里面,内每当读取一次PWMSAR寄存器,FIFO里面的数据都会减一,或者每产生一个PWM信号,FIFO的数据也会减一。直到FIFO为空,那么就无法再产生PWM信号。FIFO为空的时候会产生中断,我们可以在中断中向FIFO写入采样数据,也就是向PWMSAR写数据。 PWMCR寄存器,bit0是PWM使能信号,bit2:1设置为0,每个周期使用FIFO里面的一个数据。Bit15:4,PWM分频设置,可以设置0~4095,对应1~4096分频。Bit17:16设置PWM时钟源,设置为1,表示使用ipg_clk=66MHz。bit19:18,设置为0。Bit27:26,设置为01,表示当FIFO里面空余位置大于2的时候FIFO为空。 PWMIR寄存器,bit0设置为1,开启FIFO空中断。 二、实验程序编写#include "bsp_backlight.h" #include "bsp_int.h" struct backlight_dev_struc backlight_dev; /* 初始化背光 */ void backlight_init(void) { unsigned char i = 0; /* 1、IO初始化 */ IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT , 0); /*复用为PWM1_OUT */ IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT , 0Xb090); /* 2、PWM初始化 * PWM时钟源=66MHz,设置66分频,因此PWM时钟频率为1MHz * */ PWM1->PWMCR = 0; /* 清零 */ PWM1->PWMCR |= (1 << 16) | (65 << 4) | (1 << 26); pwm1_setperiod_value(1000); /* PWM频率为1Khz */ /* 3、设置默认站空比 */ backlight_dev.pwm_duty = 50; for(i = 0; i < 4; i++) { pwm1_setduty(backlight_dev.pwm_duty); } /*4、使能FIFO空中断 */ PWM1->PWMIR = 1 << 0; /* 使能PWM1的FIFO空中断 */ GIC_EnableIRQ(PWM1_IRQn); system_register_irqhandler(PWM1_IRQn, (system_irq_handler_t)pwm1_irqhandler, NULL); PWM1->PWMSR = 0xff; /* 5、打开PWM */ PWM1->PWMCR |= 1 << 0; } /* 设置PR寄存器 */ void pwm1_setperiod_value(unsigned int value) { unsigned int regvalue = 0; if(value < 2) regvalue = 2; else regvalue = value - 2; PWM1->PWMPR = (regvalue & 0XFFFF); } /* 设置站空比duty=0~100 */ void pwm1_setduty(unsigned char duty) { unsigned short period = 0; unsigned short sample = 0; backlight_dev.pwm_duty = duty; period = PWM1->PWMPR + 2; sample = (unsigned short)(period * backlight_dev.pwm_duty / 100.0f); PWM1->PWMSAR = (sample & 0xffff); } /* 中断处理函数 */ void pwm1_irqhandler(unsigned int gicciar, void *param) { if(PWM1->PWMSR & (1 << 3)) /* FIFO空中断 */ { pwm1_setduty(backlight_dev.pwm_duty); PWM1->PWMSR |= 1 << 3; /* 中断标志位清零 */ } } Main.c #include "main.h" #include "bsp_clk.h" #include "bsp_led.h" #include "bsp_delay.h" #include "bsp_beep.h" #include "bsp_key.h" #include "bsp_int.h" #include "bsp_exti.h" #include "bsp_epit.h" #include "bsp_keyfilter.h" #include "bsp_uart.h" #include "bsp_lcd.h" #include "bsp_rtc.h" #include "bsp_lcdapi.h" #include "bsp_ap3216c.h" #include "bsp_icm20608.h" #include "bsp_ft5426.h" #include "bsp_backlight.h" #include "stdio.h" /* * @description : 使能I.MX6U的硬件NEON和FPU * @param : 无 * @return : 无 */ void imx6ul_hardfpu_enable(void) { uint32_t cpacr; uint32_t fpexc; /* 使能NEON和FPU */ cpacr = __get_CPACR(); cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk)) | (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos); __set_CPACR(cpacr); fpexc = __get_FPEXC(); fpexc |= 0x40000000UL; __set_FPEXC(fpexc); } int main(void) { unsigned char duty; unsigned char key = 0; unsigned char i = 0; unsigned char state = OFF; imx6ul_hardfpu_enable(); /* 开启硬件浮点运算及ENON */ int_init(); /* 初始化中断 */ imx6u_clkinit(); /* 初始化系统时钟 */ delay_init(); /* 延时初始化 */ uart_init(); /* 初始化串口 */ clk_enable(); /* 使能外设时钟 */ led_init(); /* 初始化LED */ beep_init(); /* 初始化奉命器 */ key_init(); /* 初始化按键 */ lcd_init(); /* 初始化LCD */ backlight_init(); /* 初始化背光*/ tftlcd_dev.forecolor = LCD_RED; lcd_show_string(50, 10, 400, 24, 24, (char*)"IMX6U-ZERO BACKLIGHT TEST"); lcd_show_string(50, 40, 200, 16, 16, (char*)"BACKLIGHT TEST"); lcd_show_string(50, 60, 200, 16, 16, (char*)"ATOM@ALIENTEK"); lcd_show_string(50, 80, 200, 16, 16, (char*)"2019/3/27"); duty = 10; pwm1_setduty(duty); while(1) { key = key_getvalue(); if(key == KEY0_VALUE) { duty += 10; if(duty > 100) duty = 0; printf("PWM1 Duty = %d\r\n", duty); pwm1_setduty(duty); } delay_ms(10); i++; if(i == 50) { i = 0; state = !state; led_switch(LED0,state); } } return 0; }
|