commit 4bc167924200c1f1805aa2840320073d4f2eb270 Author: Imbus Date: Sun Dec 3 13:37:53 2023 +0100 Initial 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..."); +}