|
|
以下代码基于 STM32F103 系列,采用 I2C 通信方式,实现 VCNL36821S 初始化、近距离(PS)/ 环境光(ALS)数据读取、中断配置等核心功能,注释清晰,可直接适配主流 STM32 平台。
一、头文件与宏定义(vcnl36821s.h)
- <font face="宋体">#ifndef __VCNL36821S_H
- #define __VCNL36821S_H
- #include "stm32f1xx_hal.h"
- // *************************** 硬件配置 ***************************
- // VCNL36821S I2C地址(A0/A1接GND时为0x60,左移1位适配HAL库)
- #define VCNL36821S_I2C_ADDR 0x60 << 1
- // 绑定使用的I2C句柄(根据实际工程修改)
- #define VCNL36821S_I2C_HANDLE &hi2c1
- // *************************** 寄存器地址 ***************************
- #define VCNL36821S_ID_REG 0x00 // 设备ID寄存器(默认值0x11)
- #define VCNL36821S_PS_CONF1_REG 0x03 // PS配置寄存器1
- #define VCNL36821S_PS_CONF2_REG 0x04 // PS配置寄存器2
- #define VCNL36821S_ALS_CONF_REG 0x06 // ALS配置寄存器
- #define VCNL36821S_ALS_THDL_REG 0x08 // ALS下限阈值寄存器(低字节)
- #define VCNL36821S_ALS_THDH_REG 0x09 // ALS上限阈值寄存器(低字节)
- #define VCNL36821S_PS_THDL_REG 0x0A // PS下限阈值寄存器
- #define VCNL36821S_PS_THDH_REG 0x0B // PS上限阈值寄存器
- #define VCNL36821S_INT_CTRL_REG 0x0D // 中断控制寄存器
- #define VCNL36821S_ALS_DATA_REG 0x10 // ALS数据寄存器(低字节)
- #define VCNL36821S_PS_DATA_REG 0x18 // PS数据寄存器
- // *************************** 函数声明 ***************************
- /**
- * @brief 检测VCNL36821S设备ID,验证通信链路
- * @retval 1-检测成功,0-检测失败
- */
- uint8_t VCNL36821S_CheckID(void);
- /**
- * @brief 初始化VCNL36821S:配置ALS/PS工作模式
- * @note 默认配置:ALS高分辨率+50Hz工频抑制;PS中等发射功率+100ms检测周期
- */
- void VCNL36821S_Init(void);
- /**
- * @brief 读取环境光强度(ALS)
- * @retval 光强值(lx)
- */
- float VCNL36821S_ReadALS(void);
- /**
- * @brief 读取近距离检测值(PS)
- * @retval PS原始值(范围0~4095,数值越大距离越近)
- */
- uint16_t VCNL36821S_ReadPS(void);
- /**
- * @brief 配置PS/ALS中断阈值
- * @param als_thdl: ALS下限阈值(0~65535)
- * @param als_thdh: ALS上限阈值(0~65535)
- * @param ps_thdl: PS下限阈值(0~4095)
- * @param ps_thdh: PS上限阈值(0~4095)
- */
- void VCNL36821S_SetIntThreshold(uint16_t als_thdl, uint16_t als_thdh, uint16_t ps_thdl, uint16_t ps_thdh);
- /**
- * @brief 启用PS/ALS中断功能
- * @param ps_int_en: 1-启用PS中断,0-禁用
- * @param als_int_en:1-启用ALS中断,0-禁用
- */
- void VCNL36821S_EnableInt(uint8_t ps_int_en, uint8_t als_int_en);
- #endif</font>
复制代码 二、核心功能实现(vcnl36821s.c)- <font face="宋体">#include "vcnl36821s.h"
- /**
- * @brief I2C寄存器写函数(底层封装,方便移植)
- * @param reg_addr: 寄存器地址
- * @param data: 要写入的数据
- * @retval HAL状态
- */
- static HAL_StatusTypeDef VCNL36821S_WriteReg(uint8_t reg_addr, uint8_t data)
- {
- return HAL_I2C_Mem_Write(VCNL36821S_I2C_HANDLE, VCNL36821S_I2C_ADDR,
- reg_addr, 1, &data, 1, 100);
- }
- /**
- * @brief I2C寄存器读函数(底层封装,方便移植)
- * @param reg_addr: 寄存器地址
- * @param data: 读取数据缓冲区
- * @param len: 读取长度
- * @retval HAL状态
- */
- static HAL_StatusTypeDef VCNL36821S_ReadReg(uint8_t reg_addr, uint8_t *data, uint16_t len)
- {
- return HAL_I2C_Mem_Read(VCNL36821S_I2C_HANDLE, VCNL36821S_I2C_ADDR,
- reg_addr, 1, data, len, 100);
- }
- // 检测设备ID
- uint8_t VCNL36821S_CheckID(void)
- {
- uint8_t dev_id = 0;
- if(VCNL36821S_ReadReg(VCNL36821S_ID_REG, &dev_id, 1) != HAL_OK)
- {
- return 0;
- }
- // 验证威世VCNL36821S默认ID
- return (dev_id == 0x11) ? 1 : 0;
- }
- // 传感器初始化
- void VCNL36821S_Init(void)
- {
- // 通信失败直接退出
- if(!VCNL36821S_CheckID()) return;
- // ********************* PS配置 *********************
- // PS_CONF1: 0x20 → PS检测周期100ms,16次平均滤波
- VCNL36821S_WriteReg(VCNL36821S_PS_CONF1_REG, 0x20);
- // PS_CONF2: 0x08 → LED发射功率中等(120mA),禁用PS唤醒
- VCNL36821S_WriteReg(VCNL36821S_PS_CONF2_REG, 0x08);
- // ********************* ALS配置 *********************
- // ALS_CONF: 0x18 → ALS分辨率16位,启用50Hz工频抑制,测量速率10Hz
- VCNL36821S_WriteReg(VCNL36821S_ALS_CONF_REG, 0x18);
- // 等待传感器稳定
- HAL_Delay(20);
- }
- // 读取环境光强度(转换为lx)
- float VCNL36821S_ReadALS(void)
- {
- uint8_t als_data[2] = {0};
- uint16_t als_raw = 0;
- float als_lx = 0.0f;
- // 读取ALS 16位数据(低字节+高字节)
- if(VCNL36821S_ReadReg(VCNL36821S_ALS_DATA_REG, als_data, 2) != HAL_OK)
- {
- return 0.0f;
- }
- als_raw = (uint16_t)((als_data[1] << 8) | als_data[0]);
- // 转换公式(参考威世官方手册):1LSB = 0.01 lx
- als_lx = als_raw * 0.01f;
- return als_lx;
- }
- // 读取近距离检测原始值
- uint16_t VCNL36821S_ReadPS(void)
- {
- uint8_t ps_data[2] = {0};
- uint16_t ps_raw = 0;
- // 读取PS 12位数据(低字节+高字节,仅低12位有效)
- if(VCNL36821S_ReadReg(VCNL36821S_PS_DATA_REG, ps_data, 2) != HAL_OK)
- {
- return 0;
- }
- ps_raw = (uint16_t)((ps_data[1] << 8) | ps_data[0]) & 0x0FFF; // 仅保留低12位
- return ps_raw;
- }
- // 配置中断阈值
- void VCNL36821S_SetIntThreshold(uint16_t als_thdl, uint16_t als_thdh, uint16_t ps_thdl, uint16_t ps_thdh)
- {
- // 配置ALS下限阈值(低字节)
- VCNL36821S_WriteReg(VCNL36821S_ALS_THDL_REG, als_thdl & 0xFF);
- VCNL36821S_WriteReg(VCNL36821S_ALS_THDL_REG + 1, (als_thdl >> 8) & 0xFF);
- // 配置ALS上限阈值(低字节)
- VCNL36821S_WriteReg(VCNL36821S_ALS_THDH_REG, als_thdh & 0xFF);
- VCNL36821S_WriteReg(VCNL36821S_ALS_THDH_REG + 1, (als_thdh >> 8) & 0xFF);
- // 配置PS下限阈值(12位)
- VCNL36821S_WriteReg(VCNL36821S_PS_THDL_REG, ps_thdl & 0xFF);
- VCNL36821S_WriteReg(VCNL36821S_PS_THDL_REG + 1, (ps_thdl >> 8) & 0x0F);
- // 配置PS上限阈值(12位)
- VCNL36821S_WriteReg(VCNL36821S_PS_THDH_REG, ps_thdh & 0xFF);
- VCNL36821S_WriteReg(VCNL36821S_PS_THDH_REG + 1, (ps_thdh >> 8) & 0x0F);
- }
- // 启用中断功能
- void VCNL36821S_EnableInt(uint8_t ps_int_en, uint8_t als_int_en)
- {
- uint8_t int_ctrl = 0;
- // 读取当前中断控制寄存器值
- VCNL36821S_ReadReg(VCNL36821S_INT_CTRL_REG, &int_ctrl, 1);
- // 设置PS/ALS中断使能位
- if(ps_int_en) int_ctrl |= 0x02; // BIT1: PS中断使能
- else int_ctrl &= ~0x02;
- if(als_int_en) int_ctrl |= 0x01; // BIT0: ALS中断使能
- else int_ctrl &= ~0x01;
- // 写入配置
- VCNL36821S_WriteReg(VCNL36821S_INT_CTRL_REG, int_ctrl);
- }</font>
复制代码
三、主函数调用示例(main.c)- <font face="宋体">#include "stm32f1xx_hal.h"
- #include "vcnl36821s.h"
- // 全局I2C句柄(根据实际工程生成)
- I2C_HandleTypeDef hi2c1;
- int main(void)
- {
- HAL_Init();
- SystemClock_Config();
- MX_I2C1_Init(); // 初始化I2C1(速率400kHz,开漏输出)
- float als_lx;
- uint16_t ps_raw;
- // 初始化VCNL36821S
- VCNL36821S_Init();
- // 配置中断阈值(示例:ALS<100lx或>5000lx触发;PS<100或>3000触发)
- VCNL36821S_SetIntThreshold(1000, 50000, 100, 3000);
- // 启用ALS+PS中断
- VCNL36821S_EnableInt(1, 1);
- while(1)
- {
- // 读取环境光和近距离数据
- als_lx = VCNL36821S_ReadALS();
- ps_raw = VCNL36821S_ReadPS();
- // 示例:根据PS值判断距离(可根据实际场景校准)
- if(ps_raw > 3000)
- {
- // 物体接近(<5cm),执行熄屏/触发动作
- }
- else if(ps_raw < 100)
- {
- // 物体远离(>20cm),执行亮屏/复位动作
- }
- // 示例:根据ALS值调节屏幕亮度
- if(als_lx < 50.0f)
- {
- // 低光环境,调亮屏幕
- }
- else if(als_lx > 2000.0f)
- {
- // 强光环境,调暗屏幕
- }
- HAL_Delay(200); // 200ms读取一次,可按需调整
- }
- }</font>
复制代码 四、移植与使用注意事项
- 硬件适配:
- I2C 引脚需配置为开漏输出,SDA/SCL 串联 4.7kΩ 上拉电阻到 3.3V;
- 传感器 INT 引脚可接 STM32 外部中断引脚(如 PA0),用于中断触发;
- 保证传感器光学窗口无遮挡,避免油污 / 灰尘影响检测精度。
- 代码移植:
- 修改VCNL36821S_I2C_HANDLE为工程实际使用的 I2C 句柄;
- 根据实际需求调整 PS 发射功率、ALS 测量速率(修改初始化寄存器值);
- PS 原始值需根据实际场景校准(如:3000 对应 5cm,100 对应 20cm)。
- 性能优化:
- 低功耗场景:配置传感器自动休眠,仅在需要时唤醒读取数据;
- 抗干扰优化:开启 ALS 工频抑制,PS 可增加平均滤波次数(修改 PS_CONF1 寄存器)。
|
|