当前位置:首页 > 嵌入式 > 嵌入式硬件

  引言

  环境光传感器(ALS)集成电路正越来越多地用于各种显示器和照明设备,以节省电能,改善用户体验。借助ALS解决方案,系统设计师可根据环境光强度,自动调节显示屏的亮度。因为背光照明的耗电量在系统的总耗电量中占据很大的比例,实行动态的背光亮度控制,可节省大量的电能。此外,它还能够改善用户体验,让显示屏亮度根据环境光条件自行调整到最佳状态。

  系统实现需要三大部分:监测环境光强的光传感器、数据处理装置(通常是微控制器)、控制背光输入电流的执行器。

  背光控制:环境光传感器

  图1是实施背光控制的系统示范框图。在这套组合中,光传感器是关键的组成部分,因为它要向系统的其他模块提供环境光强信息。光传感器必须具备将光信号转换成电信号的信号转换器(譬如光电二极管或CdS光敏电阻)和信号放大和/或调节装置以及模/数转换器(ADC)。

图1. 实施背光控制的系统框图

  图2所示为分立光电二极管电路,从图中可以看出,该电路需要一个或多个运算放大器:一个用于电流到电压的转换,可能还需要一级放大,提供附加增益。它还包括一些分支电路,用于供电,确保高度可靠的信号链。而在空间极其宝贵的应用中,所需元件的数量过多可能导致空间受限问题。

图2. 光电二极管电路分立设计

  这里还存在一个更细微的问题。具体而言,理想情况下,应确保环境光的测量模拟了人眼对光线的响应机制。这通常借助CIE提供的视觉亮度曲线(图3)。然而,光电二极管很少能够完全模拟这种响应机制,因为它们通常具有很高的红外(IR)灵敏度。在IR强度较大的光照条件(譬如白炽灯或日光)下,这种红外灵敏度会造成错误地判断光线强度。

  解决上述问题的方法之一是使用两个光电二极管:一个采用对可见光和红外光都很敏感的元件,另一个采用只对红外光敏感的元件。最终用前者的响应值减去后者的响应值,将红外干扰降至最小,获得准确的可见光响应。

  这种解决方案虽然有效,却增加了分立电路的占用空间。通常还很难、甚至不可能让两个分立的光电二极管配合得足够紧密,以实现消除红外干扰的目的。如果不配备精密放大器(譬如对数放大器),动态范围可能很小。换句话说,很难利用这种组合获得可重复的结果。

图3. CIE曲线和典型的光电二极管

  高集成度解决方案不仅能够获得比人眼光学系统更真实的光强数据,还能够节省大量空间。MAX9635、MAX44009等环境光传感器,可将所有信号调节和模/数转换器集成在一个小封装(2mm x 2mm UTDFN封装)内,从而在空间受限应用中有效节省电路板面积。

  图4提供了MAX44009的功能框图,采用I?C通信协议,使其与微控制器的连接方式更简单,数据传输速度更快。除此之外,该解决方案的高集成特性使其能够置于柔性电缆,安装在离主电路板距离合适的位置。

图4. MAX44009功能框图

  背光控制:调节显示屏亮度

  该控制方案的第二部分是调节显示屏的背光亮度。这可通过多种方式实现,具体取决于设备中的显示屏模块。有两种最简单的方式,一种是借助脉冲宽度调制(PWM)方案的直接调节方式,另一种是采用显示屏控制器的间接调节方式。

  许多显示屏模块如今都配有一个集成控制器,用户可以通过向控制器发送串行命令,直接设置背光亮度。如果显示屏模块未配备集成控制器,还可安装一个简单的背光控制执行器,控制显示屏后面用于背光照明的白光LED灯的输入电流。实现这种控制的一种简单办法是:直接给LED串联一个场效应晶体管(FET),使用PWM信号快速打开、关闭FET (图5)。然而,也可以利用单一芯片(用于LED控制的MAX1698升压转换器)准确、可靠地调节(图6),请参考应用笔记3866“Low-power PWM output controls LED brightness”,获取详细信息。

图5. 简单的PMW控制电路

图6. 基于MAX1698的LED亮度调节器

  背光控制:建立连接

  最后一步就是在传感器和执行器之间建立连接,通过微控制器实现。有人可能首先要问:“环境光强如何映射到背光亮度?”事实上,有些文献专门介绍了相关方案。其中一种映射方式是,Microsoft?针对运行Windows? 7?操作系统的计算机提出的。图7所示曲线是由Microsoft提供的,它可以将环境光强度映射到显示屏亮度(以全部亮度的百分比表示)。

图7. 将环境光强映射为最佳显示屏亮度的曲线示例

  这种特殊曲线可以用以下函数表示:

  如果设备采用的是已集成亮度控制功能的LCD控制芯片,就可通过向芯片发送指令,轻松设置背光亮度。如果设备采用的是PWM直接控制亮度,则要考虑如何将比例信号映射至显示屏亮度。

  在MAX1698示例中,根据其产品说明书的介绍,可以将驱动电流映射为电压。通过这个示例,我们可以假设LED电流强度几乎与其电流呈线性关系。这样,我们就可以在上述等式中乘上一个系数,计算出PWM所映射的有效电压,该电压再被映射至LED电流,最后转化成显示屏亮度。

  方案实施

  最好不要从一个亮度级直接跳转到另一个亮度级,而是平滑上调和下调背光亮度,确保不同亮度等级之间无缝过渡。为了达到这一目的,最好采用带有固定或不同亮度步长、可逐步调节亮度的定时中断,也可采用带有可控制LED输入电流的PWM值的定时中断,或者是能够发送到显示屏控制器的串行指令的定时中断。图8提供了这种算法的一个示例。

图8. 步进式亮度调节的算法示例

  另一个问题是,系统响应环境光强变化的速度。我们应尽量避免过快地改变亮度等级。这是因为光强的瞬间变化(譬如一扇窗户打开或瞬间有一束光扫过)可能导致背光亮度发生不必要的变化,这往往会造成用户感觉不适。并且,较长的响应时间还有助于减少微控制器对光传感器的检测次数,从而可以释放一定的微控制器资源。

  最初级的方法就是每隔一两秒钟检查一次光传感器,然后相应地调整背光亮度。更好的方法是,只有光线强度偏离特定范围一定时间后,才对背光亮度进行调节。譬如,如果正常光强是200lux,我们可能只会在光强降到180lux以下或升至220lux以上,而且持续时间超过数秒的情况下才调节亮度。幸运的是,MAX9635和MAX44009都集成了中断引脚和阈值寄存器,可轻松实现这个目的。请参考应用笔记4786“MAX9635环境光传感器的接口程序”,获取更多详细信息。

  附录:源代码

#define MAX44009_ADDR0x96// begin definition of slave addresses for MAX44009#define INT_STATUS0x00#define INT_ENABLE0.01#define CONFIG_REG0x02#define high_BYTE0x03#define LOW_BYTE0x04#define THRESH_HIGH0x05#define THRESH_LOW0x06#define THRESH_TIMER0x07// end definition of slave addresses for MAX44009 extern float SCALE_FACTOR;// captures scaling factors to map from % brightness to PWMfloat currentBright_pct;// the current screen brightness, in % of maximumfloat desiredBright_pct;// the desired screen brightness, in % of maximumfloat stepSize;// the step size to use to go from the current // brightness to the desired brightnessuint8 lightReadingCounter; /** *Function:SetPWMDutyCycle * *Arguments:uint16 dc - desired duty cycle * *Returns:none * *Description:Sets the duty cycle of a 16-bit PWM, assuming that in this  *architecture, 0x0000 = 0% duty cycle * 0x7FFF = 50% and 0xFFFF = 100%**/extern void SetPWMDutyCycle(uint16 dc); /** *Function:I2C_WriteByte * *Arguments:uint8 slaveAddr - address of the slave device *uint8 command - destination register in slave device *uint8 data - data to write to the register * *Returns:ACK bit * *Description:Performs necessary functions to send one byte of data to a  *specified register in a specific device on the I2C bus**/uint8 2C_WriteByte(uint8 slaveAddr, uint8 command, uint8 data); /** *Function:I2C_ReadByte * * Arguments:uint8 slaveAddr - address of the slave device *uint8 command - destination register in slave device *uint8 *data - pointer data to read from the register *  *Returns:ACK bit * *Description:Performs necessary functions to get one byte of data from a  *specified register in a specific deviceon the I2C bus**/uint8 I2C_ReadByte(uint8 slaveAddr, uint8 command, uint8* data); /** *Function:getPctBrightFromLuxReading * *Arguments:float lux - the pre-computed ambient light level * *Returns:The % of maximum brightness to which the backlight should be set  *given the ambient light (0 to 1.0) * *Description:Uses a function to map the ambient light level to a backlight  *brightness by using a predetermined function**/float getPctBrightFromLuxReading(float lux); /** *Function:mapPctBrighttoPWM * *Arguments:float pct * *Returns:PWM counts needed to achieve the specified % brightness (as  *determined by some scaling factors)**/uint16 mapPctBrighttoPWM(float pct); /** *Function:getLightLevel * *Arguments:n/a * *Returns:the ambient light level, in lux * *Description:Reads both the light registers on the device and returns the  *computed light level**/float getLightLevel(void); /** *Function:stepBrightness * *Arguments:n/a * *Returns:n/a * *Description:This function would be called by an interrupt. It looks at the  *current brightness setting, then the desired brightness setting.  *If there is a difference between the two, the current brightness  *setting is stepped closer to its goal.**/void stepBrightness(void); /** *Function:timerISR * *Arguments:n/a * *Returns:n/a * *Description:An interrupt service routine which fires every 100ms or so. This  *handles all the ambient light sensor and backlight *control code.**/void timerISR(void); void main() {SetupMicro();// some subroutine which initializes this CPUI2C_WriteByte(MAX44009_ADDR, CONFIG_REG, 0x80);// set to run continuouslylightReadingCounter = 0;stepSize = .01;currentBright_pct = 0.5;desiredBright_pct = 0.5;SetPWMDutyCycle(mapPctBrighttoPWM(currentBright_pct));InitializeTimerInterrupt();// set this to fire every 100mswhile(1) {// do whatever else you need here, the LCD control is done in interruptsIdle();}} // main routine // the point at which the function clips to 100%#define MAXIMUM_LUX_BREAKPOINT1254.0float getPctBrightFromLuxReading(float lux) {if (lux > MAXIMUM_LUX_BREAKPOINT)return 1.0;elsereturn (9.9323*log(x) + 27.059)/100.0;} // getPctBrightFromLuxReading uint16 mapPctBrighttoPWM(float pct) {return (uint16)(0xFFFF * pct * SCALE_FACTOR);} // mapPctBrighttoPWM float getLightLevel(void) {uint8* lowByte;uint8* highByte;uint8 exponent;uint8 mantissa;float result;I2C_ReadByte(MAX44009_ADDR, HIGH_BYTE, highByte);I2C_ReadByte(MAX44009_ADDR, LOW_BYTE, lowByte);exponent = (highByte & 0xF0) >> 4;// upper four bits of high byte registermantissa = (highByte & 0x0F) << 4;// lower four bits of high byte register =    // upper four bits of mantissamantissa += lowByte & 0x0F;   // lower four bits of low byte register =   // lower four bits of mantissaresult = mantissa * (1 << exponent) * 0.045;return result;} //getLightLevel void stepBrightness(void) { // if current is at desired, don't do anythingif (currentBright_pct == desiredBright_pct)return;// is the current brightness above the desired brightness?else if (currentBright_pct > desiredBright_pct) {// is the difference between the two less than one step?if ( (currentBright_pct-stepSize) < desiredBright_pct)currentBright_pct = desiredBright_pct;elsecurrentBright_pct -= stepSize;} // else ifelse if (currentBright_pct < desiredBright_pct) {// is the difference between the two less than one step?if ( (currentBright_pct+stepSize) > desiredBright_pct)currentBright_pct = desiredBright_pct;elsecurrentBright_pct += stepSize;} // else ifSetPWMDutyCycle(mapPctBrighttoPWM(currentBright_pct));return;} // stepBrightness void timerISR(void) {float lux;float pctDiff;stepBrightness();if (lightReadingCounter)lightReadingCounter--;else {lightReadingCounter = 20;// 2 second delaylux = getLightLevel();desiredBright_pct = getPctBrightFromLuxReading(lux);pctDiff = abs(desiredBright_pct - currentBright_pct);stepSize = (pctDiff <= 0.01) ? 0.01:pctDiff/10;} // elseClearInterruptFlag();} // timerISR


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭