View previous topic :: View next topic |
Author |
Message |
bmete
Joined: 13 Jul 2023 Posts: 37
|
SHT45 & SHT85 Humidity / Temp Sensors with PIC16F88 |
Posted: Thu Jul 13, 2023 12:52 am |
|
|
Hello dear friends,
I am working on a project that will communicate with PIC16F88 both sht45 and sht85 over i2c. As a result of my research for a long time, I saw that I could create software over the most suitable CCS C in the PIC model I mentioned. However, I could not create the i2c code of the PIC. I also checked the datasheets of the sensors, but since I only use the i2c protocol over the arduino, I could not understand the protocol I need to do. I found some sample codes and modified them according to myself and brought it to a point. I confirmed with the "get_ack_status" function that there is a device at address 0x88, but unfortunately I still cannot communicate with the sensor. Since I don't have a serial port or a screen to show the incoming data at the moment, I am testing the program with a more primitive led on and off method. I am sharing the code I wrote below, it would be very helpful if you could review my mistakes and tell me how to fix them.
Code:
Code: |
#include <16F88.h>
#include <main.h>
#fuses NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT
#use delay(clock=4000000)
#use i2c(Master, sda=PIN_B1, scl=PIN_B4)
#use FIXED_IO(A_outputs=PIN_A2,PIN_A3)
#define SHT85_BASE_ADDR 0x88
unsigned int8 wData[1] = SHT45_CMD_MEASURE_HPM;
int8 get_ack_status(int8 address)
{
int8 status;
i2c_start();
status = i2c_write(address); // Status = 0 if got an ACK
i2c_stop();
if(status == 0)
return(TRUE);
else
return(FALSE);
}
//=================================
void main()
{
status = get_ack_status(0x88);
while(TRUE)
{
i2c_start();
i2c_write(SHT85_BASE_ADDR);
i2c_write(0x24);
i2c_write(0x0B);
i2c_stop();
delay_ms(15);
i2c_start();
i2c_write(SHT85_BASE_ADDR | 0x01);
float temperature_humidity_raw = make16(i2c_read(), i2c_read());
i2c_read(); // CRC verisini oku ve geƧ
i2c_stop();
float temperature = -45.0 + 175.0 * (float)temperature_humidity_raw / 65535.0;
float humidity = 100.0 * (float)temperature_humidity_raw / 65535.0;
delay_ms(1000);
if (temperature > 30.0)
{
output_high(PIN_A2);
output_low(PIN_A3);
}
else
{
output_high(PIN_A3);
output_low(PIN_A2);
}
}
}
| [/code] |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Thu Jul 13, 2023 2:38 am |
|
|
Several of the things that might be problems you have already covered
by using get_ack_status.
I would be worried though that the two read calls may not execute left
to right in C. C does not guarantee the order of function parameter calls.
Try simply reading the two values one after the other, and then use a
separate make8 call.
Why are you sending a second byte after the 0x24 command?. The chip
does not want this. It shows all commands as being 8bits only.
The chip returns the reading after 0.1 second. You need a longer delay
after sending the command.
Code: |
byte valh, vall;
int16 temperature_raw
while(TRUE)
{
i2c_start();
i2c_write(SHT85_BASE_ADDR);
i2c_write(0x24); //command 0.1sec then return vals
i2c_stop();
delay_ms(105); //Allow 0.1sec plus margin
i2c_start();
i2c_write(SHT85_BASE_ADDR | 0x01);
valh=i2c_read(); //MSB
vall= i2c_read(); //LSB
temperature_raw = make16(valh, vall);
vall=i2c_read();
valh=I2c_read();
valh=I2c_read();
valh=i2c_read(); //dummy read of humidity bytes
i2c_stop();
float temperature = -45.0 + 175.0 * (temperature_raw / 65535.0);
delay_ms(1000);
if (temperature > 30.0)
{
output_high(PIN_A2);
output_low(PIN_A3);
}
else
{
output_high(PIN_A3);
output_low(PIN_A2);
}
}
}
|
Now I note that the data sheet says you can abort the command after
reading the 16bit value, without reading the CRC, but it does not at
any point talk about aborting after reading the temperature without
reading the humidity, which is what you are doing. I'd say it'd be
worth trying reading all six bytes. I show that above.
You don't need the casts. dividing by 65535.0 (a float value), forces
float arithmetic.
There is one major hardware issue you may have. The Arduino accepts
+2.4v as a 'high' for a signal. On your 5v PIC the signals have to go up
to just on 4v to be correctly seen as high. You could try wiring to a pair
of pins that support TTL inputs, and using software I2C. Pins A0/A1 for example. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Thu Jul 13, 2023 5:21 am |
|
|
Mr T's last paragraph was the 1st thing I thought of....
5 volt PIC, 3 volt peripheral issue....
Nowadays ,it'd probably be best to use a 3 volt PIC as 99.44% of all peripherals are 3 volt devices.
Also, the I2C pullups generally should be 4k7 for 5 volt, 3k3 for 3 volt. The peripheral, if it's a 'module' may or may not have pullups so best to check and measure. |
|
|
bmete
Joined: 13 Jul 2023 Posts: 37
|
|
Posted: Thu Jul 13, 2023 5:35 am |
|
|
Thank you very much for your quick reply my friend. I run the code and it works great. Actually I also need a humidity value so I am going to add it. But I just wanted to learn how to receive data from sensor.
So I modified the code for SHT45 to receive both humidity and temperature data. I checked the code and it looks like works good.
Code: |
i2c_start();
i2c_write(SHT45_BASE_ADDR);
i2c_write(0xFD); //command 0.1sec then return vals
i2c_stop();
delay_ms(105); //Allow 0.1sec plus margin
i2c_start();
i2c_write(SHT45_BASE_ADDR | 0x01);
valh = i2c_read(); //MSB
vall = i2c_read(); //LSB
temperature_raw = make16(valh, vall);
CRC = i2c_read();
valh = i2c_read();
vall = I2c_read();
humidity_raw = make16(valh, vall);
CRC = i2c_read(); //dummy read of humidity bytes
i2c_stop();
float temperature = -45.0 + 175.0 * (temperature_raw / 65535.0);
float humidity = -6.0 + 125.0 * (humidity_raw / 65535.0);
|
Quote: |
There is one major hardware issue you may have. The Arduino accepts
+2.4v as a 'high' for a signal. On your 5v PIC the signals have to go up
to just on 4v to be correctly seen as high. You could try wiring to a pair
of pins support TTL inputs, and using software I2C. Pins A0/A1 for example.
|
I'm thinking of a hardware design similar to what you said, but how do I configure the A0 and A1 pins to receive data from i2c as software? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Thu Jul 13, 2023 7:56 am |
|
|
#USE_I2C will automatically setup and use software I2C, if you tell it to
use pins that don't have the hardware. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 13, 2023 11:03 am |
|
|
According to the SHT85 datasheet, you're supposed to do a NACK after the
last i2c_read() statement. This is done by giving i2c_read() a parameter of 0.
Example: i2c_read(0);
On page 10 of the data sheet it says:
Quote: | The sensor will send the temperature value first and then the relative
humidity value. After having received the checksum for the humidity
value a NACK and stop condition should be sent (see Table8). |
SHT85 datasheet:
https://www.sensirion.com/media/documents/4B40CEF3/61642381/Sensirion_Humidity_Sensors_SHT85_Datasheet.pdf |
|
|
bmete
Joined: 13 Jul 2023 Posts: 37
|
|
Posted: Fri Jul 14, 2023 12:46 am |
|
|
Thank you for all your help.
I think I understood the procedure for reading data from sensors. Apart from that, there is one more thing I want to ask you. The card with 16f88 and the sensor will send the data it read from the sensor to the PIC on the other card via i2c in line with the message from another card. In this case, 16f88 will be the master for the sensor but the slave for the other PIC. How can I configure in such a case? Can I set the same chip as both master and slave? I guess I need to use Interrupt to wait for a message over I2C. It would be very helpful if you could give me a short example of the procedure for this or tell me which of the ready-made examples I can use. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Fri Jul 14, 2023 1:03 am |
|
|
No.
You will need to have two I2C busses. Use the hardware one for the slave.
(It is almost impossible to do a slave in software). Use a second software
I2C as master to talk to the chip.
There is a technical version of I2c (multi master), where more than one
master device can exist on a bus, your chip does not support this,
but even on this the same device cannot be a master and a slave.
I honestly have to repeat my suggestion on going to a newer PIC. The 88, is
very old chip, and lacks performance compared to newer devices. Many
will offer multiple I2C busses, and these would be much better. Also
more RAM and ROM (you will soon run out of space doing floating point
maths for this). |
|
|
bmete
Joined: 13 Jul 2023 Posts: 37
|
|
Posted: Tue Jul 18, 2023 12:27 am |
|
|
Thanks for all of your help guys. Now I need to do same procedure on HDC3022. I tried so many different things but there was no positive result. For this purpose can we argue this in this topic? Or do I need to open a new Topic for this? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Tue Jul 18, 2023 2:20 am |
|
|
The 3022, needs a two byte command, not the single byte for the SHT
Very different beasty. 24 00, not FD.... |
|
|
|