#define I2C_ADDR 0x27 // I2C address of the LCD
#define RS_HIGH 0x01
#define RS_LOW 0x00
#define SHT3X_I2C_ADDRESS 0x44 // 7-bit I2C address
#define SHT3X_WRITE_ADDRESS (SHT3X_I2C_ADDRESS << 1) // Write address (0x88)
#define SHT3X_READ_ADDRESS (SHT3X_I2C_ADDRESS << 1 | 1) // Read address (0x89)
// Function declarations
void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);
void I2C_Write(uint8_t data);
uint8_t I2C_Read_ACK(void);
uint8_t I2C_Read_NACK(void);
void SHT3X_Init(void);
bool SHT3X_Read(float *temperature, float *humidity);
// Initialize I2C
void I2C_Init() {
TWSR = 0x00; // Set prescaler to 1
TWBR = 72; // Set bit rate register for 100kHz
TWCR = (1 << TWEN); // Enable TWI (I2C)
}
// Send I2C Start Condition
void I2C_Start() {
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // Send START condition
while (!(TWCR & (1 << TWINT))); // Wait for TWINT flag set
}
// Send I2C Stop Condition
void I2C_Stop() {
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN); // Send STOP condition
_delay_ms(1); // Delay to ensure stop is sent
}
// Write Data to I2C
void I2C_Write(uint8_t data) {
TWDR = data; // Load data into TWDR register
TWCR = (1 << TWINT) | (1 << TWEN); // Start transmission
while (!(TWCR & (1 << TWINT))); // Wait for TWINT flag set
}
// Read Byte with ACK
uint8_t I2C_Read_ACK(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA); // Enable ACK generation
while (!(TWCR & (1 << TWINT))); // Wait for TWINT flag to be set
return TWDR; // Return received data
}
// Read Byte with NACK
uint8_t I2C_Read_NACK(void) {
TWCR = (1 << TWINT) | (1 << TWEN); // No ACK after reception
while (!(TWCR & (1 << TWINT))); // Wait for TWINT flag to be set
return TWDR; // Return received data
}
// Initialize the SHT3x sensor with high repeatability and clock stretching
void SHT3X_Init(void) {
I2C_Start();
I2C_Write(SHT3X_WRITE_ADDRESS); // Send address with write bit
I2C_Write(0x2C); // Command for high repeatability with clock stretching
I2C_Write(0x06); // High precision mode
I2C_Stop();
_delay_ms(15); // Wait for measurement time (if not using clock stretching)
}
// Read temperature and humidity from SHT3x sensor
bool SHT3X_Read(float *temperature, float *humidity) {
uint16_t raw_temperature, raw_humidity;
uint8_t msb_temp, lsb_temp, msb_humidity, lsb_humidity;
I2C_Start();
I2C_Write(SHT3X_READ_ADDRESS); // Read from SHT3x
// Read temperature data
msb_temp = I2C_Read_ACK();
lsb_temp = I2C_Read_ACK();
I2C_Read_ACK(); // CRC byte (can be ignored for basic implementation)
// Read humidity data
msb_humidity = I2C_Read_ACK();
lsb_humidity = I2C_Read_ACK();
I2C_Read_NACK(); // CRC byte
I2C_Stop();
// Convert raw temperature and humidity data
raw_temperature = (msb_temp << 8) | lsb_temp;
raw_humidity = (msb_humidity << 8) | lsb_humidity;
// Convert to actual temperature and humidity
*temperature = -45 + 175 * ((float)raw_temperature / 65535.0);
*humidity = 100 * ((float)raw_humidity / 65535.0);
return true; // Return true if reading was successful
}
int main(void) {
float temperature, humidity;
I2C_Init();
Serial.begin(9600); // Initialize Serial at 9600 baud rate
SHT3X_Init(); // Initialize SHT3x sensor
while (1) {
if (SHT3X_Read(&temperature, &humidity)) {
// Display the temperature and humidity values
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print(" °C, Humidity: ");
Serial.print(humidity);
Serial.println(" %");
}
_delay_ms(1000); // Wait for 1 second before reading again
}
return 0;
}
void LCD_Init() {
_delay_ms(50); // Wait for LCD to power up
LCD_Send_Command(0x02); // Finally, set to 4-bit mode
// Configure the LCD in 2-line, 5x7 matrix, and turn on display
LCD_Send_Command(0x28); // 4-bit, 2-line, 5x7 matrix
LCD_Send_Command(0x0C); // Display ON, Cursor OFF, Blink OFF
LCD_Send_Command(0x01); // Clear display
_delay_ms(2);
LCD_Send_Command(0x06); // Increment cursor, no display shift
LCD_Send_Command(0x01); // Clear display command
_delay_ms(2);
}
void LCD_Write_String(const char* str) {
while (*str) {
LCD_Send_Data(*str++);
}
}
void LCD_Set_Cursor(uint8_t row, uint8_t col) {
uint8_t address = (row == 0) ? (0x80 + col) : (0xC0 + col);
LCD_Send_Command(address);
}
void LCD_Send_Command(uint8_t command) {
LCD_I2C_Write(command, RS_LOW); // Command mode
}
// Send data to LCD
void LCD_Send_Data(uint8_t data) {
LCD_I2C_Write(data, RS_HIGH); // Data mode
}
/*Summary of the Complete Communication Sequence
1. Start Condition – Master begins communication.
2. Send Address with Write Bit – Master addresses the sensor.
3. Send 16-bit Command – Master sends command to initiate measurement.
4. Stop Condition – Ends the command transmission.
5. Wait for Measurement Completion – Sensor performs measurement.
6. Start Condition – Master initiates data reading.
7. Send Address with Read Bit – Master tells the sensor it wants to read data.
8. Clock Stretching (if enabled) – Sensor holds the clock line if busy.
9. Receive Temperature and Humidity Data – Sensor sends data to master.
10. Stop Condition – Master completes the communication.
*/