[STM32U5] 【NUCLEO-U5A5ZJ-Q测评】I2C驱动使用以及驱动ISL29035光照传感器

[复制链接]
1464|1
 楼主| EPTmachine 发表于 2023-11-30 22:45 | 显示全部楼层 |阅读模式
本帖最后由 EPTmachine 于 2023-11-30 23:03 编辑

I2C外设使用以光照传感器信息读取
I2C接口是很多传感器使用的通讯接口,在低功耗应用中,传感器的使用也是很普遍的。本文使用开发板的I2C接口来读取ISL29035光照传感器的数据。
1.硬件准备
通过查看原理图可知,PB8、PB9为Arduino接口上的I2C引脚。本文使用I2C接口与ISL29035光照传感器通讯,获得环境中的光照强度信息。
本文中使用到的传感器的原理图如图所示。
80d38e44058d91a648969a9603ccf83b
与传感器通讯的的I2C接口选择Arduino接口上的PB8和PB9,传感器模块和开发板的实物连接图如下图所示。
28db607a6e9259dbd2b384e7ce9b99d0
2.程序编写
首先,在STM32 CubeIDE中创建开发板的工程,选择根据开发板创建工程,
在CubeMX界面中会自动初始化开发板上的部分外设,比如串口、调试口、LED等,本文通过I2C1控制传感器,使用的PB8和PB9,选择对应管脚的复用功能,并在I2C的配置界面选择相应的I2C通讯参数,这里使用的参数是默认的配置。
完成上述操作后,保存配置并生成相应的外设初始化代码。
传感器ISL29035的功能框图如下图所示。
5fe91af8eded8026dc9144aa2156278c
通过I2C向指令寄存器中写值,配置传感器的参数和控制传感器采样;从数据寄存器中读取采样的结果,用于计算光照值。驱动传感器工作需要实现以下几个函数。
  1. uint8_t DigitalLightISL29035_readRegister(uint8_t reg_address);
  2. void DigitalLightISL29035_writeRegister( int reg_address, uint8_t val) ;
  3. int DigitalLightISL29035_init(void) ;
  4. uint32_t DigitalLightISL29035_readIRLux(void);

其中的读取和写入寄存器的函数是驱动传感器工作的基础函数。这两个函数的具体实现如下。
  1. void DigitalLightISL29035_writeRegister( int reg_address, uint8_t val) {

  2.     uint8_t ii[2]={0x00,0x00};
  3.     ii[0] = reg_address;
  4.     ii[1] = val;

  5.         if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)ISL29035_I2C_ADDRESS_W, ii, 0x02,10000) != HAL_OK)
  6.         {
  7.         /* Error_Handler() function is called when error occurs. */
  8.         Error_Handler();
  9.         }

  10.         /*##- Wait for the end of the transfer #################################*/
  11.         /*  Before starting a new communication transfer, you need to check the current
  12.           state of the peripheral; if it�s busy you need to wait for the end of current
  13.           transfer before starting a new one.
  14.           For simplicity reasons, this example is just waiting till the end of the
  15.           transfer, but application may perform other tasks while transfer operation
  16.           is ongoing. */
  17.         while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  18.         {
  19.         }

  20. }
  1. uint8_t DigitalLightISL29035_readRegister(uint8_t reg_address) {

  2.     uint8_t value;


  3.         if (HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)ISL29035_I2C_ADDRESS_W, ®_address, 0x01,10000) != HAL_OK)
  4.         {
  5.         /* Error_Handler() function is called when error occurs. */
  6.         Error_Handler();
  7.         }

  8.         /*##- Wait for the end of the transfer #################################*/
  9.         /*  Before starting a new communication transfer, you need to check the current
  10.           state of the peripheral; if it�s busy you need to wait for the end of current
  11.           transfer before starting a new one.
  12.           For simplicity reasons, this example is just waiting till the end of the
  13.           transfer, but application may perform other tasks while transfer operation
  14.           is ongoing. */
  15.         while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  16.         {
  17.         }



  18.     /* Read data back from the I2C slave */

  19.         if (HAL_I2C_Master_Receive(&hi2c1, (uint16_t)ISL29035_I2C_ADDRESS_R, (uint8_t *)&value, 0x01,10000) != HAL_OK)
  20.         {
  21.         /* Error_Handler() function is called when error occurs. */
  22.         Error_Handler();
  23.         }

  24.         /*##- Wait for the end of the transfer #################################*/
  25.         /*  Before starting a new communication transfer, you need to check the current
  26.           state of the peripheral; if it�s busy you need to wait for the end of current
  27.           transfer before starting a new one.
  28.           For simplicity reasons, this example is just waiting till the end of the
  29.           transfer, but application may perform other tasks while transfer operation
  30.           is ongoing. */
  31.         while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  32.         {
  33.         }

  34.     return value;
  35. }
本文采用传感器的单次转换模式来获取光照强度的信息,传感器在该模式下会接收到单次转换指令后转换一次环境中的光照值,MCU通过I2C读取数据寄存器中缓存的光照强度转换值,对其根据一定规则换算,可以得到光照强度值。
通过阅读传感器的数据手册可知传感器的寄存的分布如下图
80845ceaca939324abc4998ed00f96be
通过向COMMAND-I和COMMAND-II指令寄存器中写入控制字,从而实现控制传感器的采样精度、采样时间、工作模式等。从DATA数据寄存器中读取转换完成的数据。
2da0c939a89edcf03a03ec6ad6f7b677
2adf867b9ded1f7075590b2d843fc565
值得注意的一点是在数据手册中,ID寄存器的第7位需要在开始时确定其处于复位的状态。
配合数据手册中的信息,传感器的初始化函数如下:
  1. int DigitalLightISL29035_init(void) {
  2.     uint8_t reg = 0;
  3.     reg=   DigitalLightISL29035_readRegister( CHIP_ID);//CHIP_ID->0x0f
  4.     //Serial.println(reg, HEX);
  5.     uint8_t chip_id = (reg >> 3) & 0x7;
  6.     if (chip_id != 0x5) {
  7.         return -1;
  8.     }

  9.     //清除BOUT位
  10.     DigitalLightISL29035_writeRegister(CHIP_ID, reg & 0x7f);//CHIP_ID->0x0f

  11.     //确保芯片处于停止模式
  12.     DigitalLightISL29035_writeRegister( COMMAND_I, 0);//COMMAND_I->0x00
  13.     //设置分辨率
  14.     DigitalLightISL29035_writeRegister(COMMAND_II, full_scale_lux_range | (integration_time << 2) );//COMMAND_2->0x01
  15.     //设置为单次模式
  16.     DigitalLightISL29035_writeRegister( COMMAND_I, OPMODE_ALS_ONCE);//COMMAND_I->0x00
  17.     return 0;
  18. }
完成初始化后,编写启动传感器单次转换并读取传感器的数据转换为光照强度数据。函数如下:
  1. uint32_t DigitalLightISL29035_readIRLux(void) {
  2.     uint16_t data = 0;
  3.     uint8_t l, h;
  4.     //设置为单次模式
  5.     DigitalLightISL29035_writeRegister( COMMAND_I, OPMODE_ALS_ONCE);
  6.     //等待时间
  7.     if(integration_time==0)
  8.     {
  9.             HAL_Delay(105);
  10.     }
  11.     else if(integration_time==1 || integration_time==2)
  12.     {
  13.             HAL_Delay(7);
  14.     }
  15.     else if(integration_time==3)
  16.     {
  17.             HAL_Delay(1);
  18.     }

  19.     l=DigitalLightISL29035_readRegister(DATA_L);//DATA_L->0x02
  20.     h=DigitalLightISL29035_readRegister(DATA_H);//DATA_H->0x03

  21.     data=(h << 8) | l;

  22.     uint32_t ranges=0;
  23.     if(full_scale_lux_range==0)
  24.         ranges=1000;
  25.     else if(full_scale_lux_range==1)
  26.         ranges=4000;
  27.     else if(full_scale_lux_range==2)
  28.         ranges=16000;
  29.     else if(full_scale_lux_range==3)
  30.         ranges=64000;

  31.     uint32_t adc_count_max=0;
  32.     if(integration_time==0)
  33.         adc_count_max=65536;
  34.     else if(integration_time==1)
  35.         adc_count_max=4096;
  36.     else if(integration_time==2)
  37.         adc_count_max=256;
  38.     else if(integration_time==3)
  39.         adc_count_max=16;
  40.     return ranges * (uint32_t)data /adc_count_max;
  41. }
以上为传感器的驱动函数,在主函数中调用传感器的初始化函数,在主循环中,循环调用获取光照强度的函数,并通过串口打印数据。主函数代码如下:
  1.   /* USER CODE BEGIN 2 */
  2.   DigitalLightISL29035_init();
  3.   HAL_Delay(500);
  4.   lux = DigitalLightISL29035_readIRLux();
  5.   printf("lux is %ld",lux);

  6.   /* USER CODE END 2 */

  7.   /* Infinite loop */
  8.   /* USER CODE BEGIN WHILE */
  9.   while (1)
  10.   {
  11.           HAL_Delay(1000);
  12.       lux = DigitalLightISL29035_readIRLux();
  13.       printf("lux=%ld\n",lux);
  14.     /* USER CODE END WHILE */

  15.     /* USER CODE BEGIN 3 */
  16.   }

实际的运行效果如下所示。
2e27f8977494277460a3d859846c69cc
3.总结
STM32的CubeMX工具和丰富的外设示例代码,可以帮助工程师快速完成应用的开发,实现系统原型的搭建。



U5A5ZJ_I2C_ISL29035.zip

1.43 MB, 下载次数: 0

ISL29035光照传感器_Schematic1_2022-12-10.pdf

48.64 KB, 下载次数: 0

REN_isl29035_DST_20100127.pdf

882.82 KB, 下载次数: 0

cr315 发表于 2023-12-12 09:27 | 显示全部楼层
代码框再搞标准一点就好了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

494

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部