我们使用手机时,经常会发现手机在不通环境下屏幕的背光亮度不一样。其实就是开启了自动背光调节功能。原理就是:光感获取环境光的值,然后背光根据一个环境光的曲线来调整背光的值。这个环境光曲线每家不一样,不同用户感知的效果也不一样。我们这里主要分享光感驱动部分。
下面以ISL29023 为例
1. 硬件连接
拿到规格书,第一步,确定管脚的描述定义,找到和主芯片通信的部分,电源相关PIN(VCC,GND), 中断,复杂的还需要时钟信号。在这里就是电源,中断以及IIC。
2.通信地址
硬件确认连接正常后,就需要确定通信的地址。该光感模组需要HW单独配置I2C地址,可以直接从datasheet 中获取。
在规格书,设备地址部分是一个8 bit 的地址,这里就是1000100左移1位即可。读写地址需要设备地址与最后一位做与操作,故读地址为 ((1000100 <<1) | 0x00 ) = 0x88 ,写地址为((1000100 <<1) | 0x01 ) = 0x89。
3.配置工作模式
command-I 寄存器对应有8种工作模式,通过B7~B5来配置其工作模式,此处我们选择101,另外B4,B3 保留为默认为0x00.
table4,5 的中断参数全部置为0。 那么command-1 寄存器我们需要写入的值为:1010 0000 (0xA0).
而command-II 设置光控的最大阈值范围,ADC的有效取值位数
B0~B1 的值决定了光感最大的取值范围,这里我们B1B0 配置为0x01,那么范围是0 - 16000。
B3,B3 的取值分别对应的是ADC数据的有效位数是16,12,8,4位。此处我们设置为00,那么有效位是16位
那么,command-II 寄存器我们需要设置为 0000 0001 (0x01)
4. 读取数据
配置光感的工作模式后,就可以读取有效的数据值了。table-10 中,0x02,0x03 寄存器分别是低八位,高八位的数据。读出来之后,根据上一步配置来获取有效位。上一步配置为16 位,那么ADC值就应该是:
(reg[0x02] & 0xFF) | (reg[0x03] << 8 & 0xFF00)
5. 计算光感值
E 为最终光感值,由于前面我们配置的command-I 的B0,B1 是1,0 ,那对应的Range(K)就是Range3, 最大的光感值就是16000,而ADC的有效位是16位,那么2^16 也即为65536.
最终 E = ((reg[0x02]&0xFF) | (reg[0x03] << 8 & 0xFF00)) * 16000 / 65536
6.Code
void ISL29023_init(void)
{
U8 data[2];
memset(data,0,sizeof(data));
mapi_i2c *iptr = mapi_i2c::GetI2C_Dev(ISL29023); // 光感设备地址ID
data[0] = ISL29003_COMMAND_REG; // reg: 0x00 ,也即 command-I 寄存器
data[1] = ISL29003_CMD_DEFAULT; // 0x00
iptr->WriteBytes((MAPI_U8)1, &data[0], (MAPI_U16)1, &data[1]);
printf("[light_det][%s][%d] reg = %d val = %d \n",__FUNCTION__,__LINE__,data[0],data[1]);
data[0] = ISL29003_COMMAND_REG; // reg: 0x00 ,也即 command-I 寄存器
data[1] = 0xA0; // 1010 0000
iptr->WriteBytes((MAPI_U8)1, &data[0], (MAPI_U16)1, &data[1]);
printf("[light_det][%s][%d] reg = %d val = %d \n",__FUNCTION__,__LINE__,data[0],data[1]);
data[0] = ISL29003_CONTROL_REG; // 0x01, 也即command-II寄存器
data[1] = 0x01; // byte[0] = 1
iptr->WriteBytes((MAPI_U8)1, &data[0], (MAPI_U16)1, &data[1]);
printf("[%s][%d] reg = %d val = %d \n",__FUNCTION__,__LINE__,data[0],data[1]);
}
首先,command-I 先写0x00,然后再写0xA0 完成初始状态到工作状态的配置。
接着,command-II写0x01, 设置光感的最大范围和ADC 数据的有效位数。
U32 GetLightSensorValue()
{
ISL29023_init();
U8 uLsbData[2];
U8 uMsbData[2];
memset(uLsbData,0,sizeof(uLsbData));
memset(uMsbData,0,sizeof(uMsbData));
U32 ambient_light;
uLsbData[0] = ISL29003_DATA0_REG; // reg:0x02 低八位数据寄存器
uMsbData[0] = ISL29003_DATA1_REG; // reg:0x03 低八位数据寄存器
mapi_i2c *iptr = mapi_i2c::GetI2C_Dev(ISL29003); // 设备地址ID
iptr->ReadBytes((MAPI_U8)1, &uLsbData[0], (MAPI_U16)1, &uLsbData[1]);
iptr->ReadBytes((MAPI_U8)1, &uMsbData[0], (MAPI_U16)1, &uMsbData[1]);
// E = ((reg[0x02]&0xFF) | (reg[0x03] << 8 & 0xFF00)) * 16000 / 65536
ambient_light = (uMsbData[1] << 8) | uLsbData[1];
ambient_light = (ambient_light*16000)/65536;
printf("[light_det][%s][%d] (ambient_light) = %d .\n",__FUNCTION__,__LINE__,ambient_light);
return ambient_light;
}
读取0x02,0x03 的ADC值,计算得到光感的数据值。
7.自动调节背光
得到环境光的值,根据曲线自动调节背光。