OPT3001光强传感器驱动实现(STM32F407)
程序员文章站
2022-04-01 18:33:35
...
上面是我创建的群聊,欢迎新朋友的加入。
写了个光强传感器的代码。
产品特点:
精密光学滤波以匹配人眼:拒绝IR> 99%(典型值)
自动满量程设定功能简化了软件,并确保正确的配置
0.01勒克斯至83K勒克斯
23位有效动态范围,自动增益范围
12二进制加权满量程范围设置:<0.2%(典型值)范围之间的匹配
低工作电流:1.8μA(典型值)
工作温度范围:-40°C至+ 85°C
宽电源电压范围:1.6 V至3.6 V
5.5-V容错I / O
PCB尺寸:14*13.5mm
OPT3001数字环境光传感器(ALS)高精度的人眼响应分线板
OPT3001是测量可见光的强度的传感器。传感器的光谱响应紧密匹配的人眼的明视响应并包括显着红外线排斥。
所述OPT3001是一个单芯片照度计,由人眼测量光作为??可见光的强度。精密光谱响应和强大的红外抑制装置的使OPT3001精确计人眼所看到不管光源的光的强度。强劲的IR抑制,也有助于保持高精确度时的工业设计为深色玻璃下安装传感器的美学要求。该OPT3001是专为创造人类基于光的经验系统,和理想的首选替代品光电二极管,光敏电阻,或者用更少的人眼匹配的IR抑制等环境光传感器。
测量可以从0.01勒克斯到83K勒克斯而不通过使用内置的,全面设置功能手动选择满量程范围进行。这个功能允许在一个23位的有效动态范围光测量。
数字操作灵活的系统集成。测量可以是连续的或单次。控制和中断系统具有自主运行,允许处理器睡觉而适当唤醒事件传感器搜索,通过中断引脚报告。
低功率消耗和OPT3001的低电源电压的能力提高电池供电系统的电池寿命。
模块是一个IIC驱动的传感器
这里提供底层IIC驱动源码
/*
功能:产生IIC起始信号
输入:无
输出:无
*/
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(5);
IIC_SDA=0; //START:when CLK is high,DATA change form high to low
delay_us(5);
IIC_SCL=0; //钳住I2C总线,准备发送或接收数据
}
/*
功能:产生IIC停止信号
输入:无
输出:无
*/
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
IIC_SCL=1;
delay_us(5);
IIC_SDA=1;//发送I2C总线结束信号
delay_us(5);
IIC_SCL=0;
delay_us(5);
}
/*
功能:等待应答信号到来
输入:1,接收应答失败
0,接收应答成功
输出:无
*/
uint8_t IIC_Wait_Ack(void)
{
uint8_t res=0;
IIC_SDA=1;
SDA_IN(); //SDA设置为输入
IIC_SCL=1;delay_us(5);
res = READ_SDA;
delay_us(5);
IIC_SCL=0;//时钟输出0
return res;
}
/*
功能:产生ACK应答
输入:1,产生应答
0,不产生应答
输出:无
*/
void IIC_Ack(uint8_t ack)
{
SDA_OUT();
IIC_SDA=ack;
delay_us(5);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
/*
功能:IIC发送一个字节
输入:txd:发送数据
输出:无
*/
void IIC_Send_Byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
for(t=0;t<8;t++)
{
if(txd&0x80)
IIC_SDA=1;
else
IIC_SDA=0;
delay_us(5);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
delay_us(5);
txd<<=1;
}
IIC_Wait_Ack();
}
/*
功能:IIC读取一个字节
输入:无
输出:返回数据
*/
uint8_t IIC_Read_Byte(void)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
IIC_SDA=1;
for(i=0;i<8;i++ )
{
receive <<= 1;
IIC_SCL=1;
delay_us(5);
receive |= READ_SDA;
IIC_SCL=0;
delay_us(5);
}
return receive;
}
然后是阅读该传感器的数据手册
1、设备地址
从手册可知道,这个模块有四种地址配置
通过设置ADDR的连接,可以改变不同的设备地址
//定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改 拉低0x88 拉高0x8A 接SDA-0x8C 接SCL-0x8E
#define SLAVEADDR 0x88
2、设备子地址
一共是6个地址,还蛮简单的,有一点要注意的是,这个芯片是16位的数据寄存器
3、只读寄存器
这是传感器数据保存的地址,要从传感器拿环境光强数据,就是在这拿,这个地方是只读的
4、配置寄存器
这是个十分重要的寄存器,不同的配置可能会导致读取的数据不一样
5、下限寄存器、上限寄存器
我没用到
6、ID寄存器
这个地方挺重要的
这个东西有两个ID:1.厂商ID 2.设备ID
为什么说他重要,可以通过读取ID,确定IIC驱动是否正常,如果这个ID读取不到,那后面的程序也没必要写下去了
从数据手册可以知道,设备厂商ID是0x5449,也就是ACSII码的"TI",设备ID是0x3001
7、初始化寄存器配置
上面就是芯片手册里面比较重要的寄存器的内容
现在根据配置寄存器的内容,实现芯片的配置,当然,这段配置我也是抄的,非专业我懒得去折腾
/*
功能:配置寄存器
输入:无
输出:无
*/
void opt3001_config(void)
{
uint16_t vCfg = 0;
//12:15 RN - 配置测量光照的范围 见手册20页表9 当配置位1100传感器测量范围自动选择
//11 CT - 测量时间配置 0- 100Ms 1-800Ms
//10:9 M[1:0] - 转换模式 00-关闭模式 01 - 单次转换 10、11 - 连续多次转换
//8 OVF - 测量光照超出设定的范围或最大测量值 溢出标志
//7 CRF - 转换就绪字段 1-转换完成
//6 FH - 转换的光照值 大于上限值 置位
//5 FL - 转换的光照值 小于下限值 置位
//4 L - 中断输出的两种模式 1-窗口模式 这种模式下高限置位和低限置位INT输出 0-滞后模式 高限置位INT输出 具体看手册
//3 POL - INT 中断被触发输出极性 0-拉低 1-拉高
//2 ME - 掩码字段
//0:1 FC - 超出上限范围故障计数 如果超出次数 大于等于计数设定次数 INT输出中断
vCfg = (0x0C<<12);
vCfg |= (0x01<<11);
vCfg |= (0x01<<9);
vCfg |= (0x01<<4);
opt3001_write(REG_CONFIGURATION, vCfg);
}
8、实现ID的读取
/*
功能:读取厂商ID
输入:无
输出:无
*/
uint16_t ID=0;
void opt3001_manufacturer_id(void)
{
ID = opt3001_read(REG_MANUFACTURER_ID);
}
/*
功能:读取设备ID
输入:无
输出:无
*/
void opt3001_device_id(void)
{
ID = opt3001_read(REG_DEVICE_ID);
}
9、实现数据的获取
/*
功能:读取传感器数据
输入:无
输出:无
*/
#define ARRY_SIZE 10
uint32_t opt3001_data[ARRY_SIZE];
uint8_t arry_wpr=0;
uint8_t opt3001_get_lux(void)
{
uint8_t vRval = 0;
uint16_t vCfg = 0;
uint16_t vDat = 0;
uint16_t vDatE = 0;
uint16_t vDatR = 0;
float vFval = 0.0;
float vLsbSize = 0.0;
float vFlux = 0;
vCfg = opt3001_read(REG_CONFIGURATION);
vCfg |= (0x01<<9);
opt3001_write(REG_CONFIGURATION, vCfg); //单次采集光照
vCfg = opt3001_read(REG_CONFIGURATION);
delay_ms(900); //大于800Ms
vCfg = opt3001_read(REG_CONFIGURATION);
if((vCfg&(0x01<<7)) ) //光照采集完成
{
vDat = opt3001_read(REG_RESULT);
vDatE = ((vDat&0xF000)>>12);
vDatR = (vDat&0x0FFF);
vFval = (0x01<<vDatE);
vLsbSize = (0.01f * vFval);
vFlux = (vLsbSize * (float)vDatR);
opt3001_data[arry_wpr] = ((vFlux)*100.0f);//透明外壳不需要矫正 ,乳白色外壳推荐*1.8矫正 *vp_Lux = ((vFlux*1.8)*100.0)
arry_wpr++;
if(arry_wpr >= ARRY_SIZE)
{
arry_wpr = 0;
}
}
else
{
vRval = 0x01;//光照采集失败
}
return vRval;
}
10、DEBUG看结果
首先检查厂商ID
然后查设备ID,可以看到,和数据手册是一致的
最后实现光强测试
可以看到数据会因为光强变化而变化