From 4bc167924200c1f1805aa2840320073d4f2eb270 Mon Sep 17 00:00:00 2001 From: Imbus Date: Sun, 3 Dec 2023 13:37:53 +0100 Subject: [PATCH] Initial --- 74C922.c | 51 +++++++++++++++++++ 74C922.h | 8 +++ DHT22.c | 78 +++++++++++++++++++++++++++++ DHT22.h | 7 +++ GDM1602K.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ GDM1602K.h | 9 ++++ LM335.c | 47 ++++++++++++++++++ LM335.h | 13 +++++ config.h | 6 +++ main.c | 94 +++++++++++++++++++++++++++++++++++ 10 files changed, 454 insertions(+) create mode 100644 74C922.c create mode 100644 74C922.h create mode 100644 DHT22.c create mode 100644 DHT22.h create mode 100644 GDM1602K.c create mode 100644 GDM1602K.h create mode 100644 LM335.c create mode 100644 LM335.h create mode 100644 config.h create mode 100644 main.c diff --git a/74C922.c b/74C922.c new file mode 100644 index 0000000..c9b0528 --- /dev/null +++ b/74C922.c @@ -0,0 +1,51 @@ +#include "config.h" +#include +#include +#include + +// Pin Definitions +#define ENCODER_A_PIN PD6 +#define ENCODER_B_PIN PD5 +#define ENCODER_C_PIN PD4 +#define ENCODER_D_PIN PD3 +#define ENCODER_OE_PIN PD2 +#define ENCODER_DA_PIN PD1 + +void prepare_interrupt() { + EICRA |= (1 << ISC00); // Any logical change triggers interrupt + EIMSK |= (1 << INT0); // INT0 external interrupt + PCICR |= (1 << PCIE0); +} + +// Encoder Module +void encoder_init() { + // Set A, B, C, D, and DA pins as inputs + DDRD &= ~((1 << ENCODER_A_PIN) | (1 << ENCODER_B_PIN) | (1 << ENCODER_C_PIN) | (1 << ENCODER_D_PIN) | (1 << ENCODER_DA_PIN)); + + // Set OE as output + DDRD |= (1 << ENCODER_OE_PIN); + + // Enable internal pull-up resistors for A, B, C, D, and OE pins + PORTD |= (1 << ENCODER_A_PIN) | (1 << ENCODER_B_PIN) | (1 << ENCODER_C_PIN) | (1 << ENCODER_D_PIN) | (1 << ENCODER_DA_PIN); +} + +uint8_t encoder_read() { + uint8_t encoder_data = 0; + + // Set OE (Output Enable) pin low to enable the encoder + PORTD &= ~(1 << ENCODER_OE_PIN); + _delay_us(1); + + // Read the state of the encoder + encoder_data = PIND >> (ENCODER_A_PIN - 3); + encoder_data &= 0x0F; + + // Set OE pin high to disable the encoder + PORTD |= (1 << ENCODER_OE_PIN); + + return encoder_data; +} + +bool encoder_available() { + return (PIND & (1 << ENCODER_DA_PIN)); +} \ No newline at end of file diff --git a/74C922.h b/74C922.h new file mode 100644 index 0000000..3721eb0 --- /dev/null +++ b/74C922.h @@ -0,0 +1,8 @@ +#ifndef H74C922_H +#define H74C922_H + +void encoder_init(); +uint8_t encoder_read(); +bool encoder_available(); + +#endif // 74C922_H \ No newline at end of file diff --git a/DHT22.c b/DHT22.c new file mode 100644 index 0000000..d2bd40c --- /dev/null +++ b/DHT22.c @@ -0,0 +1,78 @@ +#include "config.h" + +#include +#include +#include + +#include "GDM1602K.h" + +#define DATAPIN PC0 +#define PORT PORTC +#define PIN PINC +#define DDR DDRC + +bool is_high() { + return (PIN & (1 << DATAPIN)); +} + +// Function to read data from the DHT22 sensor +int DHT22_Read(int *temperature, int *humidity) +{ + // Set the data pin as output + DDR |= (1 << DATAPIN); + PORT |= (1 << DATAPIN); // Set the pin high, if not already pulled up + + _delay_ms(100); + + // Send start signal + PORT &= ~(1 << DATAPIN); // Set the pin low + _delay_us(500); // Hold it for a while + PORT |= (1 << DATAPIN); // Set the pin high + DDR &= ~(1 << DATAPIN); // Data direction in + + _delay_us(20); // Wait for 40 microseconds + + // Sensor should have pulled low here + if(PIN & (1 << DATAPIN)) return -2; + + _delay_us(80); // Wait for 80 microseconds + + // Sensor should have pulled high here + if(!(PIN & (1 << DATAPIN))) return -1; + + // Read data from the sensor + uint8_t data[5] = {0, 0, 0, 0, 0}; + uint8_t bitMask = 0x80; // All zeroes with MSB high + uint8_t byteIndex = 0; + + for (byteIndex = 0; byteIndex < 5; byteIndex++) + { + for (bitMask = 0x80; bitMask != 0; bitMask >>= 1) + { + // Wait for the data bit to go low + while (!(PIN & (1 << PC0))) + ; + + // Wait for the data bit to go high + _delay_us(20); + if (PIN & (1 << PC0)) + data[byteIndex] |= bitMask; + + // Wait for the data bit to go low (end of bit) + while (PIN & (1 << PC0)) + ; + } + } + + // Verify checksum + uint8_t checksum = data[0] + data[1] + data[2] + data[3]; + if (checksum != data[4]) + return -1; + + // Extract temperature and humidity + *humidity = ((data[0] << 8) | data[1]); + *temperature = ((data[2] << 8) | data[3]); + + return 0; +} + diff --git a/DHT22.h b/DHT22.h new file mode 100644 index 0000000..40167cb --- /dev/null +++ b/DHT22.h @@ -0,0 +1,7 @@ +#ifndef DHT22_H +#define DHT22_H + +int DHT22_Read(int *temperature, int *humidity); +void DHT22_Init(); + +#endif /* DHT22_H */ \ No newline at end of file diff --git a/GDM1602K.c b/GDM1602K.c new file mode 100644 index 0000000..a07f1db --- /dev/null +++ b/GDM1602K.c @@ -0,0 +1,141 @@ +#include "config.h" + +#include +#include +#include + +#define LCD_DATA_PORT PORTB +#define LCD_DATA_DDR DDRB +#define LCD_RS_PIN PB1 +#define LCD_EN_PIN PB2 +#define LCD_DB4 PB3 +#define LCD_DB5 PB4 +#define LCD_DB6 PB5 +#define LCD_DB7 PB6 + +// Delay constants from the datasheet. These are mostly in nanoseconds +#define LAG 10 +#define TW 300 +#define TSU1 100 + +void lcd_4bit_init() { + LCD_DATA_DDR = 0xFF; + LCD_DATA_PORT = (1 << LCD_DB5); + LCD_DATA_PORT &= ~(1 << LCD_RS_PIN); + _delay_us(1); + LCD_DATA_PORT |= (1 << LCD_EN_PIN); + _delay_us(1); + LCD_DATA_PORT &= ~(1 << LCD_EN_PIN); + _delay_us(1); + LCD_DATA_PORT &= ~(1 << LCD_DB5); + _delay_us(1); +} + +void lcd_send(bool rs, uint8_t data) { + LCD_DATA_DDR = 0xFF; + LCD_DATA_PORT = 0x00; + + LCD_DATA_PORT |= (data >> 4) << 3; + _delay_us(1); + + // If rs (actual text data), set RS pin high + if(rs == true) LCD_DATA_PORT |= (1 << LCD_RS_PIN); + + // Pulse enable + _delay_ms(2); + LCD_DATA_PORT |= (1 << LCD_EN_PIN); + + _delay_us(1); + LCD_DATA_PORT &= ~(1 << LCD_EN_PIN); + + //_delay_us(1); + + // Clear data pins + LCD_DATA_PORT &= ~(0x0F << 3); + + // Mask the lower bits and shift accordingly + LCD_DATA_PORT |= (data & 0x0F) << 3; + _delay_us(1); + + // Pulse enable + LCD_DATA_PORT |= (1 << LCD_EN_PIN); + _delay_us(1); + LCD_DATA_PORT &= ~(1 << LCD_EN_PIN); + _delay_us(1); + LCD_DATA_PORT &= ~(0x0F << 3); + + LCD_DATA_PORT &= ~(1 << LCD_RS_PIN); // RS Low +} + +void lcd_init() { + _delay_ms(100); + lcd_4bit_init(); + + //lcd_send(1, 0b01111000); + lcd_send(0, 0x01); // Clear screen + lcd_send(0, 0x02); // Return home + lcd_send(0, 0b00001100); // Display on, no cursor + lcd_send(0, 0b00101000); +} + +void lcd_clear() { + lcd_send(0, 0x01); +} + +void test_leds() { + DDRB |= 0xFF; + PORTB = (1 << LCD_DB4); + _delay_us(1); + PORTB = (1 << LCD_DB5); + _delay_us(1); + PORTB = (1 << LCD_DB6); + _delay_us(1); + PORTB = (1 << LCD_DB7); + _delay_us(1); + + PORTB = (1 << LCD_EN_PIN); + _delay_us(1); + PORTB = (1 << LCD_RS_PIN); + _delay_us(1); + PORTB = 0x00; +} + +void lcd_set_cursor(uint8_t row, uint8_t col) { + uint8_t position = 0x80; + + if (row == 1) position += 0x40; + + position += col; + lcd_send(0, position); +} + +// Takes a string and splits it over two lines if needed. Max length is 32 characters. +void lcd_write_string(const char* string) { + uint8_t i = 0; + while(string[i]) { + if(i == 16) { + lcd_set_cursor(1, 0); + while(string[i] == ' ') i++; // Skip leading spaces on the new line + } + lcd_send(1, string[i]); + i++; + } +} + +// Takes two separate strings and prints them on their corresponding row +void lcd_write_strings(const char* top, const char* bottom) { + uint8_t i = 0; + + while (top[i]) { + lcd_send(1, top[i]); + i++; + } + + i = 0; + lcd_set_cursor(1, 0); + while(bottom[i]) { + lcd_send(1, bottom[i]); + i++; + } + +} diff --git a/GDM1602K.h b/GDM1602K.h new file mode 100644 index 0000000..2ffb494 --- /dev/null +++ b/GDM1602K.h @@ -0,0 +1,9 @@ +#ifndef GDM1602K_H_ +#define GDM1602K_H_ + +void lcd_write_strings(const char* top, const char* bottom); +void lcd_write_string(const char* string); +void lcd_init(); +void lcd_clear(); + +#endif /* GDM1602K_H_ */ \ No newline at end of file diff --git a/LM335.c b/LM335.c new file mode 100644 index 0000000..fe7877d --- /dev/null +++ b/LM335.c @@ -0,0 +1,47 @@ +#include "config.h" +#include +#include +#include "LM335.h" + +void ADC_Init() +{ + // Set AVCC as the voltage reference with external capacitor at AREF pin + ADMUX = (1 << REFS0); + + // Set ADC clock prescaler to 64 (125kHz ADC clock) + ADCSRA = (1 << ADPS2) | (1 << ADPS1); + + // Enable ADC, enable interrupts + ADCSRA |= (1 << ADEN); // | (1 << ADIE); +} + +uint16_t ADC_Read(uint8_t channel) +{ + // Select ADC channel + ADMUX = (ADMUX & 0xF8) | (channel & 0x07); + + // Start ADC conversion + ADCSRA |= (1 << ADSC); + + // Wait for ADC conversion to complete + while (ADCSRA & (1 << ADSC)) + ; + + // Read ADC result + return ADC; +} + +float LM335_ReadTemperature() +{ + // Read ADC value from LM335 pin (PA0) + uint16_t adcValue = ADC_Read(0x00); + + float vref = 4.64; + int vfactor = 100; + float voltage = (adcValue * vref) / 1024; + + // Calculate temperature in Celsius using LM335 formula + float temperature = (voltage - 2.92) * vfactor; + + return temperature; +} \ No newline at end of file diff --git a/LM335.h b/LM335.h new file mode 100644 index 0000000..f3b6720 --- /dev/null +++ b/LM335.h @@ -0,0 +1,13 @@ +#include +#include + +#ifndef LM335_H_ +#define LM335_H_ + +#define LM335_PIN PA0 + +void ADC_Init(); +uint16_t ADC_Read(uint8_t channel); +float LM335_ReadTemperature(); + +#endif \ No newline at end of file diff --git a/config.h b/config.h new file mode 100644 index 0000000..d439994 --- /dev/null +++ b/config.h @@ -0,0 +1,6 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define F_CPU 1600000UL + +#endif // CONFIG_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..8871c41 --- /dev/null +++ b/main.c @@ -0,0 +1,94 @@ +#include "config.h" + +#include +#include +#include +#include + +#include "74C922.h" +#include "DHT22.h" +#include "GDM1602K.h" +#include "LM335.h" + +enum DisplayMode {TEMP, AVG}; + +bool b = false; + +int main() { + _delay_ms(1000); // Boot up time, let components catch up + lcd_init(); + encoder_init(); + + lcd_clear(); + lcd_write_string("Hello, world!"); + + int temp, hum; + char celc_str[30]; + char temp_with_unit[20] = ""; + char hum_str[30]; + float celcius = 0.0; + float humidity = 0.0; + char temp_unit = 'C'; + + uint8_t button_data; + char btn_string[30]; + bool btn_just_pressed = false; + + long loops = 0; + + while(1) { + // If encoder has data available + if(encoder_available() == true) { + loops = 0xFFFF; + if(!btn_just_pressed) { + btn_just_pressed = true; + button_data = encoder_read(); + sprintf(btn_string, "Knapp %d", button_data); + lcd_clear(); + if(button_data == 11) { + if(temp_unit == 'C') temp_unit = 'F'; + else if(temp_unit == 'F') temp_unit = 'K'; + else if(temp_unit == 'K') temp_unit = 'C'; + loops = 0; + } + if(button_data == 3) { + sprintf(celc_str, "10h Tmp: %s", temp_with_unit); + sprintf(hum_str, "10h Hum: %.1f%%", humidity-1); + lcd_write_strings(celc_str, hum_str); + } + } + } else { + btn_just_pressed = false; + } + + if(loops == 0) { + loops = 0x2FFFF; + + int result = DHT22_Read(&temp, &hum); + + lcd_clear(); + + if(result == 0) { + celcius = ((float)temp)/10.0; + humidity = ((float) hum)/10.0; + switch(temp_unit) { + case 'C': + sprintf(temp_with_unit, "%.1f %c", celcius, temp_unit); + break; + case 'F': + sprintf(temp_with_unit, "%.1f %c", celcius*9/5+32, temp_unit); + break; + case 'K': + sprintf(temp_with_unit, "%.1f %c", celcius + 273.15, temp_unit); + break; + } + sprintf(celc_str, "Temp: %s", temp_with_unit); + sprintf(hum_str, "Humidity: %.1f%%", humidity); + + lcd_write_strings(celc_str, hum_str); + } + } + loops--; + } + lcd_write_string("Exited..."); +}