#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>
#define F_CPU 16000000UL
#define LCD_I2C_ADDR 0x27
// Definitions for LCD control bits
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
#define En 0b00000100 // Enable bit
#define Rw 0b00000010 // Read/Write bit
#define Rs 0b00000001 // Register select bit
//define the dht pin
#define DHT22_PIN PD2
//define the led pin
#define LED_PIN PH4
// Define the buzzer pin
#define BUZZER_PIN PE5
#define BUZZER_PORT PORTB
#define BUZZER_DDR DDRB
// Define the HX711 pins
#define HX711_DT_PIN PH3 // Connect HX711 DT pin to Arduino digital pin 7
#define HX711_SCK_PIN PA0 // Connect HX711 SCK pin to Arduino digital pin A0
// HX711
void hx711_init(void) {
DDRA |= (1 << HX711_SCK_PIN); // Set SCK as output
DDRH &= ~(1 << HX711_DT_PIN); // Set DT as input
}
long hx711_read(void) {
unsigned long count = 0;
unsigned char i;
PORTA &= ~(1 << HX711_SCK_PIN); // SCK pin low
while (PINH & (1 << HX711_DT_PIN)); // Wait until DT pin is low
for (i = 0; i < 24; i++) {
PORTA |= (1 << HX711_SCK_PIN); // SCK pin high
_delay_us(1);
count = count << 1;
PORTA &= ~(1 << HX711_SCK_PIN); // SCK pin low
_delay_us(1);
if (PINH & (1 << HX711_DT_PIN)) {
count++;
}
}
PORTA |= (1 << HX711_SCK_PIN); // SCK pin high
_delay_us(1);
PORTA &= ~(1 << HX711_SCK_PIN); // SCK pin low
count ^= 0x800000; // Adjust for 24 bit reading
return count;
}
long hx711_get_value(void) {
long sum = 0;
for (int i = 0; i < 10; i++) {
sum += hx711_read();
}
return sum / 10;
}
float hx711_get_weight(long offset, float scale) {
long reading = hx711_get_value();
return (int)((reading - offset) / scale);
}
void led_init(void)
{
DDRH |= (1 << LED_PIN);
}
void led_on(void)
{
PORTH |= (1 << LED_PIN);
}
void led_off(void)
{
PORTH &= ~(1 << LED_PIN);
}
void buzzer_init(void) {
BUZZER_DDR |= (1 << BUZZER_PIN); // Set buzzer pin as output
}
void buzzer_on(void) {
BUZZER_PORT |= (1 << BUZZER_PIN); // Turn buzzer on
}
void buzzer_off(void) {
BUZZER_PORT &= ~(1 << BUZZER_PIN); // Turn buzzer off
}
void i2c_init(void) {
TWSR = 0x00;
TWBR = 0x47; // Set bit rate
TWCR = (1 << TWEN); // Enable TWI
}
void i2c_start(uint8_t address) {
TWCR = (1 << TWSTA) | (1 << TWEN) | (1 << TWINT); // Send START condition
while (!(TWCR & (1 << TWINT))); // Wait for TWINT flag set
TWDR = address; // Load slave address
TWCR = (1 << TWEN) | (1 << TWINT); // Start transmission
while (!(TWCR & (1 << TWINT))); // Wait for TWINT flag set
}
void i2c_write(uint8_t data) {
TWDR = data; // Load data to TWDR register
TWCR = (1 << TWEN) | (1 << TWINT); // Start transmission
while (!(TWCR & (1 << TWINT))); // Wait for TWINT flag set
}
void i2c_stop(void) {
TWCR = (1 << TWSTO) | (1 << TWEN) | (1 << TWINT); // Send STOP condition
while (TWCR & (1 << TWSTO)); // Wait until STOP condition is executed
}
// LCD I2C functions
void lcd_init(uint8_t lcd_addr) {
_delay_ms(50);
lcd_send_command(0x33); // Initialize LCD in 4-bit mode
lcd_send_command(0x32); // Set to 4-bit mode
lcd_send_command(0x06); // Cursor move direction
lcd_send_command(0x0C); // Turn cursor off
lcd_send_command(0x28); // 2 line display (this setting works for 4 lines too)
lcd_send_command(0x01); // Clear display
_delay_ms(5);
}
void lcd_create_char(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
lcd_send_command(0x40 | (location << 3));
for (int i = 0; i < 8; i++) {
lcd_send_data(charmap[i]);
}
}
void lcd_set_cursor(uint8_t row, uint8_t col) {
uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54};
lcd_send_command(0x80 | (col + row_offsets[row]));
}
void lcd_print(const char* str) {
while (*str) {
lcd_send_data(*str++);
}
}
static void lcd_send_command(uint8_t command) {
lcd_write(command, 0);
}
static void lcd_send_data(uint8_t data) {
lcd_write(data, Rs);
}
static void lcd_write(uint8_t data, uint8_t mode) {
uint8_t high_nibble = data & 0xF0;
uint8_t low_nibble = (data << 4) & 0xF0;
i2c_start(LCD_I2C_ADDR << 1);
i2c_write(high_nibble | mode | LCD_BACKLIGHT | En);
i2c_write(high_nibble | mode | LCD_BACKLIGHT);
i2c_write(low_nibble | mode | LCD_BACKLIGHT | En);
i2c_write(low_nibble | mode | LCD_BACKLIGHT);
i2c_stop();
}
//DHT22
void dht22_request() {
DDRD |= (1 << DHT22_PIN); // output mode
PORTD &= ~(1 << DHT22_PIN); // send low signal
_delay_ms(20); // wait for 20ms
PORTD |= (1 << DHT22_PIN); // sen high signal
_delay_us(40);
DDRD &= ~(1 << DHT22_PIN); // input mode
}
uint8_t dht22_response() {
uint8_t response = 0;
DDRD &= ~(1 << DHT22_PIN); // input mode
_delay_us(40);
if (!(PIND & (1 << DHT22_PIN))) {
_delay_us(80);
if ((PIND & (1 << DHT22_PIN))) {
response = 1;
}
_delay_us(80);
}
return response;
}
uint8_t dht22_receive_data() {
uint8_t data = 0;
for (int i = 0; i < 8; i++) {
while (!(PIND & (1 << DHT22_PIN))); // wait high level
_delay_us(30);
if (PIND & (1 << DHT22_PIN)) {
data = (data << 1) | 1; // read 1
} else {
data = (data << 1); // read 0
}
while (PIND & (1 << DHT22_PIN)); // wait high level
}
return data;
}
int main()
{
// Initialize peripherals
i2c_init();
lcd_init(LCD_I2C_ADDR);
led_init();
buzzer_init();
hx711_init();
// Create a custom character for the degree symbol
uint8_t degree_symbol[8] = {
0b00111,
0b00101,
0b00111,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000
};
lcd_create_char(0, degree_symbol);
char lcd_buffer[32];
lcd_set_cursor(0, 0);
// Tare and calibrate the load cell (adjust these values as needed)
long offset = hx711_get_value(); // Tare the load cell
float scale = 2280.f; // Calibration factor
while (1)
{
char buffer[80];
uint8_t humidity_high, humidity_low, temp_high, temp_low, checksum;
dht22_request();
if (dht22_response())
{
humidity_high = dht22_receive_data();
humidity_low = dht22_receive_data();
temp_high = dht22_receive_data();
temp_low = dht22_receive_data();
checksum = dht22_receive_data();
int humidity = (humidity_high << 8) | humidity_low;
int temperature = (temp_high << 8) | temp_low;
// Checksum control
if ((temp_high + temp_low) != checksum )
{
lcd_set_cursor(0, 0);
snprintf(lcd_buffer, sizeof(lcd_buffer), "Temperature: %d ", temperature / 10);
lcd_print(lcd_buffer);
lcd_send_data(0); // print degree symbol
lcd_print("C");
if (temperature / 10 > 25) {
led_on(); // Turn on LED
} else {
led_off(); // Turn off LED
}
}
else
{
// Checksum error
lcd_set_cursor(0, 0);
lcd_print(" checksum error");
}
}
else
{
// DHT22 not responding
lcd_set_cursor(0, 0);
lcd_print("dht22 error");
}
// Read weight from load cell
int weight = hx711_get_weight(offset, scale);
lcd_set_cursor(1, 0);
snprintf(lcd_buffer, sizeof(lcd_buffer), "Weight: %d g", weight);
lcd_print(lcd_buffer);
_delay_ms(500);
}
}