# VEML6030 环境光传感器模块资料

## 图片说明

实物图和测试视频已整理到网站页面中查看。下载版 Markdown 不附带价格说明、套餐说明、库存、成本或订单截图。

## 模块说明

VEML6030 是一款 I2C 数字环境光传感器，内部包含光电二极管、低噪声放大器和 16 位 ADC。它可以输出环境光强度数据，常用于自动背光调节、智能照明、光照记录、室内外亮度检测等项目。

常用 I2C 地址：`0x48`

常用寄存器：

| 寄存器 | 地址 | 用途 |
|---|---:|---|
| ALS_CONF | `0x00` | 增益、积分时间、开关配置 |
| ALS_WH | `0x01` | 中断高阈值 |
| ALS_WL | `0x02` | 中断低阈值 |
| PSM | `0x03` | 省电模式 |
| ALS | `0x04` | 环境光原始数据 |
| WHITE | `0x05` | 白光通道数据 |
| ALS_INT | `0x06` | 中断状态 |

基础配置建议：

| 场景 | 增益 | 积分时间 | 说明 |
|---|---:|---:|---|
| 普通室内/室外 | 1/8 或 1/4 | 100 ms | 不容易饱和，适合大多数项目 |
| 弱光环境 | 1 或 2 | 400-800 ms | 分辨率更高，但读取更慢 |
| 强太阳光 | 1/8 | 25-100 ms | 防止读数饱和 |

## ESP32 接线图

默认 ESP32 I2C 引脚常用 `GPIO21 = SDA`，`GPIO22 = SCL`。如果你的开发板引脚不同，可以在代码里的 `Wire.begin(SDA, SCL)` 修改。

```mermaid
flowchart LR
  VEML["VEML6030 模块"] -->|VIN / VCC| V33["ESP32 3V3"]
  VEML -->|GND| GND["ESP32 GND"]
  VEML -->|SDA| GPIO21["ESP32 GPIO21"]
  VEML -->|SCL| GPIO22["ESP32 GPIO22"]
  VEML -. 可选 .->|INT| GPIO25["ESP32 GPIO25"]
```

| VEML6030 | ESP32 | 说明 |
|---|---|---|
| VIN / VCC | 3V3 | 推荐 3.3V 供电 |
| GND | GND | 共地 |
| SDA | GPIO21 | I2C 数据线 |
| SCL | GPIO22 | I2C 时钟线 |
| INT | GPIO25 | 可选，中断脚，不用可悬空 |

## ESP32 Arduino 代码

下面代码不依赖第三方库，只使用 `Wire.h` 直接读写 VEML6030 寄存器。

```cpp
#include <Wire.h>

#define VEML6030_ADDR 0x48
#define SDA_PIN 21
#define SCL_PIN 22

#define REG_ALS_CONF 0x00
#define REG_ALS      0x04

void write16(uint8_t reg, uint16_t value) {
  Wire.beginTransmission(VEML6030_ADDR);
  Wire.write(reg);
  Wire.write(value & 0xFF);        // LSB
  Wire.write((value >> 8) & 0xFF); // MSB
  Wire.endTransmission();
}

uint16_t read16(uint8_t reg) {
  Wire.beginTransmission(VEML6030_ADDR);
  Wire.write(reg);
  Wire.endTransmission(false);

  Wire.requestFrom(VEML6030_ADDR, 2);
  uint16_t lsb = Wire.read();
  uint16_t msb = Wire.read();
  return (msb << 8) | lsb;
}

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA_PIN, SCL_PIN);

  // 0x0000: gain x1, integration time 100 ms, sensor enabled
  write16(REG_ALS_CONF, 0x0000);
  delay(120);

  Serial.println("VEML6030 ESP32 ready");
}

void loop() {
  uint16_t raw = read16(REG_ALS);

  // gain x1 + 100 ms 时，典型分辨率约 0.0672 lux/count
  float lux = raw * 0.0672;

  Serial.print("RAW: ");
  Serial.print(raw);
  Serial.print("  Lux: ");
  Serial.println(lux, 2);

  delay(1000);
}
```

## Arduino UNO 接线图

UNO 的 I2C 引脚为 `A4 = SDA`，`A5 = SCL`。VEML6030 芯片本身是 3.3V 器件，如果模块没有 5V 稳压和电平转换，请使用 3.3V 供电并注意 I2C 电平。

```mermaid
flowchart LR
  VEML["VEML6030 模块"] -->|VIN / VCC| V33["Arduino 3.3V"]
  VEML -->|GND| GND["Arduino GND"]
  VEML -->|SDA| A4["Arduino UNO A4"]
  VEML -->|SCL| A5["Arduino UNO A5"]
  VEML -. 可选 .->|INT| D2["Arduino UNO D2"]
```

| VEML6030 | Arduino UNO | 说明 |
|---|---|---|
| VIN / VCC | 3.3V | 推荐 3.3V |
| GND | GND | 共地 |
| SDA | A4 | I2C 数据线 |
| SCL | A5 | I2C 时钟线 |
| INT | D2 | 可选 |

## Arduino UNO 代码

```cpp
#include <Wire.h>

#define VEML6030_ADDR 0x48
#define REG_ALS_CONF 0x00
#define REG_ALS      0x04

void write16(byte reg, uint16_t value) {
  Wire.beginTransmission(VEML6030_ADDR);
  Wire.write(reg);
  Wire.write(value & 0xFF);
  Wire.write(value >> 8);
  Wire.endTransmission();
}

uint16_t read16(byte reg) {
  Wire.beginTransmission(VEML6030_ADDR);
  Wire.write(reg);
  Wire.endTransmission(false);

  Wire.requestFrom(VEML6030_ADDR, 2);
  uint16_t lsb = Wire.read();
  uint16_t msb = Wire.read();
  return (msb << 8) | lsb;
}

void setup() {
  Serial.begin(115200);
  Wire.begin();

  // gain x1，积分时间 100 ms，打开 ALS
  write16(REG_ALS_CONF, 0x0000);
  delay(120);

  Serial.println("VEML6030 Arduino UNO ready");
}

void loop() {
  uint16_t raw = read16(REG_ALS);
  float lux = raw * 0.0672;

  Serial.print("RAW = ");
  Serial.print(raw);
  Serial.print("  Lux = ");
  Serial.println(lux, 2);

  delay(1000);
}
```

## STM32 接线图

下面以常见 STM32F103C8T6 Blue Pill 为例，默认 I2C1 为 `PB7 = SDA`，`PB6 = SCL`。其它 STM32 板卡请按芯片手册或 CubeMX 配置修改。

```mermaid
flowchart LR
  VEML["VEML6030 模块"] -->|VIN / VCC| V33["STM32 3.3V"]
  VEML -->|GND| GND["STM32 GND"]
  VEML -->|SDA| PB7["STM32 PB7 / I2C1_SDA"]
  VEML -->|SCL| PB6["STM32 PB6 / I2C1_SCL"]
  VEML -. 可选 .->|INT| PA0["STM32 PA0 / EXTI"]
```

| VEML6030 | STM32F103C8T6 | 说明 |
|---|---|---|
| VIN / VCC | 3.3V | STM32 是 3.3V 逻辑，直接匹配 |
| GND | GND | 共地 |
| SDA | PB7 | I2C1_SDA |
| SCL | PB6 | I2C1_SCL |
| INT | PA0 | 可选外部中断 |

## STM32 Arduino Core 代码

如果你用 Arduino IDE 给 STM32 下载程序，可以直接使用下面代码。

```cpp
#include <Wire.h>

#define VEML6030_ADDR 0x48
#define REG_ALS_CONF 0x00
#define REG_ALS      0x04

void write16(uint8_t reg, uint16_t value) {
  Wire.beginTransmission(VEML6030_ADDR);
  Wire.write(reg);
  Wire.write(value & 0xFF);
  Wire.write(value >> 8);
  Wire.endTransmission();
}

uint16_t read16(uint8_t reg) {
  Wire.beginTransmission(VEML6030_ADDR);
  Wire.write(reg);
  Wire.endTransmission(false);

  Wire.requestFrom(VEML6030_ADDR, 2);
  uint16_t lsb = Wire.read();
  uint16_t msb = Wire.read();
  return (msb << 8) | lsb;
}

void setup() {
  Serial.begin(115200);

  // STM32 Arduino Core 一般会自动使用默认 I2C 引脚。
  // Blue Pill 常用 PB7 = SDA，PB6 = SCL。
  Wire.begin();

  write16(REG_ALS_CONF, 0x0000);
  delay(120);

  Serial.println("VEML6030 STM32 Arduino ready");
}

void loop() {
  uint16_t raw = read16(REG_ALS);
  float lux = raw * 0.0672;

  Serial.print("RAW: ");
  Serial.print(raw);
  Serial.print("  Lux: ");
  Serial.println(lux, 2);

  delay(1000);
}
```

## STM32 HAL 代码片段

如果你使用 STM32CubeMX / STM32CubeIDE，先开启 `I2C1`，速度可设为 `100 kHz` 或 `400 kHz`，再使用下面函数。HAL 的 7 位地址需要左移一位。

```c
#include "main.h"
#include <stdio.h>

extern I2C_HandleTypeDef hi2c1;

#define VEML6030_ADDR    (0x48 << 1)
#define REG_ALS_CONF     0x00
#define REG_ALS          0x04

static HAL_StatusTypeDef VEML6030_Write16(uint8_t reg, uint16_t value)
{
    uint8_t data[3];
    data[0] = reg;
    data[1] = value & 0xFF;        // LSB
    data[2] = (value >> 8) & 0xFF; // MSB

    return HAL_I2C_Master_Transmit(&hi2c1, VEML6030_ADDR, data, 3, 100);
}

static HAL_StatusTypeDef VEML6030_Read16(uint8_t reg, uint16_t *value)
{
    uint8_t data[2];
    HAL_StatusTypeDef ret;

    ret = HAL_I2C_Master_Transmit(&hi2c1, VEML6030_ADDR, &reg, 1, 100);
    if (ret != HAL_OK) return ret;

    ret = HAL_I2C_Master_Receive(&hi2c1, VEML6030_ADDR, data, 2, 100);
    if (ret != HAL_OK) return ret;

    *value = ((uint16_t)data[1] << 8) | data[0];
    return HAL_OK;
}

void VEML6030_Init(void)
{
    // gain x1，integration time 100 ms，ALS enabled
    VEML6030_Write16(REG_ALS_CONF, 0x0000);
    HAL_Delay(120);
}

void VEML6030_ReadTask(void)
{
    uint16_t raw = 0;

    if (VEML6030_Read16(REG_ALS, &raw) == HAL_OK) {
        float lux = raw * 0.0672f;

        // 可以换成串口打印、OLED 显示或上传网络
        printf("VEML6030 RAW=%u Lux=%.2f\r\n", raw, lux);
    } else {
        printf("VEML6030 read failed\r\n");
    }
}
```

在 `main.c` 中调用示例：

```c
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();

    VEML6030_Init();

    while (1) {
        VEML6030_ReadTask();
        HAL_Delay(1000);
    }
}
```

## I2C 扫描代码

如果读不到数据，先用扫描程序确认模块地址是否出现。

```cpp
#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("I2C scan start");

  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("Found I2C device: 0x");
      if (addr < 16) Serial.print("0");
      Serial.println(addr, HEX);
    }
  }
}

void loop() {}
```

## 常见问题

1. 串口一直显示 `0`  
   检查供电、SDA/SCL 是否接反、I2C 地址是否为 `0x48`。

2. 读数很大或饱和  
   降低增益，缩短积分时间。强光下建议使用 1/8 增益。

3. 弱光下读数跳动  
   提高积分时间到 400 ms 或 800 ms，再做多次平均。

4. Arduino UNO 接 5V 是否可以  
   要看模块是否带稳压和电平转换。VEML6030 芯片本体供电范围是 2.5V 到 3.6V，保险做法是接 3.3V。

## 资料来源

- Vishay VEML6030 Datasheet: https://www.vishay.com/docs/84366/veml6030.pdf
- Vishay VEML6030 Application Note: https://www.vishay.com/docs/84367/designingveml6030.pdf
- SparkFun VEML6030 Arduino Library: https://github.com/sparkfun/SparkFun_Ambient_Light_Sensor_Arduino_Library
