[GD32L233C-START 评测] 【GD32L233C-START评测】13、I2C驱动环境光和接近传感器RPR-0521RS

freeelectron   2022-1-27 17:52 楼主

相关文章:

【GD32L233C-START评测】1、优点与缺点都很明显的GD32L233C-START(开箱)

【GD32L233C-START评测】2、非阻塞方式点灯,blink,blink,blink……

【GD32L233C-START评测】3、pwm实现呼吸灯

【GD32L233C-START评测】4、串口不定长数据接收

【GD32L233C-START评测】5、Flash读写——使用内部Flash存储数据

【GD32L233C-START评测】6、硬件I2C驱动0.96吋OLED

 

【GD32L233C-START评测】7、硬件SPI1驱动RC522

【GD32L233C-START评测】8、获取MCU96位唯一ID、SRAM、FLASH大小

【GD32L233C-START评测】9、IAP程序升级——基于YMODEM协议

【GD32L233C-START评测】10、使用内部参考电压校准adc,adc采样更准确

【GD32L233C-START评测】11、GD32 ISP软件还不支持GD32L233

 

【GD32L233C-START评测】12、按键——外部中断

0、前言

很早以前评估过的一次传感器,再次移植到GD32L233上,在【GD32L233C-START评测】6、硬件I2C驱动0.96吋OLED一文中只有硬件I2C的写,本文涉及到硬件I2C的读。

 

1、关于GD32L233L的硬件I2C

可查看【GD32L233C-START评测】6、硬件I2C驱动0.96吋OLED

 

2、硬件连接

image.png GD32       传感器

3V3          VDD

GND        GND

PB10        SCL

PB11        SDA

 

3、I2C驱动

这里要注意,读写之前,要先设置传输的数据长度;

从机地址实际上设置的是8位写地址;

写之前要设置为I2C_MASTER_TRANSMIT,如果写完之后,想继续读,那么要先结束一次i2c传输,重新开始读取,要设置为I2C_MASTER_RECEIVE。

void _I2cInit(void)
{
	rcu_periph_clock_enable(RCU_I2C1);
	rcu_periph_clock_enable(RCU_GPIOB);

	gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_10);
    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_11);

    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
	
    /* configure I2C timing */
	i2c_timing_config(I2C1, 0, 0x3, 0);
    i2c_master_clock_config(I2C1, 0x13, 0x36);
	
    /* configure I2C address */
    i2c_address_config(I2C1, 0x72, I2C_ADDFORMAT_7BITS);
    /* configure slave address */
    i2c_master_addressing(I2C1, RPR0521RS_I2C_ADDE, I2C_MASTER_TRANSMIT);
    /* configure number of bytes to be transferred */
    i2c_transfer_byte_number_config(I2C1, 2);
    /* enable I2C1 */
    i2c_enable(I2C1);	
}


void RPR0521RS_WriteRegU8(uint8_t reg,uint8_t var)
{
	i2c_transfer_byte_number_config(I2C1, 2);
	i2c_master_addressing(I2C1, RPR0521RS_I2C_ADDE, I2C_MASTER_TRANSMIT);
	
	/* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
	
    /* wait until the transmit data buffer is empty */
    I2C_STAT(I2C1) |= I2C_STAT_TBE;
    while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));

	/* data transmission */
	i2c_data_transmit(I2C1, reg);
    /* wait until the TI bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
	
	i2c_data_transmit(I2C1, var);
    /* wait until the TI bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
	
    /* wait for transfer complete flag */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TC));
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C1);
    /* wait until stop condition generate */
    while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
    /* clear the STPDET bit */
    i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
}


uint8_t  RPR0521RS_ReadRegU8(uint8_t reg)
{
	uint8_t temp=0;
	
	i2c_transfer_byte_number_config(I2C1, 1);
	i2c_master_addressing(I2C1, RPR0521RS_I2C_ADDE, I2C_MASTER_TRANSMIT);
	
	/* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
	
    /* wait until the transmit data buffer is empty */
    I2C_STAT(I2C1) |= I2C_STAT_TBE;
    while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));

	/* data transmission */
	i2c_data_transmit(I2C1, reg);
    /* wait until the TI bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
	
	    /* wait for transfer complete flag */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TC));
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C1);
    /* wait until stop condition generate */
    while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
    /* clear the STPDET bit */
    i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
	
	
	i2c_transfer_byte_number_config(I2C1, 1);
	i2c_master_addressing(I2C1, RPR0521RS_I2C_ADDE, I2C_MASTER_RECEIVE);
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
	
	while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE)) {};
     /* read a data from I2C_DATA */
    temp= i2c_data_receive(I2C1);

    /* wait for transfer complete flag */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TC));
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C1);
    /* wait until stop condition generate */
    while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
    /* clear the STPDET bit */
    i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
	
	return  temp;
}



uint16_t  RPR0521RS_ReadRegU16(uint8_t reg)
{		
	uint16_t templ=0,temph=0;
	
	i2c_transfer_byte_number_config(I2C1, 1);
	i2c_master_addressing(I2C1, RPR0521RS_I2C_ADDE, I2C_MASTER_TRANSMIT);
	
	/* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
	
    /* wait until the transmit data buffer is empty */
    I2C_STAT(I2C1) |= I2C_STAT_TBE;
    while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));

	/* data transmission */
	i2c_data_transmit(I2C1, reg);
    /* wait until the TI bit is set */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
	
	    /* wait for transfer complete flag */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TC));
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C1);
    /* wait until stop condition generate */
    while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
    /* clear the STPDET bit */
    i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
	
	
	i2c_transfer_byte_number_config(I2C1, 2);
	i2c_master_addressing(I2C1, RPR0521RS_I2C_ADDE, I2C_MASTER_RECEIVE);
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C1);
	
	while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE)) {};
     /* read a data from I2C_DATA */
    templ= i2c_data_receive(I2C1);
		
	while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE)) {};
     /* read a data from I2C_DATA */
    temph= i2c_data_receive(I2C1);

    /* wait for transfer complete flag */
    while(!i2c_flag_get(I2C1, I2C_FLAG_TC));
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C1);
    /* wait until stop condition generate */
    while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET));
    /* clear the STPDET bit */
    i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
	
	return  ((temph<<8)+templ);;
}

 

5、传感器特性

  • IIC接口,支持全速模式
  • 非常广的光照度检测范围
  • 距离检测范围1-100mm
  • 内置电流可配置IrLED驱动器
  • 主要用于LCD显示等
  • 供电电压2.5-3.6V
  • 运行温度-25~85℃(非工业级)

5、传感器寄存器

image.png  

6、软件驱动
6.1、寄存器定义以及参数设置定义
#define  RPR0521RS_I2C_ADDE   0x70 

#define  SYSTEM_CONTROL      0x40
           //SW reset[7]
         #define  RESET_NOT_START         0x00
         #define  RESET_START              0x80
           //INT reset[6]
         #define  INT_NOT_INIT             0x00
         #define  INT_INACTIVE             0x40
           //Part ID[5:0]  ,only read ,value 0x0A

#define  MODE_CONTROL        0x41
           //ALS_EN[7]
         #define   ALS_STANDBY             0x00
         #define   ALS_ENABLE              0x80
           //PS_EN[6]
         #define   PS_STANDBY              0x00
         #define   PS_ENABLE               0x40
           //PS_PULSE[5]
         #define   PULSE_WIDTH_200         0x00
         #define   PULSE_WIDTH_330         0x20
           //PS Operating mode[4]
         #define   NORMAL_MODE           0x00
         #define   TWICE_MODE              0x10
           //Measurement time[3:0]
         #define   STANDBY_STANDBY         0x00
         #define   STANDBY_10MS            0x01
         #define   STANDBY_40MS            0x02
         #define   STANDBY_100MS           0x03
         #define   STANDBY_400MS           0x04
         #define   _100MS_50MS             0x05
         #define   _100MS_100MS            0x06
         #define   _100MS_400MS            0x07
         #define   _400MS_50MS             0x08
         #define   _400MS_100MS            0x09
         #define   _400MS_STANDBY          0x0A
         #define   _400MS_400MS            0x0B
         #define   _50MS_50MS              0x0C
          //0x0D 0x0E 0x0F forbidden 

#define  ALS_PS_CONTROL      0x42
          //Reserved[7:6]
          //ALS DATA0 GAIN[5:4]
         #define  ALS_DATA0_GAIN_1         0x00
         #define  ALS_DATA0_GAIN_2         0x10
         #define  ALS_DATA0_GAIN_64        0x20
         #define  ALS_DATA0_GAIN_128       0x30
          //ALS DATA1 GAIN[3:2]
         #define  ALS_DATA1_GAIN_1         0x00
         #define  ALS_DATA1_GAIN_2         0x04
         #define  ALS_DATA1_GAIN_64        0x08
         #define  ALS_DATA1_GAIN_128       0x0A
          //LED CURRENT[1:0]
         #define  CURRENT_25MA            0x00
         #define  CURRENT_50MA            0x01
         #define  CURRENT_100MA           0x02
         #define  CURRENT_200MA           0x03

#define  PS_CONTROL          0x43
          //Ambient_Ir_Flag[7:6]
         #define  LEVLE_LOW                0x00
         #define  LEVLE_HIGH                0x40
         #define  LEVLE_TOO_HIGH           0xA0
          //PS_GAIN[5:4]
         #define  PS_GAIN_1                0x00
         #define  PS_GAIN_2                0x10
         #define  PS_GAIN_4                0x20
         //0x30 forbidden
         //PS interrupt persistence setting 
         #define  ACTIVE_EACH_MEASUREMENT  0x00
         #define  UPDATE_EACH_MEASUREMENT  0x01
         #define  UPDATE_TWO_CON_TH        0x02
         #define  ACTIVE_SET_CON_TH          0x03

#define  PS_DATA_LSB         0x44
#define  PS_DATA_MSB        0x45
#define  ALS_DATA0_LSB       0x46
#define  ALS_DATA0_MSB      0x47
#define  ALS_DATA1_LSB       0x48
#define  ALS_DATA1_MSB      0x49
#define  INTERRUPT           0x4A
         //PS INT STAUTS[7]
         #define  PS_SIGNAL_INACTIVE      0x00
         #define  PS_SIGNAL_ACTIVE        0x80
         //ALS INT STATUS[6]
         #define  ALS_SIGNAL_INACTIVE     0x00
         #define  ALS_SIGNAL_ACTIVE       0x40
         //INT MODE[5:4]
         #define  PS_TH_H_EFFECTIVE              0x00
         #define  PS_TH_H_PS_TH_L_EFFECTIVE_H    0x10
         #define  PS_TH_H_PS_TH_L_EFFECTIVE_D    0x20
         //INT ASSERT[3]
         #define  OUTPUT_L_SATBLE                0x00
         #define  OUTPUT_L_ASSERT                0x08
         //INT LATCH[2]
         #define INT_PIN_LATCH           0x00
         #define INT_PIN_UPDATE          0x04

         //INT TRIG[1:0]
         #define INT_PIN_INACTIVE         0x00
         #define TRIG_ONLY_PS            0x01
         #define TRIG_ONLY_ALS           0x02
         #define TRIG_PS_ALS             0x03

#define  PS_TH_LSB            0x4B
#define  PS_TH_MSB           0x4C
#define  PS_TL_LSB            0x4D
#define  PS_TL_MSB            0x4E
#define  ALS_DATA0_TH_LSB     0x4F
#define  ALS_DATA0_TH_MSB    0x50
#define  ALS_DATA0_TL_LSB      0x51
#define  ALS_DATA0_TL_MSB    0x52
#define  PS_OFFSET_LSB       0x53
#define  PS_OFFSET_MSB       0x54
         //Resereved[7:2]

#define  MANUFACT_ID         0x92   
         //only read ,value 0xE0
6.2、读取设备ID
设备ID一般都是一个固定值,芯片出厂的时候已经固化在芯片里面了,只读,可用于检测I2C通信是否正常、检测芯片是否存在。

image.png

void RPR0521RSCheck(void)
{
	uint8_t  chip_id=0;

	chip_id=RPR0521RS_ReadRegU8(MANUFACT_ID);

	if(chip_id==0xE0)
	{
		printf("device exist\r\n");
	}
	else
	{
		printf("device not exist\r\n");
	}
}
6.3、芯片初始化以及参数设定

image.png image.png   

void RPR0521RSInit(void)
{
   RPR0521RS_WriteRegU8(SYSTEM_CONTROL,RESET_START);  //复位初始化
RPR0521RS_WriteRegU8(ALS_PS_CONTROL,ALS_DATA0_GAIN_1|ALS_DATA1_GAIN_1|
CURRENT_100MA);  //ALS DATA0和DATA1的增益均配置为1、LED电流配置为100ma
   
   RPR0521RS_WriteRegU8(PS_CONTROL,PS_GAIN_1);   //PS增益设置为1
   RPR0521RS_WriteRegU8(MODE_CONTROL,ALS_ENABLE|PS_ENABLE|_100MS_100MS);  
//模式设置:ALS和PS都使能、测量时间ALS和PS均为100ms。
}

6.4、读取数据

image.png  可以看出,PS的值是12位的,ALS DATA0DATA116位的。距离值直接从寄存器里面读出来,是数字量;照度值从寄存器里面读出来后,需要做转换,与设置的增益和转换时间有关系。

image.png  

uint8_t als_gain_table[] = {1, 2, 64, 128};//根据手册中的增益
uint16_t als_meas_time_table[] = {0,0,0,0,0,100,100,100,100,100,400,400,50,0,0,0};//als的测量时间定义

float RPR0521RSConvertLx(uint16_t *als_count) //als数字量,转化为实际值
{
	uint8_t  als_data0_gain,als_data1_gain;
	uint16_t als_measure_time;
	uint8_t mode_control_value,als_ps_control_value;

	mode_control_value=RPR0521RS_ReadRegU8(MODE_CONTROL);
	als_ps_control_value=RPR0521RS_ReadRegU8(ALS_PS_CONTROL);

	als_measure_time=als_meas_time_table[mode_control_value&0x0F];  //取低四位的值

	als_data0_gain=als_gain_table[(als_ps_control_value>>4)&0x03]; //取第五第六位的值
	als_data1_gain=als_gain_table[(als_ps_control_value>>2)&0x03];

	if(als_data0_gain==0)
	{
	return -1;
	}
	if(als_data1_gain==0)
	{
	return -1;
	}
	if(als_measure_time==0)
	{
	return -1;
	}
	else
	{
	if(als_measure_time==50)
	{
	  if((als_count[0]&0x8000)==0x8000)
	  {
		als_count[0] = 0x7FFF;
	  }
	  
	  if((als_count[1]&0x8000)==0x8000)
	  {
		als_count[1] = 0x7FFF;
	  }
	}
	}

	float lx;
	float d0, d1, d1_d0;

	d0 = (float)als_count[0] * (100 / als_measure_time) / als_data0_gain;
	d1 = (float)als_count[1] * (100 / als_measure_time) / als_data0_gain;

	if (d0 == 0) 
	{
	lx = 0;
	return (lx);
	}

	d1_d0 = d1 / d0;

	if (d1_d0 < 0.595) 
	{
	lx = (1.682 * d0 - 1.877 * d1);
	} 
	else 
	{
	if (d1_d0 < 1.015) 
	{
	  lx = (0.644 * d0 - 0.132 * d1);
	} 
	else 
	{
	  if (d1_d0 < 1.352)
	  {
		lx = (0.756 * d0 - 0.243 * d1);
	  } 
	  else
	  {
		if (d1_d0 < 3.053)
		{
		  lx = (0.766 * d0 - 0.25 * d1);
		} 
		else 
		{
		  lx = 0;
		}
	  }
	}
	}
	return (lx);
}

6.5、传感器初始化以及轮询读取

void RPR0521RSInit(void)
{
//	_I2C_Init();
	_I2cInit();
	
	RPR0521RS_WriteRegU8(SYSTEM_CONTROL,RESET_START);  //复位初始化
	RPR0521RS_WriteRegU8(ALS_PS_CONTROL,ALS_DATA0_GAIN_1|ALS_DATA1_GAIN_1|CURRENT_100MA);  //ALS DATA0和DATA1的增益均配置为1、LED电流配置为100ma
   
	RPR0521RS_WriteRegU8(PS_CONTROL,PS_GAIN_1);   //PS增益设置为1
	RPR0521RS_WriteRegU8(MODE_CONTROL,ALS_ENABLE|PS_ENABLE|_100MS_100MS);  
	//模式设置:ALS和PS都使能、测量时间ALS和PS均为100ms。
	
	RPR0521RSCheck();
}
void RPR0521RSRead(void)
{
	uint16_t ps_count;
	uint16_t als_count[2];

	float ps ,lx;
	static uint32_t tick=0;

	if(SystemGetTick()-tick>3000)
	{
		ps_count=RPR0521RS_ReadRegU16(PS_DATA_LSB);
		als_count[0]=RPR0521RS_ReadRegU16(ALS_DATA0_LSB);
		als_count[1]=RPR0521RS_ReadRegU16(ALS_DATA1_LSB);

		ps=ps_count;
		lx=RPR0521RSConvertLx(als_count);

		printf("\r\nps_count:%d\r\n",ps_count);
		printf("als_count0:%d\r\n",als_count[0]);
		printf("als_count1:%d\r\n",als_count[1]);

		printf("proximity sensor:%f\r\n",ps);
		printf("ambient light:%0.3f lx\r\n\r\n",lx);	
		
		tick =SystemGetTick();
	}
}

7、现象

image.png  可以看出,手靠近传感器的变化,proximity sensor的值逐渐增大,Ambient light的值逐渐减小。

 

本帖最后由 freeelectron 于 2022-2-7 13:04 编辑
stm32/LoRa物联网:304350312

回复评论 (1)

抓了一下i2c的速率

image.png

 

image.png    

stm32/LoRa物联网:304350312
点赞  2022-1-27 18:03
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复