【瑞萨RA-eco-RA6M4评测】BH1730环境光传感共IIC驱动
本帖最后由 yinwuqing 于 2026-8-16 00:36 编辑上期咱们分享了NSHT30温湿传感器在FreeRTOS中的实时高效采集,今天在原工程的基础上,增加对BH1730环境光传感的驱动。使其能够实时感应周围环境光照强度,进而可以实现一些感光类的智能设备应用开发。
同样的,首先咱们直接上正常日光下实物连接状态示意图。
关于BH1730环境光传感器,官方提供的参考资料文档如下:
在扩展板部分提供的电路设计原理图发现与上期分享的NSHT30温湿传感器共用IIC接口。
因此无需再使用FSP去使能其它硬件接口,笔者这里直接使用同一个线程任务去读取BH1730的光照强度。硬件接口的连接关系与上期一样,无需再变动。
直接在new_thread2线程中添加关于BH1730环境光传感器相应的驱动接口,即可实现的周围环境光的强弱进行感应。相关代码如下:
new_thread2_entry.c
#include "new_thread2.h"
#include "lcd_init.h"
#include "lcd.h"
#include "nsht30.h"
#include "bh1730.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
fsp_err_t err;
int timeout_ms = 10000;
i2c_master_event_t i2c_event;
/* I2C callback function */
void sci_i2c_master_callback(i2c_master_callback_args_t *p_args)
{
i2c_event = I2C_MASTER_EVENT_ABORTED;
if (NULL != p_args) {
i2c_event = p_args->event;
}
}
/* New Thread entry function */
/* pvParameters contains TaskHandle_t */
void new_thread2_entry(void * pvParameters)
{
FSP_PARAMETER_NOT_USED(pvParameters);
NSHT30_Init();
BH1730_Init();
BH1730_Config(BH1730_GAIN_X1, BH1730_ITIME_DEFAULT);
/* TODO: add your own code here */
while(1)
{
if (NSHT30_ReadData() == 1) {
LCD_ShowFloatNum1(88,74,nsht30_temperature,4,RED,WHITE,12);
LCD_ShowFloatNum1(88,94,nsht30_humidity,4,RED,WHITE,12);
} else {
LCD_ShowString(84,74,(uint8_t *)"GetFail",RED,WHITE,12,0);
LCD_ShowString(84,94,(uint8_t *)"GetFail",RED,WHITE,12,0);
}bh1730.h
#ifndef BH1730_H
#define BH1730_H
#include <stdint.h>
/* I2C 地址 */
#define BH1730_ADDR 0x29
/* 命令寄存器标志 (必须与地址或命令进行或运算) */
#define BH1730_CMD 0x80
/* 特殊命令 */
#define BH1730_CMD_SPECIAL 0x60
#define BH1730_CMD_SOFT_RESET 0x04
/* 普通寄存器地址 (使用时必须 |= BH1730_CMD) */
#define BH1730_REG_CONTROL 0x00
#define BH1730_REG_GAIN 0x07
#define BH1730_REG_TIMING 0x01
#define BH1730_REG_PART_ID 0x12
#define BH1730_REG_DATA0_LOW 0x14
#define BH1730_REG_DATA0_HIGH 0x15
#define BH1730_REG_DATA1_LOW 0x16
#define BH1730_REG_DATA1_HIGH 0x17
/* CONTROL 寄存器位定义 */
#define BH1730_CTRL_POWER 0x01
#define BH1730_CTRL_ADC_EN 0x02
#define BH1730_CTRL_ONE_TIME 0x08
#define BH1730_CTRL_ADC_VALID 0x10
/* 增益 */
#define BH1730_GAIN_X1 0x00
#define BH1730_GAIN_X2 0x01
#define BH1730_GAIN_X64 0x02
#define BH1730_GAIN_X128 0x03
/* 积分时间 (ITIME) 值 (测量时间 = (256 - ITIME) * 2.7ms) */
#define BH1730_ITIME_DEFAULT 0xDA // 102.6ms
#define BH1730_ITIME_LONG 0x01 // 688.5ms
/* 外部变量 */
extern float bh1730_lux;
/* 函数声明 */
void BH1730_Init(void);
uint8_t BH1730_ReadID(uint8_t *id);
void BH1730_Config(uint8_t gain, uint8_t itime);
float BH1730_ReadLight(void);
#endifbh1730.c
#include "bh1730.h"
#include "hal_data.h"
#include <string.h>
extern int timeout_ms;
extern i2c_master_event_t i2c_event;
float bh1730_lux = 0.0f;
/* 内部平均次数 */
#define AVERAGE_TIMES5
/* ========== 底层I2C操作 ========== */
/**
* @brief 写命令(单个字节,自动或上 BH1730_CMD)
*/
static uint8_t BH1730_WriteCmd(uint8_t cmd)
{
uint8_t buf = cmd | BH1730_CMD; // 必须置最高位
i2c_event = I2C_MASTER_EVENT_ABORTED;
R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, BH1730_ADDR, I2C_MASTER_ADDR_MODE_7BIT);
R_SCI_I2C_Write(&g_i2c2_ctrl, &buf, 1, false);
timeout_ms = 10000;
while ((i2c_event != I2C_MASTER_EVENT_TX_COMPLETE) && (timeout_ms > 0)) {
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (i2c_event == I2C_MASTER_EVENT_ABORTED || timeout_ms == 0) {
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 0;
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 1;
}
/**
* @brief 写寄存器(两字节:寄存器地址|CMD,数据)
*/
static uint8_t BH1730_WriteReg(uint8_t reg, uint8_t data)
{
uint8_t buf;
buf = reg | BH1730_CMD; // 高位置1
buf = data;
i2c_event = I2C_MASTER_EVENT_ABORTED;
R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, BH1730_ADDR, I2C_MASTER_ADDR_MODE_7BIT);
R_SCI_I2C_Write(&g_i2c2_ctrl, buf, 2, false);
timeout_ms = 10000;
while ((i2c_event != I2C_MASTER_EVENT_TX_COMPLETE) && (timeout_ms > 0)) {
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (i2c_event == I2C_MASTER_EVENT_ABORTED || timeout_ms == 0) {
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 0;
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 1;
}
/**
* @brief 读取指定寄存器(单字节或双字节)
* @param reg 寄存器地址 (函数内部或上BH1730_CMD)
* @param len 读取长度 (1或2)
* @param buf 输出缓冲区
*/
static uint8_t BH1730_ReadReg(uint8_t reg, uint8_t len, uint8_t *buf)
{
/* 1. 写命令:设置要读取的寄存器地址 (reg | BH1730_CMD) */
uint8_t cmd = reg | BH1730_CMD;
i2c_event = I2C_MASTER_EVENT_ABORTED;
R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, BH1730_ADDR, I2C_MASTER_ADDR_MODE_7BIT);
R_SCI_I2C_Write(&g_i2c2_ctrl, &cmd, 1, false);
timeout_ms = 10000;
while ((i2c_event != I2C_MASTER_EVENT_TX_COMPLETE) && (timeout_ms > 0)) {
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (i2c_event == I2C_MASTER_EVENT_ABORTED || timeout_ms == 0) {
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 0;
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
/* 2. 读取数据 */
i2c_event = I2C_MASTER_EVENT_ABORTED;
R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, BH1730_ADDR, I2C_MASTER_ADDR_MODE_7BIT);
R_SCI_I2C_Read(&g_i2c2_ctrl, buf, len, false);
timeout_ms = 10000;
while ((i2c_event != I2C_MASTER_EVENT_RX_COMPLETE) && (timeout_ms > 0)) {
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (i2c_event == I2C_MASTER_EVENT_ABORTED || timeout_ms == 0) {
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 0;
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 1;
}
void BH1730_Init(void)
{
R_SCI_I2C_Open(&g_i2c2_ctrl, &g_i2c2_cfg);
R_BSP_SoftwareDelay(5, BSP_DELAY_UNITS_MILLISECONDS);
}
uint8_t BH1730_ReadID(uint8_t *id)
{
return BH1730_ReadReg(BH1730_REG_PART_ID, 1, id);
}
void BH1730_Config(uint8_t gain, uint8_t itime)
{
/* 软件复位:通过特殊命令 */
BH1730_WriteReg(BH1730_CMD_SPECIAL | BH1730_CMD_SOFT_RESET, 0x80);
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
/* 设置增益 */
BH1730_WriteReg(BH1730_REG_GAIN, gain);
/* 设置积分时间 */
BH1730_WriteReg(BH1730_REG_TIMING, itime);
/* 上电并开启ADC (Power On + ADC Enable + One Time 可选,**读取时再触发) */
BH1730_WriteReg(BH1730_REG_CONTROL, BH1730_CTRL_POWER | BH1730_CTRL_ADC_EN);
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
}
/**
* @brief 读取一次光照值(多次平均)
* @return 光照强度 (lux)
*/
float BH1730_ReadLight(void)
{
uint8_t buf;
uint16_t data0, data1;
float lx_total = 0.0f;
float gain = 1.0f; // 默认GAIN_1X
/* 先触发单次测量 (CONTROL = POWER|ADC_EN|ONE_TIME) */
BH1730_WriteReg(BH1730_REG_CONTROL, BH1730_CTRL_POWER | BH1730_CTRL_ADC_EN | BH1730_CTRL_ONE_TIME);
/* 等待转换完成 (根据ITIME等待,这里简单固定等待100ms,实际可根据配置动态计算) */
R_BSP_SoftwareDelay(120, BSP_DELAY_UNITS_MILLISECONDS);
for (int i = 0; i < AVERAGE_TIMES; i++) {
/* 读取 DATA0 (可见光) */
if (!BH1730_ReadReg(BH1730_REG_DATA0_LOW, 2, buf)) {
return 0.0f;
}
data0 = (uint16_t)(buf | (buf << 8));
/* 读取 DATA1 (红外) */
if (!BH1730_ReadReg(BH1730_REG_DATA1_LOW, 2, buf)) {
return 0.0f;
}
data1 = (uint16_t)(buf | (buf << 8));
/* 计算此单次 lux (参考RT1021驱动的分段公式) */
float lx = 0.0f;
float div = (data1 == 0) ? 0.0f : ((float)data1 / data0);
if (div < 0.26f) {
lx = (1.29f * data0 - 2.733f * data1) / gain * 102.6f / BH1730_ITIME_DEFAULT;
} else if (div < 0.55f) {
lx = (0.795f * data0 - 0.859f * data1) / gain * 102.6f / BH1730_ITIME_DEFAULT;
} else if (div < 1.09f) {
lx = (0.51f * data0 - 0.345f * data1) / gain * 102.6f / BH1730_ITIME_DEFAULT;
} else if (div < 2.13f) {
lx = (0.276f * data0 - 0.13f * data1) / gain * 102.6f / BH1730_ITIME_DEFAULT;
}
if (lx < 0) lx = 0;
lx_total += lx;
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
}
bh1730_lux = lx_total / AVERAGE_TIMES;
return bh1730_lux;
} 工程完善好后,将程序更新到开发板中,由于手机拍摄会自动调节聚光,台灯的三档位变化不便于录制LCD屏上亮度值清晰显示,这里笔者使用可移动的小台灯进行演示,演示视频见如下,由此可见,FreeRTOS中可高效显示室内温湿度与光照强度值。
https://www.bilibili.com/video/BV1ynb26jExw/
整个工程的源码见如下附件:
页:
[1]