Programmatic increase in temperature measurement resolution in the SU controller (oversampling)

The SU 1.2 controller and the SU 1.5 controller enable temperature measurement using PT100 sensors in the range of -50…+160 degrees Celsius with a resolution of 0.2 degrees per bit. This is due to the fact that the microcontroller’s converter is 10 bits (1023 bits), while the offset is 89 bits:

Calculation of standard resolution

To obtain a resolution of 0.01 degrees per bit, the converter resolution must be increased to 15 bits in software. This is the so-called oversampling method, the so-called oversampling. To use the oversampling method, there should be noise in the measured signal. This noise comes from: CPU, voltage fluctuations of the power source, operation of input/output ports, thermal noise. By increasing the resolution of the converter by oversampling, we reduce the sampling frequency of the signal. To increase the resolution of the converter from 10 to 15 bits (n=5), the signal must be sampled 4^5=1024 times. The obtained results should be summed and then averaged by shifting the bits to the right by 5 bits, which corresponds to dividing it by 2^5 (so-called decimation).

Expanded resolution calculation

In the presented example, the measurement of temperature input number 1 is performed with a resolution of 0.007 degrees per bit (so-called oversampling), while the measurement of temperature input number 2 is performed with a standard resolution of 0.2 degrees per bit.

The presented example was written in C in Atmel Studio 6.2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <avr/io.h>
#include "avr/interrupt.h"
#include "avr/pgmspace.h"
#include "global.h"
#include "lcd.h"
#include "i2c.h"
#include "procedury.h"
#include <util/delay.h>
 
 
volatile unsigned char BCD[5];
     
int main(void)
{
 unsigned char godziny, minuty,sekundy;
 unsigned long przetwornik1, przetwornik2, temp1, temp2;
 unsigned int c,b;
 sei();
 
 i2c_init();    //Inicjalizacja magistrali I2C
  
 DDRB=0xff;     //magistrala danych jako wyjscie
 sbi(DDRD,4);   //aktywacja pinu wyswietlacza
 sbi(DDRC,6);   //aktywacja pinu ING1 odczytu wejsc cyfrowych
 sbi(DDRC,7);   //aktywacja pinu do sterowania wyjsc cyfrowych
 sbi(DDRA,4);   //aktywacja pinu /OE wyjsc cyfrowych
 sbi(PORTC,6);  //stan wysoki na ING1
 sbi(PORTC,7);  //stan wysoki na OUTG1
 cbi(PORTA,4);  //stan niski na /OE (sterowanie wyjsc cyfrowych mozliwe)
 sbi(PORTD,4);  //stan wysoki na DISPLAY
 
 cbi(DDRC,2);   //pin PC2 wejscie (klawisz UP)
 cbi(DDRC,3);   //pin PC2 wejscie (klawisz LEFT)
 cbi(DDRC,4);   //pin PC2 wejscie (klawisz DOWN)
 cbi(DDRC,5);   //pin PC2 wejscie (klawisz RIGHT)
 cbi(DDRA,6);   //pin PC2 wejscie (klawisz ESC)
 cbi(DDRA,7);   //pin PC2 wejscie (klawisz OK)
 
 cbi(PORTA,0);
 cbi(PORTA,1);
 cbi(PORTA,2);
 cbi(PORTA,3);
  
 //Odpowiednie skonfigurowanie przetwornika w mikrokontrolerze
 ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
 c=0;
 
 LCD_init();    //inicjalizacja wyświetlacza LCD
 LCD_clear();   //wyczyszczenie wyświetlacza
 
 //zapisanie w pamięci wyświetlacza znaczka stopnie Celsjusza
 LCD_send_0(0b01000000);
 LCD_putchar(0b0011100);
 LCD_putchar(0b0010100);
 LCD_putchar(0b0011100);
 LCD_putchar(0b0000000);
 LCD_putchar(0b0000111);
 LCD_putchar(0b0001000);
 LCD_putchar(0b0001000);
 LCD_putchar(0b0000111);
 LCD_send_0(0x080);
 wait(20000);
 
 while(1)
 {
    c++;   
 
/*
Pętle w której dokonywany jest odczyt z przetwornika
*/     
    if (c==100)
    {
        przetwornik1=0;
        przetwornik2=0;
        c=0;
         
        //W tej pętli dokonywany jest oversampling wejścia temperaturowego numer 1
        for (b=0;b<1024; b++)
        {
            ADMUX=(1<<REFS1)|(1<<REFS0)|(1<<MUX1);
            ADCSRA=(1<<ADSC)|(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
            loop_until_bit_is_set(ADCSRA, ADIF);
            ADCSRA |= _BV(ADIF); /* wyzeruj bit */
            przetwornik1=przetwornik1+ADC;
        }
     
        //Poniżej standardowy odczyt temperatury z wejścia numer 2
        przetwornik2=0;
        ADMUX=(1<<REFS1)|(1<<REFS0)|(1<<MUX1)|(1<<MUX0);
        ADCSRA=(1<<ADSC)|(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
        loop_until_bit_is_set(ADCSRA, ADIF);
        ADCSRA |= _BV(ADIF); /* wyzeruj bit */
        przetwornik2=przetwornik2+ADC;
     
    }
          
    //Odpowiednie przeliczenie odczytu według wzoru numer 2
    temp1=((przetwornik1-91136)>>5)*7/10;
    if (temp1<5000) temp1=5000-temp1;
    if (temp1>=5000) temp1=temp1-5000;
 
    //Odpowiednie przeliczenie odczytu według wzoru numer 1
    temp2=(przetwornik2-89)*225/100;
    if (temp2<500) temp2=500-temp2;
    if (temp2>=500) temp2=temp2-500;
     
    bcd8(temp1); //zamiana hex na BCD
     
    LCD_xy(1,2);
     
    //wyświetlenie temperatury numer 1 na wyświetlaczu
    LCD_putchar(0x030+(BCD[1]>>0x004));
    LCD_putchar(0x030+(BCD[1]&0x00f));
    LCD_putchar(',');
    LCD_putchar(0x030+(BCD[0]>>0x004));
    LCD_putchar(0x030+(BCD[0]&0x00f));
    LCD_putchar(0);
     
    bcd8(temp2);//zamiana hex na BCD
     
    //wyświetlenie temperatury numer 2 na wyświetlaczu
    LCD_putchar(' ');
    LCD_putchar(0x030+(BCD[1]&0x00f));
    LCD_putchar(0x030+(BCD[0]>>0x004));
    LCD_putchar(',');
    LCD_putchar(0x030+(BCD[0]&0x00f));
    LCD_putchar(0);
                 
    //Odczyt zegara RTC
    sekundy=read_ram_rtc(0x002);
    minuty=read_ram_rtc(0x003);
    godziny=read_ram_rtc(0x004);
     
    //Wyświetlenie aktualnego czasu na wyświetlaczu LCD
    LCD_xy(9,1);
    LCD_LCZB(godziny);
    LCD_putchar(':');
    LCD_LCZB(minuty);
    LCD_putchar(':');
    LCD_LCZB(sekundy);
 }
}

A video presenting how oversampling works in practice

Scroll to Top