应用程序在低功率应用中,由于电流供应有限,同时点亮整组LED以达到最大亮度可能是不可能的。为了获得最佳亮度,必须有效地管理每个LED从低功率电源流出的功率。这就需要一种功率管理技术,即在特定时间内,仅对LED组中的一组LED进行供电。在达到所需亮度期间,其他LED组将不会在视觉上被察觉。.


为了计算给定时间间隔内所需的 LED 数量,必须确定应用所需的可用功率和发光强度。应比较发光强度和直流电流特性,以选择具有所需强度的 LED。一旦确定了所需的 LED 数量,即可根据 LED 所需总电流与可用电流之比,为这些 LED 供电一段时间,具体如下:

 

一组 LED 的数量 = LED 所需的总电流 / 电源提供的总电流。
必须调整 LED 组的开关频率,使导通时间足够长,能够完全照亮整个 LED 组;同时,导通时间应限制在 LED 组开始明显变暗之前所需的时间。导通时间限制了可以通过控制时间间隔来控制的额外 LED 组的数量。


该技术可低成本实现,仅需时钟源、用于控制 LED 阵列的数字触发器以及用于检测启动状态的或门(通过简单的开/关开关)。图 1 显示了用于控制四个 LED 阵列的 D 触发器配置框图。.


应用1初始状态下,触发器处于静态,需要一个至少持续一个时钟周期的触发脉冲。该脉冲可在时钟上升沿被第一个触发器检测到。触发信号必须是瞬时的,且持续时间不能超过一个时钟周期;否则,触发器的前两个输出将同时置位。由于供电电流有限,照明应用将无法正常工作。在这种配置下,一组 LED 灯在每个时钟周期的上升沿都会完全点亮,人眼会感觉所有 LED 灯同时完全点亮。.


然而,这种实现方式较为单调,缺乏设计灵活性,只有简单的开/关状态。该电路可能适用于液晶背光等应用,但如果需要调光或生成序列,基于微控制器的电路则能提供最大的灵活性,且对整体成本的影响最小。由于微控制器可以控制每个LED组,并能检测用户输入以进行调光控制和序列选择,因此电路结构更简单,所需的元件更少。.


低成本、低引脚数的8位微控制器,例如Microchip的PIC10F或PIC12F系列,搭配I/O端口扩展器(例如Microchip的MCP23018),可以提供经济的解决方案。当照明电路远离微控制器时,I/O扩展还可以用于控制LED。.


应用2I/O端口扩展器用于扩展微控制器的I/O端口。在本应用中,微控制器使用I2C™协议控制I/O扩展器来控制LED的亮灭。微控制器的I/O引脚可用于通过按钮感应用户输入,或通过内置的A/D转换器感应电位器电平,从而实现调光控制。.


I/O 扩展器提供开漏输出或推挽输出配置。微控制器可在 3.3V 或更低电压下工作,因此具有开漏输出的 I/O 扩展器非常适合此应用。其优势在于,只要微控制器和 I/O 扩展器的供电电压较低,它就允许 LED 在 5V 或更高电压下工作。MCP23018 是一款 16 位 I/O 端口扩展器,具有开漏输出和 I2C 接口。图 2 显示了具有开漏输出的 I/O 扩展器的电路图,其输出电压高于微控制器的供电电压。.


当 I/O 端口设置为低电平时,I/O 放大器两端的电压为 0V,电流流过,使 LED 正向偏置并导通。LED 偏置电阻根据所需的亮度限制流过 LED 的电流,同时还起到开漏输出的上拉电阻作用。.


当I/O放大器的输出端口设置为高电平时,开漏输出进入截止或高阻抗状态,上拉电阻将I/O放大器端口的电压提升至5V。由于没有电流流过,LED处于截止状态。开漏配置的另一个优点是,当端口设置为高阻抗时,由于寄生电容的影响,LED需要更长时间才能关闭。这使得下一组LED的导通时间比类似的推挽输出应用略长。.


MCP23018 的 16 个 I/O 端口最多可控制 16 个 LED。当 LED 完全导通时,可通过控制 I/O 放大器的输出来限制流向 I/O 端口的电流。I/O 端口的低电平电压在 8.5mA 电流下最高可达 0.6V。如果电流超过 8.5mA,低电平电压将呈指数级增长。绝对最大电流为 25mA。.


例如,如果供电电流限制为 5V/50mA,其中 2mA 分配给微控制器、I/O 扩展器和用于用户输入检测的电阻,则剩余的可用电流可用于 LED 照明。如果 LED 在约 10mA 电流下的发光强度足够,则每组可以驱动四个 LED。在本例中,限流电阻的额定值约为 440Ω。.

 

void main (Void){
    initialize(); //初始化PICmicro外设,包括Timer0和I/O扩展器外设
    bank_counter = 0; //清除存储体计数器变量
    while(1){} //无限循环
   }
  void Interrupt int_service(void){
    TurnOffAll_LEDs(); //关闭所有先前点亮的LED的子程序
    I2C_start(); //I2C协议 - 启动信号子程序
    I2C_send(Comand_byte); //I2C协议 - 发送字节子程序

    如果 (bank_counter == bank1) { // bank1 是一个定义为 0 的常量
        I2C_send(Address_pionter_bank1n2); // 发送外设寄存器地址指针
        I2C_send('0000 1111'); // I2C 协议 – 发送 bank 状态(bank 1 开启,bank 2 关闭)
        bank_counter = bank_counter + 1;
    }
    如果 (bank_counter == bank2) { // bank1 是一个定义为 1 的常量
        I2C_send(Address_pionter_bank1n2); // 发送外设寄存器地址指针
        I2C_send('1111 0000'); // I2C 协议 – 发送 bank 状态(bank 2 开启,bank 1 关闭)
        bank_counter = bank_counter + 1;
    }
    如果 (bank_counter == bank3) { // bank1 是一个定义为 2 的常量
        I2C_send(Address_pionter_bank3n4); //发送外设寄存器地址指针
        I2C_send('0000 1111'); //I2C协议 – 发送存储体状态(存储体3开启,存储体4关闭)
        bank_counter = bank_counter + 1;
    }
    If(bank_counter == bank4){ // bank1 是一个定义为 3 的常量
        I2C_send(Address_pionter_bank3n4); //发送外设寄存器地址指针
        I2C_send('1111 0000'); //I2C协议 – 发送存储体状态(存储体4开启,存储体3关闭)
        bank_counter = 0;
    }
    I2C_stop(); //I2C协议 – 停止信号子程序
}   

伪代码 1:微控制器中断服务例程代码


   *
    *
    *
    如果(bank_counter == bank1){ // bank1 是一个定义为 0 的常量
        I2C_send(Address_pionter_bank1n2); // 发送外设寄存器地址指针
        Bank1n2_pattern = ~Bank1n2_pattern; // 使用 '~' 对变量取反
        I2C_send((Bank1n2_pattern | '0000 1111')); // I2C 协议 – 发送 bank 状态
                        //(使用 OR '|' 将 bank 1 设置为开启,bank 2 设置为关闭)
        bank_counter = bank_counter + 1;
    }
    *
    *
    *

伪代码 2:序列生成。.



    *
    *
    *    
    void Interrupt int_service(void){
        TurnOffAll_LEDs(); //关闭所有先前点亮的LED的子程序
        If (Delay_ON == ON){ // ON是一个常量,定义为1
            Update_Timer0_Counter(Timer0delay_interval); //更新Timer0的子程序
                             // Timer0delay_interval是一个常量,用于设置最小延迟
            Delay_Counter = Delay_Counter – 1; //延迟倒计时
            If(Delay_Counter == 0){
                Delay_ON = OFF; //清除延迟标志,以便下次中断
                Delay_Counter = Get_Delay_Counter(); //检测用户输入
                        并设置延迟计数器变量的
            }else{
                Delay_ON = ON; //保持延迟标志为ON
                Return; //退出中断服务程序
            }
        }

        I2C_start(); //I2C协议启动信号子程序
        I2C_send(Comand_byte); //I2C协议发送字节子程序
        If(bank_counter == bank1){ // bank1 是一个定义为 0 的常量
            I2C_send(Address_pionter_bank1n2); //发送外设寄存器地址指针
            Bank1n2_pattern = ~Bank1n2_pattern; //使用 '~' 对变量取反
            I2C_send((Bank1n2_pattern | '0000 1111')); //I2C协议发送 bank 状态
                                   //(使用 OR '|' 设置 bank 1 为开启,bank 2 为关闭)
            bank_counter = bank_counter + 1;
            delay_ON = ON; // 打开延迟标志
        }
    *
    *
    *

伪代码 3:实现延迟代码以可视化照明序列。.



图 1 所示的时序图可以用一段简短的微控制器指令代码来实现。例如,对于伪代码 1,主子程序可以是一个无限循环。在每个微控制器时间间隔(Timer0)内,中断服务程序会向 I/O 扩展器发送一条 I2C 指令,以驱动一个 LED 组。中断服务程序会计数或跟踪 LED 组的状态,例如该组当前是否导通,以及对应的 I/O 扩展器端口的电平(高电平或低电平)。初始状态下,或者在微控制器复位后,在第一个 Timer0 中断时,LED 组 1 被点亮。在第二个中断时,LED 组 1 被熄灭,LED 组 2 被点亮。然后,在第三个中断时,LED 组 2 被熄灭,LED 组 3 被点亮。最后,在第四个中断时,LED 组 1 被禁用,LED 组 4 被激活,并且 LED 组计数器变量被重置为零。下一次中断发生时,循环重复,激活存储体 1 并停用存储体 4。其他变量,例如 Command_byte、Address_pointer_bank1n2 和 Address_pointer_bank3n4,都是在启动文件中定义的常量。在这种实现方式中,电路会产生所需的光强度,看起来就像所有 LED 都由可用电源同时激活一样。.

 

void get_PWM_ratio(void) {
    Double PotScale; //用于存储ADC输出比例的局部变量
    Double PWM_Percentage; //用于存储PWM变化百分比的局部变量

    PotScale = (ADRESH)/16 + 1; // 缩放 ADC 输出高字节
    PWM_Percentage = 1/16 * PotScale; // 将输出从 0 缩放到 1,相当于 100%
    PWM_High = Frequency_counter * PWM_Percentage; // 设置 PWM 高电平 Timer0 值
    PWM_Low = Frequency_counter * (1 – PWM_Percentage); // 设置 PWM 低电平 Timer0 值
        // PWM_High 和 PWM_Low 是全局变量,
        // Frequency_counter 是 Timer0 的常量值,用于设置频率。
   }

伪代码 4:计算 PWM 比率的子程序

 

   *
   *
   *
   如果(bank_counter == bank1){ // bank1 是一个常量,定义为 0
    如果 (PWM_High_Low_flag == OFF){ //检查 PWM 状态标志
        get_PWM_ratio(); //检测用户输入的 PWM 比率
        Timer0_counter = 65535 – PWM_High; //设置 Timer0 计数器变量
        Update_Timer0_Counter(Timer0_counter); //更新 Timer0 的子程序
                    
        I2C_send(Address_pionter_bank1n2); //发送外设寄存器地址指针
        Bank1n2_pattern = ~Bank1n2_pattern; //使用 '~' 对变量取反
        I2C_send((Bank1n2_pattern | '0000 1111')); //I2C 协议 – 发送 bank 状态
                              //(使用 OR '|' 设置 bank 1 为开,bank 2 为关)
        PWM_High_Low_flag = ON; //设置标志位
        Delay_ON = OFF;

    }else{
        Timer0_counter = 65535 – PWM_Low; //设置 Timer0 计数器变量
        Update_Timer0_Counter(Timer0_counter); //更新 Timer0 的子程序
                            
        I2C_send(Address_pionter_bank1n2); //发送外设寄存器地址指针
        I2C_send('1111 1111')); //I2C 协议 – 关闭所有 LED
        bank_counter = bank_counter + 1;
        PWM_High_Low_flag = OFF; //清除标志
        Delay_ON = ON;
    }
   }
   *
   *
   *

伪代码 5:调整 PWM 比率的代码流程。.


调光控制和LED序列生成。
基于微控制器的应用程序可以生成有趣的灯光序列。I/O端口扩展器的输出状态从……加载。


RAM 中有两个字节的变量,分别名为 Bank1n2_pattern 和 Bank3n4_pattern。每个半字节对应一个存储区。预定义的查找表包含每个存储区对应的若干个 1 和 0 的序列。.


应用3为了持续监测开关按钮的状态,在微控制器代码中添加了一条 IF THEN 指令:即主子程序的无限循环“while”。当按钮被短暂按下时,会从查找表中加载一个序列到 RAM 的两个字节中,分别命名为 Bank1n2_pattern 和 Bank3n4_pattern。当 Timer0 中断发生时,新的序列会被发送到 I/O 扩展器,LED 会根据该序列点亮。只要用户短暂按下按钮,主子程序就会遍历查找表。要显示另一个灯光序列,只需发送前一个序列的补码即可。例如,如果 bank1 中的序列是“0101”,则其补码为“1010”,如伪代码 2 所示,伪代码 2 是伪代码 1 的一个片段。.


然而,在用于开关存储体的 IF THEN 指令执行之前,必须在中断子程序中添加一个延迟,以便目视检查交替序列。该延迟由 Delay_ON 标志产生,这样在下一次中断中,只需减去延迟计数器即可计算延迟期间的中断次数。用户还可以使用电位器选择延迟值,电位器的端子连接到集成在微控制器中的 A/D 转换器的输入端。A/D 转换器输出的数字数据通过检测高四位(提供 16 个电平)进行缩放,从而实现从最小延迟到最大延迟的设置。通过检测高五位(即 32 个电平),可以进行更精确的调整。最大延迟是 LED 闪烁的最慢速率,而最小延迟则使所有 LED 看起来都亮着。图 3 显示了延迟 tDELAY 的位置。.


为了控制每个灯组的时间间隔,调光控制采用脉冲宽度调制 (PWM)。Timer0 中断持续时间有两个值:长持续时间和短持续时间,这两个值与 PWM 百分比成正比,PWM 百分比由一个旋转电位器调节,该电位器的中心端连接到 A/D 转换器的输入端。可以通过选择 A/D 转换器的高 4 位或 5 位来调节分辨率级别。Timer0 计数器的位置根据 A/D 转换器的数据按比例和刻度进行调整,其中 100% PWM 对应于计数器的最大位置(完全点亮),0% 对应于最小或最低调光级别。伪代码 4 显示了 16 级 PWM 的刻度方程,图 3 显示了 PWM、tPWM_LOW 和 tPWM_HIGH 期间的时序图。
中断服务例程必须更新 Timer0 计数器的位置以迎接下一次中断。它还必须检测 PWM 信号是长信号还是短信号。因此,必须添加一些指令来检测电位器电平,以便使用伪代码 4 中所示的 PWM_High 和 PWM_Low 值来调光控制和按比例缩放 Timer0 计数器位置。伪代码 5 显示了调整 PWM 的代码;使用 IF THEN 指令来检测 PWM 状态。


这种方法也可以在带有额外程序存储器的中端 8 位微控制器上实现,例如 Microchip 的 PIC16F 系列。升级后,主子程序可以处理更高级的照明序列,例如连续运动灯光。微控制器的 Timer1 模块可用于改变持续时间,并且 RAM 中的两个字节会更新以适应连续运动序列。.


设计师们一直在寻找降低成本而不影响性能的新方法。目前已有多种方法可以高效控制用于液晶背光或灯光序列应用中的LED灯组,从而实现高效照明。在低功耗应用中,可以通过管理每个LED灯组的定时间隔来控制LED。此外,低引脚微控制器和I/O端口扩展器为照明解决方案提供了一种低成本且设计更灵活的替代方案。.

作者:

Ezana Haile,Microchip Technology Inc.模拟和接口产品部首席应用工程师.

更多信息或报价