当前位置: 首页 > article >正文

42. 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分频设置,可以设置04095,对应14096分频。Bit17:16设置PWM时钟源,设置为1,表示使用ipg_clk=66MHz。bit19:18,设置为0。Bit27:26,设置为01,表示当FIFO里面空余位置大于2的时候FIFO为空。
PWMIR寄存器,bit0设置为1,开启FIFO空中断。

二、实验程序编写

//bsp_backlight.c

#include "bsp_backlight.h"
#include "bsp_int.h"
#include "stdio.h"


/* 背光设备 */
struct backlight_dev_struc backlight_dev;

/*
 * @description : pwm1中断处理函数
 * @param       : 无
 * @return      : 无
 */
void pwm1_irqhandler(void)
{

    if(PWM1->PWMSR & (1 << 3))  /* FIFO为空中断 */
    {
        /* 将占空比信息写入到FIFO中,其实就是设置占空比 */
        pwm1_setduty(backlight_dev.pwm_duty); 
        PWM1->PWMSR |= (1 << 3); /* 写1清除中断标志位 */ 
    }
}

/*
 * @description : 初始化背光PWM
 * @param       : 无
 * @return      : 无
 */
void backlight_init(void)
{
    unsigned char i = 0;
    
    /* 1、背光PWM IO初始化 */
    IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT, 0); /* 复用为PWM1_OUT */

    /* 配置PWM IO属性   
     *bit 16:0 HYS关闭
     *bit [15:14]: 10 100K上拉
     *bit [13]: 1 pull功能
     *bit [12]: 1 pull/keeper使能
     *bit [11]: 0 关闭开路输出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 010 驱动能力为R0/2
     *bit [0]: 0 低转换率
     */
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT, 0XB090);
    
    /* 2、初始化PWM1        */
    /*
     * 初始化寄存器PWMCR
     * bit[27:26]   : 01  当FIFO中空余位置大于等于2的时候FIFO空标志值位
     * bit[25]      :
 0  停止模式下PWM不工作
     * bit[24]      : 0   休眠模式下PWM不工作
     * bit[23]      : 0   等待模式下PWM不工作
     * bit[22]      : 0   调试模式下PWM不工作
     * bit[21]      : 0   关闭字节交换
     * bit[20]      : 0   关闭半字数据交换
     * bit[19:18]   : 00  PWM输出引脚在计数器重新计数的时候输出高电平
     *                    在计数器计数值达到比较值以后输出低电平
     * bit[17:16]   : 01  PWM时钟源选择IPG CLK = 66MHz
     * bit[15:4]    : 65  分频系数为65+1=66,PWM时钟源 = 66MHZ/66=1MHz
     * bit[3]       : 0   PWM不复位
     * bit[2:1]     : 00  FIFO中的sample数据每个只能使用一次。
     * bit[0]       : 0   先关闭PWM,后面再使能
     */
    PWM1->PWMCR = 0;    /* 寄存器先清零 */
    PWM1->PWMCR |= (1 << 26) | (1 << 16) | (65 << 4);

    /* 设置PWM周期为1000,那么PWM频率就是1M/1000 = 1KHz。 */
    pwm1_setperiod_value(1000);

    /* 设置占空比,默认50%占空比   ,写四次是因为有4个FIFO */
    backlight_dev.pwm_duty = 50;
    for(i = 0; i < 4; i++)
    {
        pwm1_setduty(backlight_dev.pwm_duty);   
    }
    
    /* 使能FIFO空中断,设置寄存器PWMIR寄存器的bit0为1 */
    PWM1->PWMIR |= 1 << 0;
    system_register_irqhandler(PWM1_IRQn, (system_irq_handler_t)pwm1_irqhandler, NULL); /* 注册中断服务函数 */
    GIC_EnableIRQ(PWM1_IRQn);   /* 使能GIC中对应的中断 */
    PWM1->PWMSR = 0;            /* PWM中断状态寄存器清零 */
    
    pwm1_enable();              /* 使能PWM1 */

    
}

/*
 * @description : 使能PWM
 * @param       : 无
 * @return      : 无
 */
void pwm1_enable(void)
{
    PWM1->PWMCR |= 1 << 0;   
}

/*
 * @description     : 设置Sample寄存器,Sample数据会写入到FIFO中,
 *                    所谓的Sample寄存器,就相当于比较寄存器,假如PWMCR中的POUTC
 *                    设置为00的时候。当PWM计数器中的计数值小于Sample的时候
 *                    就会输出高电平,当PWM计数器值大于Sample的时候输出底电平,
 *                    因此可以通过设置Sample寄存器来设置占空比
 * @param -  value  : 寄存器值,范围0~0XFFFF
 * @return          : 无
 */
void pwm1_setsample_value(unsigned int value)
{
    PWM1->PWMSAR = (value & 0XFFFF);    
}

/*
 * @description     : 设置PWM周期,就是设置寄存器PWMPR,PWM周期公式如下
 *                    PWM_FRE = PWM_CLK / (PERIOD + 2), 比如当前PWM_CLK=1MHz
 *                    要产生1KHz的PWM,那么PERIOD = 1000000/1K - 2 =   998
 * @param -  value  : 周期值,范围0~0XFFFF
 * @return          : 无
 */
void pwm1_setperiod_value(unsigned int value)
{
    unsigned int regvalue = 0;

    if(value < 2)
        regvalue = 2;
    else 
        regvalue = value - 2;
    PWM1->PWMPR = (regvalue & 0XFFFF);
}

/*
 * @description     : 设置PWM占空比
 * @param -  value  : 占空比0~100,对应0%~100%
 * @return          : 无
 */
void pwm1_setduty(unsigned char duty)
{
    unsigned short preiod;
    unsigned short sample;

    backlight_dev.pwm_duty = duty;
    preiod = PWM1->PWMPR + 2;
    sample = preiod * backlight_dev.pwm_duty / 100;
    pwm1_setsample_value(sample);
}

//bsp_backlight.h

#ifndef _BACKLIGHT_H
#define _BACKLIGHT_H
#include "imx6ul.h"

/* 背光PWM结构体 */
struct backlight_dev_struc
{   
    unsigned char pwm_duty;     /* 占空比  */
};

/* 函数声明 */
void backlight_init(void);
void pwm1_enable(void);
void pwm1_setsample_value(unsigned int value);
void pwm1_setperiod_value(unsigned int value);
void pwm1_setduty(unsigned char duty);
void pwm1_irqhandler(void);

#endif

//main.c

#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"
#include "bsp_rtc.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);
}

/*
 * @description : main函数
 * @param       : 无
 * @return      : 无
 */
int main(void)
{
    unsigned char keyvalue = 0;
    unsigned char i = 0;
    unsigned char state = OFF;
    unsigned char duty = 0;
    
    imx6ul_hardfpu_enable();    /* 使能I.MX6U的硬件浮点            */
    int_init();                 /* 初始化中断(一定要最先调用!) */
    imx6u_clkinit();            /* 初始化系统时钟                  */
    delay_init();               /* 初始化延时                    */
    clk_enable();               /* 使能所有的时钟                  */
    led_init();                 /* 初始化led                   */
    beep_init();                /* 初始化beep                  */
    uart_init();                /* 初始化串口,波特率115200 */
    lcd_init();                 /* 初始化LCD                   */
    backlight_init();           /* 初始化背光PWM                 */ 

    tftlcd_dev.forecolor = LCD_RED;
    lcd_show_string(50, 10, 400, 24, 24, (char*)"ZERO-IMX6U BACKLIGHT PWM TEST");  
    lcd_show_string(50, 40, 200, 16, 16, (char*)"ATOM@ALIENTEK");  
    lcd_show_string(50, 60, 200, 16, 16, (char*)"2019/3/27");   
    lcd_show_string(50, 90, 400, 16, 16, (char*)"PWM Duty:   %");  
    tftlcd_dev.forecolor = LCD_BLUE;

    /* 设置默认占空比 10% */
    duty = 10;
    lcd_shownum(50 + 72, 90, duty, 3, 16);
    pwm1_setduty(duty); 
    
    while(1)                    
    {
        keyvalue = key_getvalue();
        if(keyvalue == KEY0_VALUE)
        {
            duty += 10;             /* 占空比加10% */
            if(duty > 100)          /* 如果占空比超过100%,重新从10%开始 */
                duty = 10;
            lcd_shownum(50 + 72, 90, duty, 3, 16);
            pwm1_setduty(duty);     /* 设置占空比 */
        }
        
        delayms(10);
        i++;
        if(i == 50)
        {   
            i = 0;
            state = !state;
            led_switch(LED0,state); 
        }
    }
    return 0;
}

http://www.kler.cn/a/529315.html

相关文章:

  • 安装anaconda3 后 电脑如何单独运行python,python还需要独立安装吗?
  • 使用真实 Elasticsearch 进行高级集成测试
  • 【上篇】-分两篇步骤介绍-如何用topview生成和自定义数字人-关于AI的使用和应用-如何生成数字人-优雅草卓伊凡-如何生成AI数字人
  • 三、js笔记
  • 神经网络的数据流动过程(张量的转换和输出)
  • FreeRTOS从入门到精通 第十五章(事件标志组)
  • HAL库W25Qxx系列芯片驱动
  • C++STL之stack和queue容器(详细+通俗易懂)
  • 课设:【ID0022】火车票售票管理系统(前端)
  • Qt 5.14.2 学习记录 —— 이십이 QSS
  • 【AI文章解读】《No, DeepSeek Is Not A ‘Sputnik Moment’》
  • 信息学奥赛一本通 ybt 1608:【 例 3】任务安排 3 | 洛谷 P5785 [SDOI2012] 任务安排
  • 制造业数字化转型:从标准化设备到数据与智能算法的共生革命
  • 《基于单中心损失监督的频率感知判别特征学习用于人脸伪造检测 》学习笔记
  • PostgreSQL 数据库视图基础操作
  • tf.Keras (tf-1.15)使用记录1-基础模型创建的两种方法
  • 【股票数据API接口48】如何获取股票最新分时BOLL数据之Python、Java等多种主流语言实例代码演示通过股票数据接口获取数据
  • 【Python】理解Python中的协程和生成器:从yield到async
  • PostgreSQL 数据库备份与还原
  • 如何使用SliverList组件
  • 数据分析系列--⑨RapidMiner训练集、测试集、验证集划分
  • 拉格朗日定理
  • C++编程语言:抽象机制:模板(Bjarne Stroustrup)
  • 【网站建设:HTTPS - 如何生成免费SSL证书,并自动更新】
  • 【自开发工具介绍】SQLSERVER的ImpDp和ExpDp工具01
  • RabbitMQ持久化队列配置修改问题