Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] HTS221 Humidity and Temperature sensing problem with MikroC and PIC

Status
Not open for further replies.

BiNa2605

Full Member level 3
Joined
Sep 1, 2015
Messages
179
Helped
6
Reputation
12
Reaction score
4
Trophy points
18
Location
VietNam
Activity points
1,357
Hi all,

Does anyone work with HTS221 of ST using MikroC? I used I2C to communicate with that chip but when I read the sensing signals from HTS221, I think I have errors. I always read value 79 from any register :bang:.

I used RB0, RB1 and configure them as SCK and SDA in I2C. I uploaded whole of my codes and the signals that I captured by an oscilloscope. Any recommendations and suggestions will be high appreciated. Many thanks.


HTS221.png

Code:
#define W_SAD 0xBE
#define R_SAD 0xBF

sbit SDA at RB0_bit;
sbit SCL at RB1_bit;

sbit SDA_D at TRISB0_bit;

void GPIO_Init();
void HTS221_Init();
void HTS221_Start();
void HTS221_Stop();
void HTS221_ACK();
void HTS221_NACK();
void HTS221_Write(unsigned char address);
unsigned char HTS221_uRead(unsigned char address);
char HTS221_cRead(unsigned char address);

void main() {
     unsigned char data0_temp[8], data0_humid[8];
     unsigned char ucSensor;
     char data1_temp[8], data1_humid[8];
     char Temperature[2], Humidity[2];
     int H0=0, H1=0, H2=0, H3=0;
     int T0=0, T1=0, T2=0, T3=0;
     int temp=0, humi=0;
     float fTemp=0, fHumidity=0;
     int raw=0;
     
     GPIO_Init();
     HTS221_Init();
     
     while(1)
     {
               PORTB.B5 = 1;
               //Reading calibration values
               //H0_rH_x2 0x30 register address - u8
               data0_humid[0] = HTS221_uRead(0x30);
               H0 =  data0_humid[0]/2;
               //H1_rH_x2 0x31 register address - u8
               data0_humid[1] = HTS221_uRead(0x31);
               H1 = data0_humid[1]/2;
               //H0_T0_OUT 0x36 0x37 - s16
               data1_humid[0] = HTS221_cRead(0x36);  //Lower Byte
               data1_humid[1] = HTS221_cRead(0x37);  //Higher Byte
               H2 = data1_humid[1]*256+data1_humid[0];
               //H1_T0_OUT 0x3A 0x3B - s16
               data1_humid[2] = HTS221_cRead(0x3A);  //Lower Byte
               data1_humid[3] = HTS221_cRead(0x3B);  //Higher Byte
               H3= data1_humid[3]*256+data1_humid[2];

               //T0_degC_x8 0x32 register address - u8
               data0_temp[0] = HTS221_uRead(0x32);
               T0 = data0_temp[0];
               //T1_degC_x8 0x33 register address - u8
               data0_temp[1] = HTS221_uRead(0x33);
               T1 = data0_temp[1];
               //T1/T0 msb 0x35 - u2
               data0_temp[2] = HTS221_uRead(0x35);
               raw = data0_temp[2];
               T0 = ((raw & 0x03)*256) + T0;
               T1 = ((raw & 0x0C)*64) + T1;
               //T0_OUT 0x3C 0x3D - s16
               data1_temp[0] = HTS221_cRead(0x3C);   //Lower Byte
               data1_temp[1] = HTS221_cRead(0x3D);   //Higher Byte
               T2 = data1_temp[1]*256 + data1_temp[0];
               //T1_OUT 0x3E 0x3F - s16
               data1_temp[2] = HTS221_cRead(0x3E);   //Lower Byte
               data1_temp[3] = HTS221_cRead(0x3F);   //Higher Byte
               T3 = data1_temp[3]*256 + data1_temp[2];

               //Reading Humidity and Temperature output
               //H_OUT 0x28 0x29 - s16
               Humidity[0] = HTS221_cRead(0x28);
               Humidity[1] = HTS221_cRead(0x29);
               //T_OUT 0x2A 0x2B - s16
               Temperature[0] = HTS221_cRead(0x2A);
               Temperature[1] = HTS221_cRead(0x2B);

               humi = Humidity[1]*256+Humidity[0];
               temp = Temperature[1]*256+Temperature[0];
               if(temp > 32767)
               {
                     temp-= 65536;
               }
               fHumidity = ((1.0 * H1) - (1.0 * H0)) * (1.0 * humi - 1.0 * H2) / (1.0 * H3 - 1.0 * H2) + (1.0 * H0);
               fTemp = ((T1 - T0) / 8.0) * (temp - T2) / (T3 - T2) + (T0 / 8.0); // Temperature in Celcius

               UART1_Write(Humidity[1]);
     }
}

//Initialize GPIO and I2C protocol for measuring sensing signal
void GPIO_Init()
{
     ANSELC = 0;
     ANSELB = 0;
     TRISB = 0;
     //PORTB = 0;
     TRISC = 0;
     //PORTC = 0;
     OSCCON = 0b01011011;        //Internal Oscillator 1Mhz
     //I2C1_Init(100000);          //Initialize I2C communication
     //I2C1_Start();
     
     
     UART1_Init(9600);
     delay_ms(300);
}

//HTS221 Start I2C communication
void HTS221_Start()
{
     SDA_D = 0; // Data output
     SDA = 1;
     SCL = 1;
     delay_us(10);
     SDA = 0;
     //delay_us(10);
}

//HTS221 Stop I2C communication
void HTS221_Stop()
{
     SDA_D = 0;
     SDA = 0;
     SCL = 1;
     delay_us(10);
     SDA = 1;
     //delay_us(100);
}

//HTS221 Ackowledgement
void HTS221_ACK()
{
     SDA_D = 0;
     SDA = 0;
     SCL = 0;
     delay_us(1);
     SCL = 1;
     delay_us(2);
     SCL = 0;
     delay_us(1);
     SDA = 1;
}

//HTS221 Not Ackowledgement
void HTS221_NACK()
{
     SDA_D = 0;
     SDA = 1;
     SCL = 0;
     delay_us(1);
     SCL = 1;
     delay_us(2);
     SCL = 0;
     delay_us(1);
     SDA = 0;
}

//Write data to HTS221 based on register address
void HTS221_Write(unsigned char CMD)
{
     unsigned char i;
     unsigned char j = CMD;
     SDA_D = 0;      //Write function so SDA_D is OUTPUT
     for(i=0x80; i>0; i/=2)
     {
          SCL = 0;
          //delay_us(1);
          if(i & j)        //AND SCL and DATA if
          {
             SDA = 1;      //SDA = 1 value
          }
          else
          {
             SDA = 0;      //SDA = 0 value
          }
          SCL = 1;
          //delay_us(1);
     }
}

//Read data from HTS221 based on register address, return unsigned char value
unsigned char HTS221_uRead(unsigned char CMD)
{
     unsigned char ucData=0;
     int i=0;
     HTS221_Start();
     HTS221_Write(W_SAD);
     HTS221_Write(CMD);

     HTS221_Start();       //Repeat Start
     HTS221_Write(R_SAD);
     SDA_D = 1;
     SCL = 0;
     delay_us(1);
     SCL = 1;
     while(SDA==1);
        delay_us(200);
     for(i=0; i<8; i++)
     {
              ucData <<= 1;
              SCL = 0;
              if(SDA == 1)
                     ucData = ucData | 0x01;
              SCL = 1;
     }
     HTS221_Stop();
     return ucData;
}

//Read data from HTS221 based on register address, return unsigned char value
char HTS221_cRead(unsigned char CMD)
{
     char cData=0;
     int i=0;
     HTS221_Start();
     HTS221_Write(W_SAD);
     HTS221_Write(CMD);
     
     HTS221_Start();       //Repeat Start
     HTS221_Write(R_SAD);
     SDA_D = 1;
     SCL = 0;
     delay_us(1);
     SCL = 1;
     while(SDA==1);
        delay_us(200);
     for(i=0; i<8; i++)
     {
              cData <<= 1;
              SCL = 0;
              if(SDA == 1)
                     cData = cData | 0x01;
              SCL = 1;
     }
     HTS221_Stop();
     return cData;
}

//Initialize HTS211 Humidity and Temperature sensor
void HTS221_Init()
{
     HTS221_Start();
     HTS221_Write(W_SAD);
     HTS221_Write(0x10);     //AV_CONF
     HTS221_Write(0x1B);     //Temperature average samples = 16; Humidity average samples = 32
     HTS221_Stop();
     
     //Configure Active Mode, 1Hz @ODR, not continuous update 0x20
     HTS221_Start();
     HTS221_Write(W_SAD);
     HTS221_Write(0x20);
     HTS221_Write(0x85);
     HTS221_Stop();
}

HTS221 datasheet:
**broken link removed**

References:
C language: https://github.com/ControlEverythingCommunity/HTS221/blob/master/C/HTS221.c
Arduino : https://github.com/ControlEverythingCommunity/HTS221/blob/master/Arduino/HTS221.ino
 

Hi,

Maybe a timing problem.
The conversion data rate is low. Maybe you need to wait until conversion is finished.

Klaus
 
@KlauST: you mean in the Read function I should wait until the conversion is finished. May I can use an interrupt?
 

Hi,

No, not "in the READ function",
but you should READ - wait - READ -

***
What debugging have you done so far?
--> does the sensor send ACK?
--> Read status byte: and show H_DA and T_DA.
--> show raw (HEX) data read from the I2C

Your scope picture shows 8 clock cycles only. I expect 9. ( 8 data + 1 ACK)

Why the bit bang mode? Doesn´t your uC has I2C perifieral?

Klaus
 

Your I2C handling seems basically wrong. At least SDA should be operated as open drain, means you will be toggling the direction bit SDA_D while SDA is programmed to 0.

Fix the I2C handling and check that you get correct waveforms according to the Philips/NXP I2C protocol specification. The waveform in the screenshot is completely wrong.
 

@FvM: I really appreciate your suggestions but could you tell me more in detail. Which are parts in the waveforms wrong?
In my circuit, I used pull-up resistor for both SCK and SDA and I change the direction of SDA_D from Write to Read depending on my purpose.
@KlausSt: my uC I used that is PIC16F1513 and it has I2C function but the same pin was used for SPI so I took another pin and try to configure them as same as I2C communication. I will do more experiments later.
 

Hi,

I change the direction of SDA_D from Write to Read
SDA and SCL are never driven actively HIGH by the controller. Either high_impedance or driven_LOW. It is open_collector or open_drain style .

Details:
Did you read I2C specification? If not, then I strongly recommend to do so.
--> Where is the ninth clock pulse?

Klaus
 

@KlausST: may you check for me?
tek00000.png

I write 0xBE(W_Add), 0x30 (Register Add), 0xBF(R_Add) and then read 8 bit value.
 
Last edited:

Hi,

Look at typical timing diagrams.
Especially the ACK handling...and the timing of SCK...and the signal until first bit of next byte...

After transmitting the 8th bit
.. SCK is pulled low to begin ACK handling
.. during ACK_Low period the ACK (= Low) is asserted, either by master or slave
.. (keeping timing) the master detects the ACK and answers with SCK_low (this is what I miss in your scope picture
.. SCK remains LOW between two transmitted bytes.

Klaus
 
@KlausST: Actually I understood what you said but I did still not solve my problem.
Picture1.jpg
this is my Write function:

Code:
//Write data to HTS221 based on register address
void HTS221_Write(unsigned char CMD)
{
     unsigned char i;
     unsigned char j = 128;
     SDA_D = 0;      //Write function so SDA_D is OUTPUT
     for(i=1; i<=8; i++)
     {
          SCL = 0;
          if(CMD & j)
          {
             SDA = 1;      //SDA = 1 value
          }
          else
          {
             SDA = 0;      //SDA = 0 value
          }
          SCL = 1;

          CMD <<= 1;
     }

     //Checking acknowledgement pulse
     SDA_D = 1;
     SCL = 0;
     while(!SDA);
     SCL = 1;
}
 
Last edited:

Hi,

It seems you still refuse to accept I2C specifications.

From your code it seems you are driving sometimes SDA actively HIGH. This is not allowed! (Already mentioned in post#7)
Short circuit currents may occur (if you keep on specification, then short circuit is impossible). This may lead to IC damage.

And it seems the short circuit really happens inyour case.
See SDA line at about 2.6ms after trigger. It is clean low, then it reaches about 0.4V then it goes back to zero.
At the point wher it reaches 0.4V I assume you try to drive SDA line HIGH, but the slave forces it LOW.
Btw.: This is also at the beginning of your communication.. before trigger event.

--> Don´t be surprised if an IC gets damaged.

Klaus
 
@Klaus: I tried again just only a write function with a captured screen. I get problem with a read function. How stupid am I. I will post a read function and a figure later. Could you check for me?
tek00002.png

- - - Updated - - -

And for Read function and a capture:
tek00003.png
 

:bang::bang::sad::sad: I read all 0,0 values.
Write function:
Code:
//Write data to HTS221 based on register address
void HTS221_Write(unsigned char CMD)
{
     unsigned char i;
     unsigned char j = 128;

     for(i=1; i<=8; i++)
     {
          SCL = 0;
          if(CMD & j)
          {
             SDA = 1;      //SDA = 1 value
          }
          else
          {
             SDA = 0;      //SDA = 0 value
          }
          SCL = 1;
          CMD <<= 1;
     }

     SDA = 1;
     SCL = 0;
     i2c_dly();
     while(SDA_IN);
     SCL = 1;
}

I2C Read function:
Code:
//I2C read function
unsigned char i2c_rx(char ack)
{
  char x, d=0;
  SDA = 1;
  for(x=0; x<8; x++) {
    d <<= 1;
    do {
      SCL = 0;
    }
    while(SCL_IN==0);    // wait for any SCL clock stretching
    i2c_dly();
    if(SDA_IN==1) d |= 1;
    SCL = 1;
  }
  if(ack) SDA = 0;
  else SDA = 1;
  SCL = 0;
  i2c_dly();             // send (N)ACK bit
  SCL = 1;
  SDA = 1;
  return d;
}

Read 1 byte from IC chip:
Code:
//Read data from HTS221 based on register address, return unsigned char value
unsigned char HTS221_uRead(unsigned char CMD)
{
     unsigned char ucData=0;
     int i=0;
     i2c_start();
     HTS221_Write(W_SAD);
     HTS221_Write(CMD);

     i2c_start();       //Repeat Start
     HTS221_Write(R_SAD);
     ucData = i2c_rx(0);
     i2c_stop();
     return ucData;
     delay_ms(250);
}

@zuisti: Could you check for me please?
 

Hi,

again: Read I2C specification.
There are goode internet pages, that explain everything in detail.
Example: https://www.i2c-bus.org/addressing/

Compare your waveforms with the specified waveforms.

I2C_iisue.PNG
Just two issues, maybe there are more....
* Why is there no ACK after addressing?
* Correct the bad timing after seinding the first byte
* add an ACK cycle after the first byte.

The same as I did with your scope picture... you could do also. Just comparing pictures...

Klaus
 
I changed my code to receive an ACK after write byte (after 8 bits).
Code:
//Write data to HTS221 based on register address
void HTS221_Write(unsigned char CMD)
{
     unsigned char i;
     unsigned char j = 128;

     for(i=1; i<=8; i++)
     {
          SCL = 0;
          if(CMD & j)
          {
             SDA = 1;      //SDA = 1 value
          }
          else
          {
             SDA = 0;      //SDA = 0 value
          }
          SCL = 1;
          CMD <<= 1;
     }
     //SDA = 0;
     SCL = 0;
     i2c_dly();
     SCL = 1;
     while(SDA_IN);
}

tek00004.png

But I still receive a wrong data. I will try the next step.
@KlausST: That is right or wrong Sir? I changed another IC chip.
 

The latest Write routine is wrong in so far that it doesn't release SDA before reading acknowledge.

It's also not right to wait for acknowledge. The write transaction will be either acknowledged or not acknowledged, but SDA won't change any more while SCL is high.

Finally, unless you redefined SDA in your code (you only showed a definition in post #1)
Code:
sbit SDA at RB0_bit;
SDA will be still set high and low in push-pull mode, which is not correct as verbosely explained before.
 
@FvM: I redefined SDA, thanks Sir
Code:
#define SCL     TRISB.F1 // I2C bus
#define SDA     TRISB.F0 //
#define SCL_IN  RB1    //
#define SDA_IN  RB0    //

- - - Updated - - -

@KlausST: in post #16, I have a problem with my code. For the ACK checking I programmed wrong codes.
For checking ACK pulse after LSB bit.
Code:
SDA = 1;
SCL = 0;
i2c_dly();
while(SDA_IN == 0);    //
SCL = 1;

I did not receive ACK pulse from Sensor. Until now I did not solve that problem.
 

Hi,

Although I am not familiar with PIC and MicroC...
I assume
SDA = 1..is driving active HIGH.

If this is the case ... and you are not willing to correct this...we can not help anymore.

SDA must never be driven high --> instead it should be released, = high Z
SCL must never be driven high --> instead it should be released, = high Z

Klaus
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top