本帖最后由 EPTmachine 于 2023-11-30 23:03 编辑
I2C外设使用以光照传感器信息读取
I2C接口是很多传感器使用的通讯接口,在低功耗应用中,传感器的使用也是很普遍的。本文使用开发板的I2C接口来读取ISL29035光照传感器的数据。
1.硬件准备
通过查看原理图可知,PB8、PB9为Arduino接口上的I2C引脚。本文使用I2C接口与ISL29035光照传感器通讯,获得环境中的光照强度信息。
本文中使用到的传感器的原理图如图所示。
与传感器通讯的的I2C接口选择Arduino接口上的PB8和PB9,传感器模块和开发板的实物连接图如下图所示。
2.程序编写
首先,在STM32 CubeIDE中创建开发板的工程,选择根据开发板创建工程,
在CubeMX界面中会自动初始化开发板上的部分外设,比如串口、调试口、LED等,本文通过I2C1控制传感器,使用的PB8和PB9,选择对应管脚的复用功能,并在I2C的配置界面选择相应的I2C通讯参数,这里使用的参数是默认的配置。
完成上述操作后,保存配置并生成相应的外设初始化代码。
传感器ISL29035的功能框图如下图所示。
通过I2C向指令寄存器中写值,配置传感器的参数和控制传感器采样;从数据寄存器中读取采样的结果,用于计算光照值。驱动传感器工作需要实现以下几个函数。
uint8_t DigitalLightISL29035_readRegister(uint8_t reg_address);
void DigitalLightISL29035_writeRegister( int reg_address, uint8_t val) ;
int DigitalLightISL29035_init(void) ;
uint32_t DigitalLightISL29035_readIRLux(void);
其中的读取和写入寄存器的函数是驱动传感器工作的基础函数。这两个函数的具体实现如下。
void DigitalLightISL29035_writeRegister( int reg_address, uint8_t val) {
uint8_t ii[2]={0x00,0x00};
ii[0] = reg_address;
ii[1] = val;
if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)ISL29035_I2C_ADDRESS_W, ii, 0x02,10000) != HAL_OK)
{
/* Error_Handler() function is called when error occurs. */
Error_Handler();
}
/*##- Wait for the end of the transfer #################################*/
/* Before starting a new communication transfer, you need to check the current
state of the peripheral; if it�s busy you need to wait for the end of current
transfer before starting a new one.
For simplicity reasons, this example is just waiting till the end of the
transfer, but application may perform other tasks while transfer operation
is ongoing. */
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
{
}
}
uint8_t DigitalLightISL29035_readRegister(uint8_t reg_address) {
uint8_t value;
if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)ISL29035_I2C_ADDRESS_W, ®_address, 0x01,10000) != HAL_OK)
{
/* Error_Handler() function is called when error occurs. */
Error_Handler();
}
/*##- Wait for the end of the transfer #################################*/
/* Before starting a new communication transfer, you need to check the current
state of the peripheral; if it�s busy you need to wait for the end of current
transfer before starting a new one.
For simplicity reasons, this example is just waiting till the end of the
transfer, but application may perform other tasks while transfer operation
is ongoing. */
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
{
}
/* Read data back from the I2C slave */
if (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)ISL29035_I2C_ADDRESS_R, (uint8_t *)&value, 0x01,10000) != HAL_OK)
{
/* Error_Handler() function is called when error occurs. */
Error_Handler();
}
/*##- Wait for the end of the transfer #################################*/
/* Before starting a new communication transfer, you need to check the current
state of the peripheral; if it�s busy you need to wait for the end of current
transfer before starting a new one.
For simplicity reasons, this example is just waiting till the end of the
transfer, but application may perform other tasks while transfer operation
is ongoing. */
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
{
}
return value;
}
本文采用传感器的单次转换模式来获取光照强度的信息,传感器在该模式下会接收到单次转换指令后转换一次环境中的光照值,MCU通过I2C读取数据寄存器中缓存的光照强度转换值,对其根据一定规则换算,可以得到光照强度值。
通过阅读传感器的数据手册可知传感器的寄存的分布如下图
通过向COMMAND-I和COMMAND-II指令寄存器中写入控制字,从而实现控制传感器的采样精度、采样时间、工作模式等。从DATA数据寄存器中读取转换完成的数据。
值得注意的一点是在数据手册中,ID寄存器的第7位需要在开始时确定其处于复位的状态。
配合数据手册中的信息,传感器的初始化函数如下:
int DigitalLightISL29035_init(void) {
uint8_t reg = 0;
reg= DigitalLightISL29035_readRegister( CHIP_ID);//CHIP_ID->0x0f
//Serial.println(reg, HEX);
uint8_t chip_id = (reg >> 3) & 0x7;
if (chip_id != 0x5) {
return -1;
}
//清除BOUT位
DigitalLightISL29035_writeRegister(CHIP_ID, reg & 0x7f);//CHIP_ID->0x0f
//确保芯片处于停止模式
DigitalLightISL29035_writeRegister( COMMAND_I, 0);//COMMAND_I->0x00
//设置分辨率
DigitalLightISL29035_writeRegister(COMMAND_II, full_scale_lux_range | (integration_time << 2) );//COMMAND_2->0x01
//设置为单次模式
DigitalLightISL29035_writeRegister( COMMAND_I, OPMODE_ALS_ONCE);//COMMAND_I->0x00
return 0;
}
完成初始化后,编写启动传感器单次转换并读取传感器的数据转换为光照强度数据。函数如下:
uint32_t DigitalLightISL29035_readIRLux(void) {
uint16_t data = 0;
uint8_t l, h;
//设置为单次模式
DigitalLightISL29035_writeRegister( COMMAND_I, OPMODE_ALS_ONCE);
//等待时间
if(integration_time==0)
{
HAL_Delay(105);
}
else if(integration_time==1 || integration_time==2)
{
HAL_Delay(7);
}
else if(integration_time==3)
{
HAL_Delay(1);
}
l=DigitalLightISL29035_readRegister(DATA_L);//DATA_L->0x02
h=DigitalLightISL29035_readRegister(DATA_H);//DATA_H->0x03
data=(h << 8) | l;
uint32_t ranges=0;
if(full_scale_lux_range==0)
ranges=1000;
else if(full_scale_lux_range==1)
ranges=4000;
else if(full_scale_lux_range==2)
ranges=16000;
else if(full_scale_lux_range==3)
ranges=64000;
uint32_t adc_count_max=0;
if(integration_time==0)
adc_count_max=65536;
else if(integration_time==1)
adc_count_max=4096;
else if(integration_time==2)
adc_count_max=256;
else if(integration_time==3)
adc_count_max=16;
return ranges * (uint32_t)data /adc_count_max;
}
以上为传感器的驱动函数,在主函数中调用传感器的初始化函数,在主循环中,循环调用获取光照强度的函数,并通过串口打印数据。主函数代码如下:
/* USER CODE BEGIN 2 */
DigitalLightISL29035_init();
HAL_Delay(500);
lux = DigitalLightISL29035_readIRLux();
printf("lux is %ld",lux);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(1000);
lux = DigitalLightISL29035_readIRLux();
printf("lux=%ld\n",lux);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
实际的运行效果如下所示。
3.总结
STM32的CubeMX工具和丰富的外设示例代码,可以帮助工程师快速完成应用的开发,实现系统原型的搭建。
|