相关文章:
【GD32L233C-START评测】1、优点与缺点都很明显的GD32L233C-START(开箱)
【GD32L233C-START评测】2、非阻塞方式点灯,blink,blink,blink……
【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、硬件连接
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、传感器特性
5、传感器寄存器
#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
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");
}
}
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、读取数据
可以看出,PS的值是12位的,ALS DATA0和DATA1是16位的。距离值直接从寄存器里面读出来,是数字量;照度值从寄存器里面读出来后,需要做转换,与设置的增益和转换时间有关系。
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、现象
可以看出,手靠近传感器的变化,proximity sensor的值逐渐增大,Ambient light的值逐渐减小。
本帖最后由 freeelectron 于 2022-2-7 13:04 编辑