Has anyone successfully interfaced this temp/humidity sensor with a PIC18F? I've been using Sensirion's sample code provided
I'm using Adafruit's SHT31 breakout board which already has the 10k pull up/down resistors. I think I'm getting close to getting readings but I am stuck at the moment and not sure which direction to go. I am getting waveforms on my oscilloscope for SDA/SCL lines.
I'm trying to output the temperature and humidity readings to my LCD but I'm not getting anything.
I'm using error handlers to see where it's getting stuck. Specifically in the main while loop it stops here:
//read status register
error |= SHT3X_ReadStatus(&status.u16);
if(error != NO_ERROR) {
LCDWriteStringXY(0,0,"Read Status Error");
}break;
Are my initializing parameters correct for the i2c and SHT31? Below are the main i2c and a portion of the sht3x source files. The entire project can be downloaded here: https://ufile.io/fwrhp (are external links allowed? It's too large to post here)
One thing I'd like to note is I have two delay functions. One is used for the menu and LCD files and the other is for sht31 and i2c files. I'm not sure if these two things might be causing a problem. I'll try to explore that next. Any help would be appreciated.
main.c
/******************************************************************************/
/* Files to Include */
/******************************************************************************/
#if defined(__XC)
#include <xc.h> /* XC8 General Include File */
#elif defined(HI_TECH_C)
#include <htc.h> /* HiTech General Include File */
#elif defined(__18CXX)
#include <p18cxxx.h> /* C18 General Include File */
#endif
#if defined(__XC) || defined(HI_TECH_C)
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#endif
#include "system.h" /* System funct/params, like osc/peripheral config */
#include "user.h" /* User funct/params, such as InitApp */
#include "lcd.h"
#include "config.h"
#include "port.h"
#include "damper.h"
#include "sht3x.h"
/******************************************************************************/
/* User Global Variable Declaration */
/******************************************************************************/
/* i.e. uint8_t <variable_name>; */
#define MSB(x) (((x)>>8)&0xFF)
#define LSB(x) ((x)&0xFF)
unsigned int sensor;
unsigned int CAL = 128;
float PressureVal;
int startup = TRUE;
int LCDWait;
int MEM;
/******************************************************************************/
/* Main Program */
/******************************************************************************/
// Delay Routine
void delay(unsigned int delay)
{
for(;delay;delay--)
__delay_us(100);
}
void mainScreen(void)
{
LCDWriteStringXY(0,0,"Temp: ");
LCDWriteStringXY(0,1,"RH% : ");
}
void main()
{
etError error; // error code
u32t serialNumber;// serial number
regStatus status; // sensor status
ft temperature; // temperature [°C]
ft humidity; // relative humidity [%RH]
bt heater; // heater, false: off, true: on
if(startup == TRUE)
{
ConfigureOscillator();
InitApp();
LCDBoot(); // call boot function for initializing LCD and startup screen
MemReadConfig();
KeyPadInit();
Counter();
GIE = 0;
LCDWait = TRUE;
GIE = 1;
GIEL = 1;
TMR0ON = 0;
startup = FALSE;
SHT3X_Init(0x44); // initialize SHT31 sensor on default 0x44 address
// wait 50ms after power on
DelayMicroSeconds(50000);
error = SHT3x_ReadSerialNumber(&serialNumber);
if(error == NO_ERROR){} // do error handling here
// demonstrate a single shot measurement with clock-stretching
error = SHT3X_GetTempAndHumi(&temperature, &humidity, REPEATAB_HIGH, MODE_CLKSTRETCH, 50);
if(error != NO_ERROR){} // do error handling here
// demonstrate a single shot measurement with polling and 50ms timeout
error = SHT3X_GetTempAndHumi(&temperature, &humidity, REPEATAB_HIGH, MODE_POLLING, 50);
if(error != NO_ERROR){} // do error handling here
}
while(1)
{
error = NO_ERROR;
// loop while no error
while(error == NO_ERROR)
{
if(LCDWait == TRUE)
{
write();
//read status register
error |= SHT3X_ReadStatus(&status.u16);
if(error != NO_ERROR) {
LCDWriteStringXY(0,0,"Read Status Error");
}break;
//check if the reset bit is set after a reset or power-up
// if(status.bits.ResetDetected)
// {
// // override default temperature and humidity alert limits
// error = SHT3X_SetAlertLimits( 70.0f, 50.0f, // high set: RH [%], T [°C]
// 68.0f, 48.0f, // high clear: RH [%], T [°C]
// 32.0f, -2.0f, // low clear: RH [%], T [°C]
// 30.0f, -4.0f); // low set: RH [%], T [°C]
// if(error != NO_ERROR) break;
//
// // clear reset and alert flags
// error = SHT3X_ClearAllAlertFlags();
// if(error != NO_ERROR) break;
//
// //start periodic measurement, with high repeatability and 1 measurements per second
// error = SHT3X_StartPeriodicMeasurment(REPEATAB_HIGH, FREQUENCY_1HZ);
// if(error != NO_ERROR) break;
//
// }
// read measurement buffer
error = SHT3X_ReadMeasurementBuffer(&temperature, &humidity);
if(error == ACK_ERROR)
{
error = NO_ERROR;
}
// else break;
if(LCDWait == TRUE) //If the LCD Menu is active then
{
mainScreen();
LCDWriteIntXY(6,0,temperature,2);
LCDWriteIntXY(6,1,humidity,2);
LCDTImer1();
}
}
// else {
// Modulate();
// }
}
// if(error != NO_ERROR)
// {
// LCDWriteStringXY(0,0,"Soft Resetting...");
// DelayMicroSeconds(1000);
// SHT3X_SoftReset();
// }
}
}
i2c initialization
/*
* File: i2c_hal.c
* Author: Johan.Andrade
*
* Created on September 22, 2017, 10:46 AM
* Brief : I2C hardware abstraction layer
============================================================================
*/
/******************************************************************************/
/* Files to Include */
/******************************************************************************/
#if defined(__XC)
#include <xc.h> /* XC8 General Include File */
#elif defined(HI_TECH_C)
#include <htc.h> /* HiTech General Include File */
#elif defined(__18CXX)
#include <p18cxxx.h> /* C18 General Include File */
#endif
#include "i2c_hal.h"
//-- Defines ------------------------------------------------------------------
#define MCUCLK 4000000 // 4MHz ( same as OSCCON)
#define I2C_SPEED 100000 // 100kHz
#define I2C_SSPADD ( ( MCUCLK / ( 4 * I2C_SPEED ) ) - 1 )
#if I2C_SSPADD > 255
#error "I2C_SPPED can not be greater that 255 ! Please adjust MCUCLK and I2C_SPEED"
#endif
// I2C IO-Pins /* -- adapt the defines for your uC -- */
// SDA on port B, bit 14
//#define SDA_LOW() (GPIOB->BSRR = 0x40000000) // set SDA to low
//#define SDA_OPEN() (GPIOB->BSRR = 0x00004000) // set SDA to open-drain
//#define SDA_READ (GPIOB->IDR & 0x4000) // read SDA
// PIC18F2420 SDA on PORTC RC4
#define SDA TRISCbits.TRISC4
#define SDA_IN PORTCbits.RC4
// SCL on port B, bit 13 /* -- adapt the defines for your uC -- */
//#define SCL_LOW() (GPIOB->BSRR = 0x20000000) // set SCL to low
//#define SCL_OPEN() (GPIOB->BSRR = 0x00002000) // set SCL to open-drain
//#define SCL_READ (GPIOB->IDR & 0x2000) // read SCL
// PIC18F2420 SCL on PORTC RC3
#define SCL TRISCbits.TRISC3
#define SCL_IN PORTCbits.RC3
//-- Static function prototypes -----------------------------------------------
static etError I2c_WaitWhileClockStreching(u8t timeout);
//-----------------------------------------------------------------------------
void I2c_Init(void) /* -- adapt the init for your uC -- */
{
//SSPCON1 = 0;
PIE1bits.SSPIE = 0; // Disable interrupt from I2C module
TRISC = 0b00011000; // Make SCL (RC3) SDA (RC4) to be inputs
SSPSTATbits.SMP = 1; // enable 100KHz & 1MHz
SSPSTATbits.CKE = 0; // I2C specification
SSPCON2bits.GCEN = 0; // disable interrupt when detect general call address on the i2c bus.
SSPADD = I2C_SSPADD;
SSPCON1 = 0x28; // Master mode, SSPEN enabled, I2C_Clock = ( Fosc / ( 4 * SSPADD ) ) - 1;
PIR1bits.SSPIF = 0;
}
//-----------------------------------------------------------------------------
void I2c_StartCondition(void)
{
// SDA_OPEN();
SDA = 1;
DelayMicroSeconds(1);
// SCL_OPEN();
SCL = 1;
DelayMicroSeconds(1);
// SDA_LOW();
SDA = 0;
DelayMicroSeconds(10); // hold time start condition (t_HD;STA)
// SCL_LOW();
SCL = 0;
DelayMicroSeconds(10);
}
//-----------------------------------------------------------------------------
void I2c_StopCondition(void)
{
// SCL_LOW();
SCL = 0;
DelayMicroSeconds(1);
// SDA_LOW();
SDA = 0;
DelayMicroSeconds(1);
// SCL_OPEN();
SCL = 1;
DelayMicroSeconds(10); // set-up time stop condition (t_SU;STO)
// SDA_OPEN();
SDA = 1;
DelayMicroSeconds(10);
}
//-----------------------------------------------------------------------------
etError I2c_WriteByte(u8t txByte)
{
etError error = NO_ERROR;
u8t mask;
for(mask = 0x80; mask > 0; mask >>= 1) // shift bit for masking (8 times)
{
if((mask & txByte) == 0)
// SDA_LOW(); // masking txByte, write bit to SDA-Line
SDA = 0;
else
// SDA_OPEN();
SDA = 1;
DelayMicroSeconds(1); // data set-up time (t_SU;DAT)
//SCL_OPEN(); // generate clock pulse on SCL
SCL = 1;
DelayMicroSeconds(5); // SCL high time (t_HIGH)
//SCL_LOW();
SCL = 0;
DelayMicroSeconds(1); // data hold time(t_HD;DAT)
}
//SDA_OPEN(); // release SDA-line
SDA = 1;
//SCL_OPEN(); // clk #9 for ack
SCL = 1;
DelayMicroSeconds(1); // data set-up time (t_SU;DAT)
//if(SDA_READ)
if(SDA_IN)
error = ACK_ERROR; // check ack from i2c slave
//SCL_LOW();
SCL = 0;
DelayMicroSeconds(20); // wait to see byte package on scope
return error; // return error code
}
//-----------------------------------------------------------------------------
etError I2c_ReadByte(u8t *rxByte, etI2cAck ack, u8t timeout)
{
etError error = NO_ERROR;
u8t mask;
*rxByte = 0x00;
//SDA_OPEN(); // release SDA-line
SDA = 1;
for(mask = 0x80; mask > 0; mask >>= 1) // shift bit for masking (8 times)
{
//SCL_OPEN(); // start clock on SCL-line
SCL = 1;
DelayMicroSeconds(1); // clock set-up time (t_SU;CLK)
error = I2c_WaitWhileClockStreching(timeout);// wait while clock stretching
DelayMicroSeconds(3); // SCL high time (t_HIGH)
//if(SDA_READ)
if(SDA_IN)
*rxByte |= mask; // read bit
//SCL_LOW();
SCL = 0;
DelayMicroSeconds(1); // data hold time(t_HD;DAT)
}
if(ack == ACK)
//SDA_LOW(); // send acknowledge if necessary
SDA = 0;
else
//SDA_OPEN();
SDA = 1;
DelayMicroSeconds(1); // data set-up time (t_SU;DAT)
//SCL_OPEN(); // clk #9 for ack
SCL = 1;
DelayMicroSeconds(5); // SCL high time (t_HIGH)
//SCL_LOW();
SCL = 0;
//SDA_OPEN(); // release SDA-line
SDA = 1;
DelayMicroSeconds(20); // wait to see byte package on scope
return error; // return with no error
}
//-----------------------------------------------------------------------------
etError I2c_GeneralCallReset(void)
{
etError error;
I2c_StartCondition();
error = I2c_WriteByte(0x00);
if(error == NO_ERROR)
error = I2c_WriteByte(0x06);
return error;
}
//-----------------------------------------------------------------------------
static etError I2c_WaitWhileClockStreching(u8t timeout)
{
etError error = NO_ERROR;
//while(SCL_READ == 0)
while(SCL_IN == 0)
{
if(timeout-- == 0)
return TIMEOUT_ERROR;
DelayMicroSeconds(1000);
}
return error;
}
SHT initialize (portion)
/*
* File: sht3x.c
* Author: Johan.Andrade
*
* Created on September 22, 2017, 10:46 AM
* Brief : I2C hardware abstraction layer
============================================================================
*/
/******************************************************************************/
/* Files to Include */
/******************************************************************************/
#if defined(__XC)
#include <xc.h> /* XC8 General Include File */
#elif defined(HI_TECH_C)
#include <htc.h> /* HiTech General Include File */
#elif defined(__18CXX)
#include <p18cxxx.h> /* C18 General Include File */
#endif
#include "sht3x.h"
#include "i2c_hal.h"
//-- Defines ------------------------------------------------------------------
// Generator polynomial for CRC
#define POLYNOMIAL 0x131 // P(x) = x^8 + x^5 + x^4 + 1 = 100110001
//=============================================================================
// IO-Pins /* -- adapt the defines for your uC -- */
//-----------------------------------------------------------------------------
// Reset on port B, bit 12
//#define RESET_LOW() (GPIOB->BSRR = 0x10000000) // set Reset to low
//#define RESET_HIGH() (GPIOB->BSRR = 0x00001000) // set Reset to high
// Alert on port B, bit 10
//#define ALERT_READ (GPIOB->IDR & 0x0400) // read Alert
//=============================================================================
//-- Global variables ---------------------------------------------------------
static u8t _i2cAddress; // I2C Address
//-- Static function prototypes -----------------------------------------------
static etError SHT3X_WriteAlertLimitData(ft humidity, ft temperature);
static etError SHT3X_ReadAlertLimitData(ft* humidity, ft* temperature);
static etError SHT3X_StartWriteAccess(void);
static etError SHT3X_StartReadAccess(void);
static void SHT3X_StopAccess(void);
static etError SHT3X_WriteCommand(etCommands command);
static etError SHT3X_Read2BytesAndCrc(u16t* data, etI2cAck finaleAckNack,
u8t timeout);
static etError SHT3X_Write2BytesAndCrc(u16t data);
static u8t SHT3X_CalcCrc(u8t data[], u8t nbrOfBytes);
static etError SHT3X_CheckCrc(u8t data[], u8t nbrOfBytes, u8t checksum);
static ft SHT3X_CalcTemperature(u16t rawValue);
static ft SHT3X_CalcHumidity(u16t rawValue);
static u16t SHT3X_CalcRawTemperature(ft temperature);
static u16t SHT3X_CalcRawHumidity(ft humidity);
//-----------------------------------------------------------------------------
void SHT3X_Init(u8t i2cAddress) /* -- adapt the init for your uC -- */
{
// init I/O-pins
// RCC->APB2ENR |= 0x00000008; // I/O port B clock enabled
//
// // Alert on port B, bit 10
// GPIOB->CRH &= 0xFFFFF0FF; // set floating input for Alert-Pin
// GPIOB->CRH |= 0x00000400; //
//
// // Reset on port B, bit 12
// GPIOB->CRH &= 0xFFF0FFFF; // set push-pull output for Reset pin
// GPIOB->CRH |= 0x00010000; //
// RESET_LOW();
//
I2c_Init(); // init I2C
SHT3X_SetI2cAdr(i2cAddress);
//
// // release reset
// RESET_HIGH();
}
//-----------------------------------------------------------------------------
void SHT3X_SetI2cAdr(u8t i2cAddress)
{
_i2cAddress = i2cAddress;
}
//-----------------------------------------------------------------------------
etError SHT3x_ReadSerialNumber(u32t* serialNumber)
{
etError error; // error code
u16t serialNumWords[2];
error = SHT3X_StartWriteAccess();
// write "read serial number" command
error |= SHT3X_WriteCommand(CMD_READ_SERIALNBR);
// if no error, start read access
if(error == NO_ERROR) error = SHT3X_StartReadAccess();
// if no error, read first serial number word
if(error == NO_ERROR) error = SHT3X_Read2BytesAndCrc(&serialNumWords[0], ACK, 100);
// if no error, read second serial number word
if(error == NO_ERROR) error = SHT3X_Read2BytesAndCrc(&serialNumWords[1], NACK, 0);
SHT3X_StopAccess();
// if no error, calc serial number as 32-bit integer
if(error == NO_ERROR)
{
*serialNumber = (serialNumWords[0] << 16) | serialNumWords[1];
}
return error;
}
User contributions licensed under CC BY-SA 3.0