I originally planned to modify the example and add the function of serial port outputting temperature and humidity data, but I don't have the J-LINK download tool for the time being. At the same time, I saw that some forum friends tried to download and burn but failed. So I thought it would be better to directly intercept the data on the I2C bus. In this way, I don't need to make any changes to the original evaluation board, and I can just use my expansion board. So I used a ready-made STM32L412 board for the experiment. The following figure shows the experimental setup:
The I2C data on the evaluation board was obtained through a logic analyzer. The evaluation board reads and writes the sensor once per second:
The actual operation is to write the command first, then wait for nearly 1 second before reading it out, so the timing diagram captured from the logic analyzer is read first and written later:
The read operation is to send the address code 139 first, and then read out 6 bytes of data continuously:
From the data sheet, we know that the first 3 bytes are temperature data, that is, 16-bit temperature data plus 1-byte checksum, and the last 3 bytes are humidity data, also 16-bit humidity data plus 1-byte checksum:
The command written is a 16-bit command, the address code is 138:
Based on these data, I wrote a piece of code to read out these 6 bytes of data. The following is the code for reading the I2C bus:
Read a byte:
/******************************************************
*Program name: Read_I2C
*Function: Read data on the I2C bus
*Input parameter: None
*Return parameter: Read data (1 byte)
******************************************************/
uint8_t Read_I2C(void)
{
uint8_t dat,i;
//Start reading one byte of data
for(i=0;i<8;i++){
while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 0);
dat <<= 1;
if(HAL_GPIO_ReadPin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin) == 1) dat |= 0x01;
while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 1);
}
return dat;
}
Here is the code to read all the data:
/******************************************************
*Program name: Intercept_I2C
*Function: intercept read data on I2C bus
*Input parameter: None
*Return parameter:
******************************************************/
void Intercept_I2C(void)
{
uint8_t i,d[7];
uint32_t temp=0,hum=0;
uint32_t d_t,d_h;
//Wait for I2C start signalwhile
(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin)==1){
while(HAL_GPIO_ReadPin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin)==1);
}
// while(Read_I2C() != 139) //Read address appears on the I2C bus
for(i = 0; i < 7; i++)
d = Read_I2C();
/*
temp = Read_I2C(); //Get the upper eight bits
temp <<= 8;
temp |= (uint16_t )Read_I2C();
hum = Read_I2C(); //Check byte (discarded)
hum = Read_I2C();
hum <<= 8;
hum |= (uint16_t )Read_I2C();
*/
d_t = d[1];
d_t <<= 8;
d_t |= d[2];
// temp = (d_t * 175 / 65535) - 45;
temp = d_t *1000 / 267 - 4500;
d_h = d[4];
d_h <<= 8;
d_h |= d[5];
hum = d_h * 10000 / 65535;
LCD_write_value(12,3,5,0,1,temp);
LCD_write_value(12,4,5,0,1,hum);
LCD_write_value(50,3,5,0,1,d_t);
LCD_write_value(50,4,5,0,1,d _h);
LCD_write_value(0,0,3,0,1,d[0]);
// LCD_write_value(24,0,3,0,1,d[0]);
LCD_write_value(0,1,3,0,1,d[1]);
LCD_write_value(24,1,3,0,1,d[2]);
LCD_write_value(50,1,3,0,1,d[3]);
LCD_write_value(0,2,3,0,1,d[4]);
LCD_write_value(24,2,3,0,1,d[5]);
LCD_write_value(50,2,3,0,1,d[6]);
HAL_Delay(2);
}
After repeated tests, these data were basically read out, but they seemed not quite correct, especially the calculation process was incorrect, and the calculated temperature and humidity data were very different from the actual display. In the figure below, the first line is the read address code, the second and third lines are the temperature and humidity data and the check code, the blue circles are the read temperature and humidity data, and the red circles are the calculated temperature and humidity values, which are inconsistent with the actual display, especially the humidity data jumps and fluctuates, and is unstable.
According to the data sheet, the calculation formulas for temperature and humidity are as follows:
However, the data calculated by the code I wrote according to this formula is different from the manual calculation. I don’t know where the code is wrong. Here is the code:
d_t = d[1];
d_t <<= 8;
d_t |= d[2];
// temp = (d_t * 175 / 65535) - 45;
temp = d_t *1000 / 267 - 4500;
d_h = d[4];
d_h <<= 8;
d_h |= d[5];
hum = d_h * 10000 / 65535; //Round to two decimal places
I changed the variable type from 16-bit unsigned to 32-bit unsigned, but the result was still wrong.
I couldn't get the correct temperature and humidity values by manual calculation. I don't know where the problem lies.
When reading and writing I2C bus data, I ignored the ACK after each byte. Could this be the reason for the incorrect data acquisition? According to the timing diagram, 1 ACK is 3 microseconds, and the time to the start of the next byte is 5.125 microseconds, a total of 8.125 microseconds. I don't know how long it takes from the read byte function to the next re-entry, but this should not affect the synchronization, because reading the next byte is based on the SCL clock, unless the time to return to the next re-entry is less than 3 microseconds.
This content is originally created by EEWORLD forum user hujj . If you want to reprint or use it for commercial purposes, you must obtain the author's consent and indicate the source