第十一篇、CubeMX | 可见光谱颜色传感器 AS7341

简介


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;
}
相关推荐
黑白园4 小时前
STM32 printf函数重定向到USATR1输出打印
stm32·单片机·嵌入式硬件
踏着七彩祥云的小丑4 小时前
嵌入式——认识电子元器件——温度保险丝系列
单片机·嵌入式硬件
12.=0.4 小时前
【stm32_6.1】串行异步接口USART,串口的原理和应用
c语言·stm32·单片机·嵌入式硬件
雅斯驰5 小时前
4Gbit密度+16位总线宽度:H5AN4G6NBJR-UHC在DDR4成熟期的产品定位
运维·单片机·嵌入式硬件·物联网·自动化
weixin_456808385 小时前
【沁恒蓝牙开发】电压监控
单片机·嵌入式硬件
LCG元5 小时前
STM32实战:基于RT-Thread的STM32开发环境搭建与LED任务
stm32·单片机·嵌入式硬件
ye150127774555 小时前
220V转12V1000mA恒流驱动WT5112
单片机·嵌入式硬件·其他·硬件工程
青山_FPGA5 小时前
以太网 MAC-PHY 接口总结
嵌入式硬件·macos
振南的单片机世界5 小时前
函数调用时,返回地址和局部变量都存“栈”里
stm32·单片机·嵌入式硬件