简介
AS7341可见光传感器采用业内知名的ams公司推出的新一代AS7341光谱传感IC。该传感器有8个可见光通道、1个闪烁通道、1个NIR通道和1个未加滤光片的通道。该传感器拥有6个独立的16位ADC通道,可以并行的处理数据。该传感器板载了两颗高亮LED,可在暗光环境下进行补光。

引脚说明
- 工作电压: 3.3V/5V
- 工作电流: 20mA(不打开LED) 70mA(打开LED)
- 传感器: AS7341
- 逻辑电压: 3.3V/5V
- 通信接口: I2C
| 引脚号 | 标识 | 管脚描述 |
|---|---|---|
| 1 | VCC | 3.3V/5V电源正 |
| 2 | GND | 电源地 |
| 3 | SDA | I2C数据线 |
| 4 | SCL | I2C时钟线 |
| 5 | INT | 中断输出引脚 |
| 6 | GPIO | 通用输入/输出 |
HAL库模拟IIC驱动参考
c
#include "stm32f1xx_hal.h"
#define I2C_WR 0 /* 写控制bit */
#define I2C_RD 1 /* 读控制bit */
/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define I2C_GPIO_PORT GPIOA /* GPIO端口 */
#define I2C_RCC_PORT RCC_APB2Periph_GPIOA /* GPIO端口时钟 */
#define I2C_SCL_PIN GPIO_Pin_9 /* 连接到SCL时钟线的GPIO */
#define I2C_SDA_PIN GPIO_Pin_8 /* 连接到SDA数据线的GPIO */
#define I2C_SCL_1() HAL_GPIO_WritePin(SC1_GPIO_Port, SC1_Pin, GPIO_PIN_SET) /* SCL = 1 */
#define I2C_SCL_0() HAL_GPIO_WritePin(SC1_GPIO_Port, SC1_Pin, GPIO_PIN_RESET) /* SCL = 0 */
#define I2C_SDA_1() HAL_GPIO_WritePin(SD1_GPIO_Port, SD1_Pin, GPIO_PIN_SET) /* SDA = 1 */
#define I2C_SDA_0() HAL_GPIO_WritePin(SD1_GPIO_Port, SD1_Pin, GPIO_PIN_RESET) /* SDA = 0 */
#define I2C_SDA_READ() HAL_GPIO_ReadPin(SD1_GPIO_Port, SD1_Pin) /* 读SDA口线状态 */
/*
*********************************************************************************************************
* 函 数 名: i2c_Delay
* 功能说明: I2C总线位延迟,最快400KHz
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Delay(void)
{
uint8_t i;
/*
下面的时间是通过逻辑分析仪测试得到的。
工作条件:CPU主频72MHz ,MDK编译环境,1级优化
循环次数为10时,SCL频率 = 205KHz
循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
*/
for (i = 0; i < 8; i++);
}
void i2c_Delay_ms(uint32_t xms)
{
uint32_t i,t;
t = xms * 12000;
for (i = 0; i < t; i++);
}
// 设置SD1为输出模式
void SD1_SetOutput(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SD1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SD1_GPIO_Port, &GPIO_InitStruct);
}
// 设置SD1为输入模式
void SD1_SetInput(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SD1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(SD1_GPIO_Port, &GPIO_InitStruct);
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线启动信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
I2C_SDA_1();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_0();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Stop
* 功能说明: CPU发起I2C总线停止信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
I2C_SDA_0();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_1();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_SendByte
* 功能说明: CPU向I2C总线设备发送8bit数据
* 形 参:_ucByte : 等待发送的字节
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
I2C_SDA_1();
}
else
{
I2C_SDA_0();
}
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
if (i == 7)
{
I2C_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
/*
*********************************************************************************************************
* 函 数 名: i2c_ReadByte
* 功能说明: CPU从I2C总线设备读取8bit数据
* 形 参:无
* 返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(void)
{
uint8_t i;
uint8_t value;
SD1_SetInput();
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
I2C_SCL_1();
i2c_Delay();
if (I2C_SDA_READ())
{
value++;
}
I2C_SCL_0();
i2c_Delay();
}
SD1_SetOutput();
return value;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_WaitAck
* 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
* 形 参:无
* 返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{
uint8_t re;
SD1_SetInput();
//I2C_SDA_1(); /* CPU释放SDA总线 */
i2c_Delay();
I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
i2c_Delay();
if (I2C_SDA_READ()) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;
}
I2C_SCL_0();
i2c_Delay();
SD1_SetOutput();
return re;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
I2C_SDA_0(); /* CPU驱动SDA = 0 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
I2C_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: i2c_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
I2C_SDA_1(); /* CPU驱动SDA = 1 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_CfgGpio
* 功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_CfgGpio(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE(); /* 打开GPIO时钟 */
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = SD1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SD1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = SC1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SC1_GPIO_Port, &GPIO_InitStruct);
/* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */
i2c_Stop();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_CheckDevice
* 功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
* 形 参:_Address:设备的I2C总线地址
* 返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*********************************************************************************************************
*/
uint8_t i2c_CheckDevice(uint8_t _Address)
{
uint8_t ucAck;
i2c_CfgGpio(); /* 配置GPIO */
i2c_Start(); /* 发送启动信号 */
/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
i2c_SendByte(_Address | I2C_WR);
ucAck = i2c_WaitAck(); /* 检测设备的ACK应答 */
i2c_Stop(); /* 发送停止信号 */
return ucAck;
}
/***************************************************************************************************************
AS7341 Read Command
功能:从AS7341传感器的指定寄存器读取数据
参数:
- reg_addr:要读取的寄存器地址
- rev_data:用于存储读取到数据的缓冲区指针
- length:要读取的数据字节数
返回值:无
****************************************************************************************************************/
void AS7341_ReadCommand(uint8_t reg_addr, uint8_t *rev_data, uint8_t length)
{
i2c_Start(); // 发送I2C总线的启动信号
i2c_SendByte(AS7341_I2CADDR << 1 | 0); // 发送设备地址(左移1位并设置写控制位为0)
i2c_WaitAck(); // 等待从设备的ACK应答信号
i2c_SendByte(reg_addr); // 发送要读取的寄存器地址
i2c_WaitAck(); // 等待从设备对寄存器地址的ACK应答
i2c_Start(); // 重新发送I2C总线的启动信号(用于切换到读模式)
i2c_SendByte(AS7341_I2CADDR << 1 | 1); // 发送设备地址(左移1位并设置读控制位为1)
i2c_WaitAck(); // 等待从设备对读操作的ACK应答
for (uint8_t i = 0; i < length; i++) {
rev_data[i] = i2c_ReadByte(); // 从I2C总线接收数据并存储到缓冲区
if (i != length - 1) {
i2c_Ack(); // 发送ACK应答,通知从设备继续发送数据
}
}
i2c_NAck(); // 发送NACK应答,通知从设备数据接收完毕
i2c_Stop(); // 发送I2C总线的停止信号
}
/***************************************************************************************************************
AS7341 Write Command
功能:向AS7341传感器的指定寄存器写入数据
参数:
- reg_addr:要写入的寄存器地址
- send_data:包含要写入数据的缓冲区指针
- length:要写入的数据字节数
返回值:无
****************************************************************************************************************/
void AS7341_WriteCommand(uint8_t reg_addr, uint8_t *send_data, uint16_t length)
{
i2c_Start(); // 发送I2C总线的启动信号
i2c_SendByte(AS7341_I2CADDR << 1 | 0); // 发送设备地址(左移1位并设置写控制位为0)
i2c_WaitAck(); // 等待从设备的ACK应答信号
i2c_SendByte(reg_addr); // 发送要写入的寄存器地址
i2c_WaitAck(); // 等待从设备对寄存器地址的ACK应答
for (uint16_t i = 0; i < length; i++) {
i2c_SendByte(send_data[i]); // 逐个字节发送数据
i2c_WaitAck(); // 等待从设备对每个数据字节的ACK应答
}
i2c_Stop(); // 发送I2C总线的停止信号
}
/***************************************************************************************************************
AS7341 Write one byte
功能:向AS7341传感器的指定寄存器写入一个字节的数据
参数:
- reg_addr:要写入的寄存器地址
- send_data:要写入的字节数据
返回值:无
****************************************************************************************************************/
void AS7341_WriteByte(uint8_t reg_addr, uint8_t send_data)
{
AS7341_WriteCommand(reg_addr, &send_data, 1); // 调用写命令函数,写入一个字节数据
}
/***************************************************************************************************************
AS7341 Get Device Identity
功能:获取AS7341传感器的设备标识
参数:无
返回值:
- true:如果获取到的设备标识不为0x00,表示获取成功
- false:如果获取到的设备标识为0x00,表示获取失败
****************************************************************************************************************/
bool AS7341_Get_Id(void)
{
uint8_t id = 0x00;
AS7341_ReadCommand(AS7341_REG_DEVICE, &id, 1); // 从设备标识寄存器读取数据
if (id != 0x00)
return true;
return false;
}
/***************************************************************************************************************
The integration time in INT_MODE = (SPM/SYNS) is set using the ATIME (0x81) and
ASTEP (0xCA, 0xCB) registers. The integration time, in milliseconds, is equal to:
Equation 1: Setting the integration time
The reset value for ASTEP is 999 (2.78ms) and the recommended configuration for these two
registers is ASTEP = 599 and ATIME = 29, which results in an integration time of 50ms. It is not
The integration time also defines the full-scale ADC value, which is equal to:
Equation 2: ADC full scale value(1)
功能:设置AS7341传感器的积分时间
参数:
- atime:ATIME寄存器的值
- astep:ASTEP寄存器的值(16位,通过两个字节写入)
返回值:无
****************************************************************************************************************/
void AS7341_SetIntegrationTime(uint8_t atime, uint16_t astep)
{
uint8_t buf[2] = {astep & 0xff, astep >> 8}; // 将16位的astep拆分为两个字节
AS7341_WriteCommand(AS7341_REG_ATIME, &atime, 1); // 写入ATIME寄存器
AS7341_WriteCommand(AS7341_REG_ASTEP_L, buf, 2); // 写入ASTEP寄存器的两个字节
}
/***************************************************************************************************************
AS7341 set Gain
功能:设置AS7341传感器的增益
参数:
- value:增益值
返回值:无
****************************************************************************************************************/
void AS7341_SetGain(uint8_t value)
{
AS7341_WriteCommand(AS7341_REG_CFG1, &value, 1); // 向配置寄存器1写入增益值
}
/***************************************************************************************************************
AS7341 set Enable
功能:使能或禁用AS7341传感器
参数:
- status:
- true:使能传感器
- false:禁用传感器
返回值:无
****************************************************************************************************************/
void AS7341_SetEnable(bool status)
{
uint8_t rev_data = 0x00;
AS7341_ReadCommand(AS7341_REG_ENABLE, &rev_data, 1); // 读取使能寄存器的值
rev_data = (status == true) ? (rev_data | 0x01) : (rev_data & 0xfe); // 根据status设置使能位
AS7341_WriteCommand(AS7341_REG_ENABLE, &rev_data, 1); // 写入更新后的使能寄存器值
}
/***************************************************************************************************************
AS7341 Spectral Measurement
功能:启用或禁用AS7341传感器的光谱测量功能
参数:
- status:
- true:启用光谱测量
- false:禁用光谱测量
返回值:无
****************************************************************************************************************/
void AS7341_SpectralMeasurement(bool status)
{
uint8_t rev_data = 0x00;
AS7341_ReadCommand(AS7341_REG_ENABLE, &rev_data, 1); // 读取使能寄存器的值
rev_data = (status == true) ? (rev_data | 0x02) : (rev_data & 0xfd); // 根据status设置光谱测量使能位
AS7341_WriteCommand(AS7341_REG_ENABLE, &rev_data, 1); // 写入更新后的使能寄存器值
}
/***************************************************************************************************************
AS7341 set Low Power
功能:设置AS7341传感器的低功耗模式
参数:
- status:
- true:启用低功耗模式
- false:禁用低功耗模式
返回值:无
****************************************************************************************************************/
void AS7341_SetLowPower(bool status)
{
uint8_t rev_data = 0x00;
AS7341_ReadCommand(AS7341_REG_ENABLE, &rev_data, 1); // 读取使能寄存器的值
rev_data = (status == true) ? (rev_data | 0x20) : (rev_data & 0xdf); // 根据status设置低功耗位
AS7341_WriteCommand(AS7341_REG_ENABLE, &rev_data, 1); // 写入更新后的使能寄存器值
}
/***************************************************************************************************************
AS7341 set bank
功能:设置AS7341传感器的存储体(bank)
参数:
- status:
- true:设置为某个存储体(具体取决于传感器定义)
- false:设置为另一个存储体(具体取决于传感器定义)
返回值:无
****************************************************************************************************************/
void AS7341_SetBank(bool status)
{
uint8_t rev_data = 0x00;
AS7341_ReadCommand(AS7341_REG_CFG0, &rev_data, 1); // 读取配置寄存器0的值
rev_data = (status == true) ? (rev_data | 0x10) : (rev_data & 0xef); // 根据status设置存储体位
AS7341_WriteCommand(AS7341_REG_CFG0, &rev_data, 1); // 写入更新后的配置寄存器0值
}
/***************************************************************************************************************
SMUX command.
Selects the SMUX command to execute when setting SMUXEN gets set. Do not change during ongoing SMUX operation.
功能:设置AS7341传感器的模拟多路复用器(SMUX)命令
参数:
- value:SMUX命令值
返回值:无
****************************************************************************************************************/
void AS7341_SetSMUX(uint8_t value)
{
AS7341_WriteCommand(AS7341_REG_CFG6, &value, 1); // 向配置寄存器6写入SMUX命令值
}
/***************************************************************************************************************
SMUX Enable.
1: Starts SMUX command
Note: this bit gets cleared automatically as soon as
SMUX operation is finished
功能:启用AS7341传感器的模拟多路复用器(SMUX)操作
参数:无
返回值:无
****************************************************************************************************************/
void AS7341_SetEnableSMUX(void)
{
uint8_t rev_data = 0x00;
AS7341_ReadCommand(AS7341_REG_ENABLE, &rev_data, 1); // 读取使能寄存器的值
rev_data = rev_data | 0x10; // 设置SMUX使能位
AS7341_WriteCommand(AS7341_REG_ENABLE, &rev_data, 1); // 写入更新后的使能寄存器值
}
/***************************************************************************************************************
Configure SMUX for sensors F1-4, Clear and NIR
功能:配置AS7341传感器的模拟多路复用器(SMUX),用于选择F1-4传感器、Clear和NIR通道
参数:无
返回值:无
****************************************************************************************************************/
void AS7341_F1F4_Clear_NIR(void)
{
AS7341_WriteByte(0x00, 0x30);
AS7341_WriteByte(0x01, 0x01);
AS7341_WriteByte(0x02, 0x00);
AS7341_WriteByte(0x03, 0x00);
AS7341_WriteByte(0x04, 0x00);
AS7341_WriteByte(0x05, 0x42);
AS7341_WriteByte(0x06, 0x00);
AS7341_WriteByte(0x07, 0x00);
AS7341_WriteByte(0x08, 0x50);
AS7341_WriteByte(0x09, 0x00);
AS7341_WriteByte(0x0A, 0x00);
AS7341_WriteByte(0x0B, 0x00);
AS7341_WriteByte(0x0C, 0x20);
AS7341_WriteByte(0x0D, 0x04);
AS7341_WriteByte(0x0E, 0x00);
AS7341_WriteByte(0x0F, 0x30);
AS7341_WriteByte(0x10, 0x01);
AS7341_WriteByte(0x11, 0x50);
AS7341_WriteByte(0x12, 0x00);
AS7341_WriteByte(0x13, 0x06);
}
/***************************************************************************************************************
Configure SMUX for sensors F5-8, Clear and NIR
功能:配置AS7341传感器的模拟多路复用器(SMUX),用于选择F5-8传感器、Clear和NIR通道
参数:无
返回值:无
****************************************************************************************************************/
void AS7341_F5F8_Clear_NIR(void)
{
AS7341_WriteByte(0x00, 0x00);
AS7341_WriteByte(0x01, 0x00);
AS7341_WriteByte(0x02, 0x00);
AS7341_WriteByte(0x03, 0x40);
AS7341_WriteByte(0x04, 0x02);
AS7341_WriteByte(0x05, 0x00);
AS7341_WriteByte(0x06, 0x10);
AS7341_WriteByte(0x07, 0x03);
AS7341_WriteByte(0x08, 0x50);
AS7341_WriteByte(0x09, 0x10);
AS7341_WriteByte(0x0A, 0x03);
AS7341_WriteByte(0x0B, 0x00);
AS7341_WriteByte(0x0C, 0x00);
AS7341_WriteByte(0x0D, 0x00);
AS7341_WriteByte(0x0E, 0x24);
AS7341_WriteByte(0x0F, 0x00);
AS7341_WriteByte(0x10, 0x00);
AS7341_WriteByte(0x11, 0x50);
AS7341_WriteByte(0x12, 0x00);
AS7341_WriteByte(0x13, 0x06);
}
/***************************************************************************************************************
Configure SMUX for flicker detection
功能:配置AS7341传感器的模拟多路复用器(SMUX),用于闪烁检测
参数:无
返回值:无
****************************************************************************************************************/
void AS7341_FDConfig(void)
{
AS7341_WriteByte(0x00, 0x00);
AS7341_WriteByte(0x01, 0x00);
AS7341_WriteByte(0x02, 0x00);
AS7341_WriteByte(0x03, 0x00);
AS7341_WriteByte(0x04, 0x00);
AS7341_WriteByte(0x05, 0x00);
AS7341_WriteByte(0x06, 0x00);
AS7341_WriteByte(0x07, 0x00);
AS7341_WriteByte(0x08, 0x00);
AS7341_WriteByte(0x09, 0x00);
AS7341_WriteByte(0x0A, 0x00);
AS7341_WriteByte(0x0B, 0x00);
AS7341_WriteByte(0x0C, 0x00);
AS7341_WriteByte(0x0D, 0x00);
AS7341_WriteByte(0x0E, 0x00);
AS7341_WriteByte(0x0F, 0x00);
AS7341_WriteByte(0x10, 0x00);
AS7341_WriteByte(0x11, 0x00);
AS7341_WriteByte(0x12, 0x00);
AS7341_WriteByte(0x13, 0x60);
}
/***************************************************************************************************************
Spectral Valid.
Indicates that the spectral measurement has been completed
功能:检查AS7341传感器的光谱测量是否完成
参数:无
返回值:
- true:如果光谱测量已完成
- false:如果光谱测量未完成
****************************************************************************************************************/
bool AS7341_WaitDataReady(void)
{
uint8_t status;
AS7341_ReadCommand(AS7341_REG_STATUS2, &status, 1); // 读取状态寄存器2的值
if ((status & 0x40) >> 6) // 检查状态寄存器中表示光谱测量完成的位
return true;
else
return false;
}
/***************************************************************************************************************
AS7341 Control Led
status:open led or close led
value: 1 ~ 127
功能:控制AS7341传感器的LED(补光灯)
参数:
- status:
- true:打开LED
- false:关闭LED
- value:LED的亮度值(范围1到127)
返回值:无
****************************************************************************************************************/
void AS7341_ControlLed(bool status, uint8_t value)
{
AS7341_SetBank(true); // 设置传感器的存储体(可能与LED控制相关)
uint8_t rev_data = 0x00;
AS7341_ReadCommand(AS7341_REG_CONFIG, &rev_data, 1); // 读取配置寄存器的值
rev_data = (status == true) ? (rev_data | 0x08) : (rev_data & 0xf7); // 根据status设置LED使能位
AS7341_WriteCommand(AS7341_REG_CONFIG, &rev_data, 1); // 写入更新后的配置寄存器值
rev_data = value;
rev_data = (status == true) ? (rev_data | 0x80) : (rev_data & 0x7f); // 根据status设置LED亮度相关位
AS7341_WriteCommand(AS7341_REG_LED, &rev_data, 1); // 写入LED控制寄存器
AS7341_SetBank(false); // 恢复传感器的存储体设置
}
/***************************************************************************************************************
AS7341 Enable Flicker Detection
功能:启用或禁用AS7341传感器的闪烁检测功能
参数:
- status:
- true:启用闪烁检测
- false:禁用闪烁检测
返回值:无
****************************************************************************************************************/
void AS7341_EnableFlickerDetection(bool status)
{
uint8_t rev_data = 0x00;
AS7341_ReadCommand(AS7341_REG_ENABLE, &rev_data, 1); // 读取使能寄存器的值
rev_data = (status == true) ? (rev_data | 0x40) : (rev_data & 0xBF); // 根据status设置闪烁检测使能位
AS7341_WriteCommand(AS7341_REG_ENABLE, &rev_data, 1); // 写入更新后的使能寄存器值
}
/***************************************************************************************************************
AS7341 Read Flicker Data
功能:读取AS7341传感器的闪烁检测数据
参数:无
返回值:读取到的闪烁检测数据字节
****************************************************************************************************************/
uint8_t AS7341_ReadFlickerData(void)
{
uint8_t flicker;
AS7341_SetBank(false); // 设置传感器的存储体(可能与闪烁检测相关)
AS7341_SpectralMeasurement(false); // 禁用光谱测量
AS7341_SetSMUX(AS7341_SMUX_WRITE); // 设置SMUX为写模式
AS7341_FDConfig(); // 配置SMUX用于闪烁检测
AS7341_SetEnableSMUX(); // 启用SMUX操作
AS7341_SpectralMeasurement(true); // 启用光谱测量
AS7341_EnableFlickerDetection(true); // 启用闪烁检测功能
i2c_Delay_ms(600); // 延迟600毫秒,等待检测完成
AS7341_ReadCommand(AS7341_REG_FD_STATUS, &flicker, 1); // 读取闪烁检测状态寄存器的值
AS7341_EnableFlickerDetection(false); // 禁用闪烁检测功能
return flicker; // 返回读取到的闪烁检测数据
}
/***************************************************************************************************************
AS7341 Read All Channels
功能:读取AS7341传感器所有通道的数据
参数:
- readings_buffer:用于存储读取到的所有通道数据的缓冲区指针
返回值:
- true:如果成功读取所有通道数据
- false:如果读取过程中出现错误(目前代码中未体现错误返回false的情况)
****************************************************************************************************************/
bool AS7341_ReadAllChannels(uint16_t *readings_buffer)
{
uint8_t rev_data[12] = {0};
AS7341_SetBank(false); // 设置传感器的存储体(可能与通道数据读取相关)
AS7341_SpectralMeasurement(false); // 禁用光谱测量
AS7341_SetSMUX(AS7341_SMUX_WRITE); // 设置SMUX为写模式
AS7341_F1F4_Clear_NIR(); // 配置SMUX用于选择F1-4传感器、Clear和NIR通道
AS7341_SetEnableSMUX(); // 启用SMUX操作
AS7341_SpectralMeasurement(true); // 启用光谱测量
while (!AS7341_WaitDataReady()) // 等待光谱测量完成
{
i2c_Delay_ms(1); // 每次等待1毫秒
}
AS7341_ReadCommand(AS7341_REG_CH0_DATA_L, rev_data, 12); // 读取通道数据
for (int i = 0; i < 4; i++)
readings_buffer[i] = rev_data[i * 2 + 1] << 8 | rev_data[i * 2]; // 组合两个字节的数据为16位数据存储到缓冲区
AS7341_SetBank(false); // 再次设置传感器的存储体
AS7341_SpectralMeasurement(false); // 禁用光谱测量
AS7341_SetSMUX(AS7341_SMUX_WRITE); // 设置SMUX为写模式
AS7341_F5F8_Clear_NIR(); // 配置SMUX用于选择F5-8传感器、Clear和NIR通道
AS7341_SetEnableSMUX(); // 启用SMUX操作
AS7341_SpectralMeasurement(true); // 启用光谱测量
while (!AS7341_WaitDataReady()) // 等待光谱测量完成
{
i2c_Delay_ms(1); // 每次等待1毫秒
}
AS7341_ReadCommand(AS7341_REG_CH0_DATA_L, rev_data, 12); // 读取通道数据
for (int i = 0; i < 6; i++)
readings_buffer[4 + i] = rev_data[i * 2 + 1] << 8 | rev_data[i * 2]; // 组合两个字节的数据为16位数据存储到缓冲区
return true; // 返回读取成功标志
}
/***************************************************************************************************************
AS7341 Initialization
功能:初始化AS7341传感器
参数:无
返回值:
- true:如果初始化成功(获取到设备标识且启用传感器成功)
- false:如果初始化失败(未获取到设备标识)
****************************************************************************************************************/
bool AS7341_Init(void)
{
// Get AS7341 ID
if (!AS7341_Get_Id()) // 尝试获取设备标识
return false;
// enable AS7341
AS7341_SetEnable(true); // 启用AS7341传感器
return true;
}
//色温计算函数
//需要参数:spectraNum[10]数组
//spectralNum[10],存放着F1-F8 and Clear,NIR的数据
int color_temperature(uint16_t *spectralNum)
{
float X,Y,Z,x,y,n,cdc;
X=0.39814*spectralNum[0]+ 1.29540*spectralNum[1]+ 0.36956*spectralNum[2]+ 0.10902*spectralNum[3]+ 0.71942*spectralNum[4]+ 1.78180*spectralNum[5]+ 1.10110*spectralNum[6] -0.03991*spectralNum[7] -0.27597*spectralNum[8] -0.02347*spectralNum[9];
Y=0.01396*spectralNum[0]+ 0.16748*spectralNum[1]+ 0.23538*spectralNum[2]+ 1.42750*spectralNum[3]+ 1.88670*spectralNum[4]+ 1.14200*spectralNum[5]+ 0.46497*spectralNum[6] -0.02702*spectralNum[7] -0.24468*spectralNum[8] -0.01993*spectralNum[9];
Z=1.95010*spectralNum[0]+ 6.45490*spectralNum[1]+ 2.78010*spectralNum[2]+ 0.18501*spectralNum[3]+ 0.15325*spectralNum[4]+ 0.09539*spectralNum[5]+ 0.10563*spectralNum[6]+ 0.08866*spectralNum[7] -0.61140*spectralNum[8] -0.00938*spectralNum[9];
x=X/(X+Y+Z);
y=Y/(X+Y+Z);
n=(x-0.3320)/(0.1858-y);
cdc=437*n*n*n+ 3601 *n*n +6831 *n+ 5517;
return (int)cdc;
}
//RGB颜色计算函数
#include <math.h> // 使用C标准数学库(如sqrtf/powf)
// 颜色结果结构体(C99兼容)
typedef struct {
unsigned char R, G, B; // RGB分量(0-255)
float H, S, V; // HSV分量(H:0-360, S/V:0-100)
} ColorResult;
// 辅助函数:限制浮点数范围
static inline float clamp_float(float val, float min, float max) {
return (val < min) ? min : (val > max) ? max : val;
}
// 主函数:计算环境光颜色(C99兼容)
ColorResult calculate_light_color(const uint16_t spectralNum[10]) {
ColorResult result = {0, 0, 0, 0.0f, 0.0f, 0.0f};
float X, Y, Z, R, G, B;
// === 1. 计算XYZ三刺激值(整数运算优化) ===
int32_t X_tmp =
398 * spectralNum[0] + 1295 * spectralNum[1] + 370 * spectralNum[2] +
109 * spectralNum[3] + 719 * spectralNum[4] + 1782 * spectralNum[5] +
1101 * spectralNum[6] - 40 * spectralNum[7] - 276 * spectralNum[8] - 23 * spectralNum[9];
int32_t Y_tmp =
14 * spectralNum[0] + 167 * spectralNum[1] + 235 * spectralNum[2] +
1428 * spectralNum[3] + 1887 * spectralNum[4] + 1142 * spectralNum[5] +
465 * spectralNum[6] - 27 * spectralNum[7] - 245 * spectralNum[8] - 20 * spectralNum[9];
int32_t Z_tmp =
1950 * spectralNum[0] + 6455 * spectralNum[1] + 2780 * spectralNum[2] +
185 * spectralNum[3] + 153 * spectralNum[4] + 95 * spectralNum[5] +
106 * spectralNum[6] + 89 * spectralNum[7] - 611 * spectralNum[8] - 9 * spectralNum[9];
// 转换为浮点(之前放大了1000倍)
X = (float)X_tmp / 1000.0f;
Y = (float)Y_tmp / 1000.0f;
Z = (float)Z_tmp / 1000.0f;
// === 2. XYZ转RGB(sRGB标准矩阵) ===
R = 3.2406f * X - 1.5372f * Y - 0.4986f * Z;
G = -0.9689f * X + 1.8758f * Y + 0.0415f * Z;
B = 0.0557f * X - 0.2040f * Y + 1.0570f * Z;
// 伽马校正
R = (R > 0.0031308f) ? (1.055f * powf(R, 1.0f/2.4f) - 0.055f) : 12.92f * R;
G = (G > 0.0031308f) ? (1.055f * powf(G, 1.0f/2.4f) - 0.055f) : 12.92f * G;
B = (B > 0.0031308f) ? (1.055f * powf(B, 1.0f/2.4f) - 0.055f) : 12.92f * B;
// 限制到0-255并赋值
result.R = (unsigned char)(clamp_float(R * 255.0f, 0.0f, 255.0f));
result.G = (unsigned char)(clamp_float(G * 255.0f, 0.0f, 255.0f));
result.B = (unsigned char)(clamp_float(B * 255.0f, 0.0f, 255.0f));
// === 3. RGB转HSV ===
float rgb_max = fmaxf(fmaxf(R, G), B);
float rgb_min = fminf(fminf(R, G), B);
float delta = rgb_max - rgb_min;
// 计算色相H
if (delta <= 0.001f) { // 避免浮点误差
result.H = 0.0f;
} else if (rgb_max == R) {
result.H = fmodf(60.0f * ((G - B) / delta) + 360.0f, 360.0f);
} else if (rgb_max == G) {
result.H = 60.0f * ((B - R) / delta) + 120.0f;
} else {
result.H = 60.0f * ((R - G) / delta) + 240.0f;
}
// 计算饱和度S和明度V
result.V = rgb_max * 100.0f;
result.S = (rgb_max > 0.001f) ? (delta / rgb_max) * 100.0f : 0.0f;
return result;
}
ColorResult calculate_light_color_fixed(const uint16_t spectralNum[10]) {
ColorResult result = {0, 0, 0, 0.0f, 0.0f, 0.0f};
float X, Y, Z, R, G, B;
// === 1. 归一化传感器数据 ===
float normalized[10];
for (int i = 0; i < 10; i++) {
normalized[i] = spectralNum[i] / 65535.0f; // 根据实际传感器位深调整
}
// === 2. 计算XYZ(使用原始浮点系数) ===
// 使用归一化数据计算XYZ(系数无需额外放大)
X = 0.39814f * normalized[0] + 1.29540f * normalized[1] + 0.36956f * normalized[2]
+ 0.10902f * normalized[3] + 0.71942f * normalized[4] + 1.78180f * normalized[5]
+ 1.10110f * normalized[6] - 0.03991f * normalized[7] - 0.27597f * normalized[8]
- 0.02347f * normalized[9];
Y = 0.01396f * normalized[0] + 0.16748f * normalized[1] + 0.23538f * normalized[2]
+ 1.42750f * normalized[3] + 1.88670f * normalized[4] + 1.14200f * normalized[5]
+ 0.46497f * normalized[6] - 0.02702f * normalized[7] - 0.24468f * normalized[8]
- 0.01993f * normalized[9];
Z = 1.95010f * normalized[0] + 6.45490f * normalized[1] + 2.78010f * normalized[2]
+ 0.18501f * normalized[3] + 0.15325f * normalized[4] + 0.09539f * normalized[5]
+ 0.10563f * normalized[6] + 0.08866f * normalized[7] - 0.61140f * normalized[8]
- 0.00938f * normalized[9];
// === 3. XYZ转RGB并限制范围 ===
R = clamp_float(3.2406f * X - 1.5372f * Y - 0.4986f * Z, 0.0f, 1.0f);
G = clamp_float(-0.9689f * X + 1.8758f * Y + 0.0415f * Z, 0.0f, 1.0f);
B = clamp_float(0.0557f * X - 0.2040f * Y + 1.0570f * Z, 0.0f, 1.0f);
// 伽马校正
R = (R > 0.0031308f) ? (1.055f * powf(R, 1.0f/2.4f) - 0.055f) : 12.92f * R;
G = (G > 0.0031308f) ? (1.055f * powf(G, 1.0f/2.4f) - 0.055f) : 12.92f * G;
B = (B > 0.0031308f) ? (1.055f * powf(B, 1.0f/2.4f) - 0.055f) : 12.92f * B;
// 输出RGB
result.R = (unsigned char)(clamp_float(R * 255.0f, 0.0f, 255.0f));
result.G = (unsigned char)(clamp_float(G * 255.0f, 0.0f, 255.0f));
result.B = (unsigned char)(clamp_float(B * 255.0f, 0.0f, 255.0f));
// === 4. RGB转HSV ===
float rgb_max = fmaxf(fmaxf(R, G), B);
float rgb_min = fminf(fminf(R, G), B);
float delta = rgb_max - rgb_min;
// 计算HSV
result.V = clamp_float(rgb_max * 100.0f, 0.0f, 100.0f); // 强制限制V在0-100%
result.S = (rgb_max > 0.001f) ? (delta / rgb_max) * 100.0f : 0.0f;
/* 色相H计算保持不变 */
// 计算色相H
if (delta <= 0.001f) { // 避免浮点误差
result.H = 0.0f;
} else if (rgb_max == R) {
result.H = fmodf(60.0f * ((G - B) / delta) + 360.0f, 360.0f);
} else if (rgb_max == G) {
result.H = 60.0f * ((B - R) / delta) + 120.0f;
} else {
result.H = 60.0f * ((R - G) / delta) + 240.0f;
}
return result;
}
// 校准后的颜色计算函数
ColorResult calculate_light_color_calibrated(const uint16_t spectralNum[10]) {
ColorResult result = {0, 0, 0, 0.0f, 0.0f, 0.0f};
float normalized[10];
// 1. 归一化并补偿红外干扰
for (int i = 0; i < 10; i++) {
normalized[i] = spectralNum[i] / 65535.0f;
}
normalized[5] = fmaxf(0, normalized[5] - 0.1f * normalized[9]); // 红光通道NIR补偿
// 2. CIE视效函数加权(简化版)
const float cie_weights[8] = {0.01f, 0.12f, 0.45f, 0.85f, 0.92f, 0.78f, 0.25f, 0.03f};
for (int i = 0; i < 8; i++) {
normalized[i] *= cie_weights[i];
}
// 3. 修正后的XYZ转换(针对AS7341优化)
float X = 1.20f * normalized[0] + 0.35f * normalized[1] - 0.15f * normalized[2]
+ 0.05f * normalized[3] + 0.80f * normalized[4] + 1.50f * normalized[5]
+ 0.95f * normalized[6] + 0.30f * normalized[7];
float Y = 0.02f * normalized[0] + 0.25f * normalized[1] + 1.20f * normalized[2]
+ 0.90f * normalized[3] + 0.60f * normalized[4] + 0.40f * normalized[5]
+ 0.15f * normalized[6] + 0.05f * normalized[7];
float Z = 0.01f * normalized[0] + 0.10f * normalized[1] + 0.50f * normalized[2]
+ 0.30f * normalized[3] + 0.10f * normalized[4] + 0.05f * normalized[5];
// 4. XYZ转RGB(sRGB标准)
float R = clamp_float( 3.2406f * X - 1.5372f * Y - 0.4986f * Z, 0.0f, 1.0f);
float G = clamp_float(-0.9689f * X + 1.8758f * Y + 0.0415f * Z, 0.0f, 1.0f);
float B = clamp_float( 0.0557f * X - 0.2040f * Y + 1.0570f * Z, 0.0f, 1.0f);
// 伽马校正
R = (R > 0.0031308f) ? (1.055f * powf(R, 1.0f/2.4f) - 0.055f) : 12.92f * R;
G = (G > 0.0031308f) ? (1.055f * powf(G, 1.0f/2.4f) - 0.055f) : 12.92f * G;
B = (B > 0.0031308f) ? (1.055f * powf(B, 1.0f/2.4f) - 0.055f) : 12.92f * B;
// 输出RGB
result.R = (unsigned char)(clamp_float(R * 255.0f, 0.0f, 255.0f));
result.G = (unsigned char)(clamp_float(G * 255.0f, 0.0f, 255.0f));
result.B = (unsigned char)(clamp_float(B * 255.0f, 0.0f, 255.0f));
// 5. RGB转HSV
float rgb_max = fmaxf(fmaxf(R, G), B);
float rgb_min = fminf(fminf(R, G), B);
float delta = rgb_max - rgb_min;
result.V = rgb_max * 100.0f;
result.S = (rgb_max > 0.001f) ? (delta / rgb_max) * 100.0f : 0.0f;
if (delta <= 0.001f) {
result.H = 0.0f;
} else if (rgb_max == R) {
result.H = fmodf(60.0f * ((G - B) / delta) + 360.0f, 360.0f);
} else if (rgb_max == G) {
result.H = 60.0f * ((B - R) / delta) + 120.0f;
} else {
result.H = 60.0f * ((R - G) / delta) + 240.0f;
}
return result;
}