catmega16proteuscodevisionavr

Temperature sensor (LM35) with Atmega16 simulation


I am simulating the LM35 sensor with Proteus and Codevision application. The project is to show the temperature on the LCD and 7seg.

Now everything is working but it does not show the Negative numbers (It show 0.0C).

But for positive numbers it show approximately right!

I have tried a lot of codes but none of them worked. I have also tried adding 2*10k resistor for the LM35 to make it 2.5v and making the bias circuit.

#include <mega16.h>
#include <delay.h>
#include <alcd.h>
#include <stdio.h>

#define ADC_VREF_TYPE ((0<<REFS1)|(1<<REFS0)|(0<<ADLAR))

const unsigned char seg_patterns[11] = {
    0xC0,  // 0
    0xF9,  // 1
    0xA4,  // 2
    0xB0,  // 3
    0x99,  // 4
    0x92,  // 5
    0x82,  // 6
    0xF8,  // 7
    0x80,  // 8
    0x90,  // 9
    0xBF   // Minus sign '-'
};

volatile unsigned char display_digit = 0;
volatile unsigned char digits[4] = {0xFF, 0xFF, 0xFF, 0xFF};
volatile unsigned char decimal_points[4] = {0, 0, 1, 0};

interrupt [TIM0_OVF] void timer0_ovf_isr(void) {
    TCNT0 = 240;
    PORTB &= ~0xF0;

    if (digits[display_digit] != 0xFF) {
        PORTC = seg_patterns[digits[display_digit]];
        if (decimal_points[display_digit]) PORTC &= ~0x80;
    } else {
        PORTC = 0xFF;
    }

    PORTB |= (1 << (display_digit + 4));
    display_digit = (display_digit + 1) % 4;
}

unsigned int read_adc(unsigned char ch) {
    ADMUX = ch | ADC_VREF_TYPE;
    delay_us(10);
    ADCSRA |= (1 << ADSC);
    while (ADCSRA & (1 << ADSC));
    return ADCW;
}

void update_display(float temp) {
    int temp_int;
    unsigned char is_negative = 0;
    
    // Check if temperature is negative
    if (temp < 0) {
        is_negative = 1;
        temp_int = (int)((-temp) * 10);  // Make positive for digit extraction
    } else {
        temp_int = (int)(temp * 10);
    }
    
    // For negative numbers: -26.0 should show as "-26.0"
    // digits[0] = minus, digits[1] = 2, digits[2] = 6, digits[3] = 0
    
    if (is_negative) {
        digits[0] = 10;  // Minus sign
        if (temp_int >= 100) {  // Two digits before decimal (e.g., -26.0)
            digits[1] = (temp_int / 100) % 10;  // Tens digit
            digits[2] = (temp_int / 10) % 10;   // Units digit
            digits[3] = temp_int % 10;          // Decimal digit
        } else {  // One digit before decimal (e.g., -5.2)
            digits[1] = 0xFF;  // Blank
            digits[2] = (temp_int / 10) % 10;   // Units digit
            digits[3] = temp_int % 10;          // Decimal digit
        }
    } else {
        // Positive numbers
        if (temp_int >= 1000) {  // Three digits (e.g., 125.4)
            digits[0] = (temp_int / 1000) % 10;
            digits[1] = (temp_int / 100) % 10;
            digits[2] = (temp_int / 10) % 10;
            digits[3] = temp_int % 10;
        } else if (temp_int >= 100) {  // Two digits (e.g., 25.5)
            digits[0] = 0xFF;  // Blank
            digits[1] = (temp_int / 100) % 10;
            digits[2] = (temp_int / 10) % 10;
            digits[3] = temp_int % 10;
        } else {  // One digit (e.g., 5.2)
            digits[0] = 0xFF;  // Blank
            digits[1] = 0xFF;  // Blank
            digits[2] = (temp_int / 10) % 10;
            digits[3] = temp_int % 10;
        }
    }
    
    // Set decimal point position (after digit 2)
    decimal_points[0] = 0;
    decimal_points[1] = 0;
    decimal_points[2] = 1;  // Decimal point here
    decimal_points[3] = 0;
}

void main(void) {
    DDRB = 0xF1;
    DDRC = 0xFF;
    PORTC = 0xFF;

    TCCR0 = (1 << CS01);
    TIMSK |= (1 << TOIE0);
    TCNT0 = 240;

    ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

    lcd_init(16);
    #asm("sei")
    lcd_clear();

    // Test counter for simulating different temperatures
    int test_counter = 0;

    while (1) {
        unsigned int adc_value = read_adc(0);
        float voltage = (adc_value * 5.0) / 1024.0;
        float temp = voltage / 0.01;  // LM35 output 10mV per °C
        
        // TEMPORARY: Simulate negative temperatures for testing
        // Remove this section once you confirm negative display works
        if (test_counter < 10) {
            temp = -26.5;  // Test negative temperature
        } else if (test_counter < 20) {
            temp = -5.2;   // Test single digit negative
        } else if (test_counter < 30) {
            temp = 25.5;   // Test positive temperature
        } else {
            test_counter = 0;  // Reset counter
        }
        test_counter++;
        // END OF TEST SECTION

        char lcd_text[16];
        if (temp < 0) {
            sprintf(lcd_text, "Temp: -%.1fC", -temp);
        } else {
            sprintf(lcd_text, "Temp: %.1fC", temp);
        }
        lcd_clear();
        lcd_puts(lcd_text);

        update_display(temp);
        delay_ms(500);
    }
}

enter image description here


Solution

  • enter image description here

    This is the schematic for negative temperature. You should use two ADC and compare the inputs.