#include "main.h" const char* lm35_string = "LM35 Temp: "; const struct { x = sizeof(lm35_string); y = 0; } lm35_value_pos; #ifdef CALIBRATION const char* diode_string = "Diode Value: "; #else const char* diode_string = "Diode Temp: "; #endif const struct { x = sizeof(diode_string); y = 1; } diode_value_pos; /** @brief Initialises general pins for use. * * @note Does not initialise LCD pins. That is handled by lcdlibrary */ void pin_init() { /* Pin Mappings: * PC0 -> ADC0 input for diode measurement * PC1 -> ADC1 input for LM35 */ // Pin Config for Diode ADC DDRC &= ~(1 << DDRC0); DIDR0 |= (1 << ADC0D); // Disable digital input // Pin Config for LM35 ADC DDRC &= ~(1 << DDRC1); DIDR0 |= (1 << ADC1D); // Disable digital input } /** @brief Initializes ADC with required settings */ void adc_init() { /* ADC Settings * Use Aref as Vref * Initially set input as GND * Data right-adjusted * No Interrupts */ // Set MUX[3:0] to 0b1111 (GND reference) ADMUX |= (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (1 << MUX0); // Make sure data is right adjusted ADMUX &= ~(1 << ADLAR); // Set the clock prescaler to 128 (slower ADC means more accurate measurements) ADCSRA |= (1 << ADPS2) | (1 << ADPS1) (1 << ADPS0); // Enable ADC ADCSRA |= (1 << ADEN); } /** @brief Blocking function to read an ADC conversion from a selected ADC input. * * @note Blocks until conversion finishes, so speed of this function is dependant * on ADC prescaler. */ uint16_t adc_run_conversion(uint8_t adc_selection) { // Select ADC ADMUX &= 0xF0 | adc_selection; // Start conversion ADCSRA |= (1 << ADSC); // Wait until conversion is complete while (ADCSRA & (1 << ADIF)); // Read out conversion value // may not be correct return ADC; } /** @brief Converts an ADC value from a measurement on an LM35 into a temperature. */ float lm35_convert(uint16_t adc_reading) { return (float) (adc_reading * ADC_VREF / ADC_RESOLUTION) / LM35_SENSITIVITY; } /** @brief Converts and ADC value from a measurement on a diode into a temperature. * TODO */ float diode_convert(uint16_t adc_reading) { // Do some funky math here return 0; } int main() { // Initialise peripherals pin_init(); adc_init(); // Initialise display // NOTE: LCD uses PB0-PB6 lcd_init(LCD_DISP_ON); // Write "base" strings to LCD lcd_puts(lm35_string); lcd_gotoxy(0, diode_value_pos.y); // Switch to bottom lcd_puts(diode_string); // Note that special compiler/linker flags have to be added to enable // printf-ing floats // See: https://startingelectronics.org/articles/atmel-AVR-8-bit/print-float-atmel-studio-7/ while (1) { // Read LM35 value, and write to LCD float lm35_temp = lm35_convert(adc_run_conversion(1)); // Convert measured value to string char[6] lm35_temp_str; sprintf(lm35_temp_str, "%3.1f", lm35_temp); // Display temp on LCD lcd_gotoxy(lm35_value_pos.x, lm35_value_pos.y); lcd_puts((const char*) lm35_temp_str); // Read diode value, and write to LCD #ifdef CALIBRATION uint16_t diode_value = adc_run_conversion(0); char[6] diode_str; sprintf(diode_str, "%d", diode_value); #else float diode_temp = diode_convert(adc_run_conversion(0)); char[6] diode_str; sprintf(diode_str, "%3.1f", diode_temp); #endif // Display diode info on LCD lcd_gotoxy(diode_value_pos.x, diode_value_pos.y); lcd_puts((const char*) diode_str); } }