Do I need to normalize the response of internal temp sensor by 1.1V Vref?

Aim: Measure and display chip (ATmega328)/ambient temperature on 4-digit cc (common cathode)-type 7-segment multiplexed display unit at 3-sec interval.

Figure-1: Interconnection of various hardware modules of ATmega328 involved in the process (conceptual view)

1. The data sheet says to use internal 1.1V as Vref for the ADC while measuring the output of the internal temperature sensor.
2. The data sheet has given the following two-point known responses for the internal temp sensor.
A(VDT1, TT1) = A(0.314V, 250C)
B(VDT2, TT2) = B(0.380V, 850C)
C(VDT, T) = the unknown point to be determined

Here: VDT stands for DC Voltage (response of temperature sensor) when the temperature is T0C.

3. Through algebraic manipulation, I have found the response equation as:
T = 909.0909*VDT - 260.4545

4. Now, I need to transform VDT from decimal (analog) domain into Binary (Hex = compact form of Binary) domain. I have the following options:
(a) VDT = 5VHT/10231024 where: 5 is the Vref = 5V, VHT = ADC value when the input analog is VDT.
(b) VDT = 1.1
VHT/10231024 where: 1.1 is the Vref = 1.1V, VHT = ADC value when the input analog is VDT.

My question:
Which option out of out 4(a) and 4(b) should I use?
Say, I have chosen option 4(b), then should I normalize the responses of A(0.314V, 250C) and B(0.380V, 850C) with respect to 1.1V?

The divisor is 1024.

The divisor is 1024.

OK! To remain in compliance with Atmel data sheets.

It's helpful if you don't call a variable V when it doesn't represent a voltage.

You're doing this backwards. Instead of converting ADC counts to voltages, you should be converting the voltages to ADC counts based on your chosen reference (1.1V). In other words, use formula (b) but solve for VHT instead of VDT.

That lets you use the datasheet's recommended equation T = (ADC - T[sub]OS[/sub])/[i]k[/i]. You can calculate values for TOS and k based on the nominal 1.1V reference and the typical sensor outputs in Table 28-2, but the tolerance on those values is pretty bad. If you need accurate results, you will have to do a two point calibration in order to measure appropriate values for TOS and k, but it would be better to just get an external temperature sensor anyway.

Only very rarely is the voltage on the ADC input the actual value of interest. Most of the time it is a proxy for some other quantity, like temperature, pressure, or light intensity. The sensor circuitry converts the measurement to a voltage, and the ADC converts the voltage to a digital number. The voltage is an uninteresting intermediate stage that should be factored out of the equation as much as possible, so you can arrange a function to directly convert the ADC result to the quantity of interest. That's how the datasheet's formula was created.

It's helpful if you don't call a variable V when it doesn't represent a voltage.

The closest alternative symbolic names to me (in lieu of VHT) : ADCHT or ADCT. I think that I will use ADCT to mean ADC value (output binary value of ADC) when the ambient temperature is T. Do you have any suggestion?

//----------------------------------------------------------------------------------------------------------

I am going through the rest of your message, and I am finding it increasingly interesting and encouraging. I will do some experiments to clear up some of the conceptual things of your post/the data sheet.

//----------------------------------------------------------------------------------------------------------

Thank you for the reply and expecting more in due time.

Again this stupid pedantic nonsense.
MUCH more important are other errors.
If Vref is Vcc it may be anything between 5.5V and 4.5V (or even wider ofc). The 1.1 V voltage reference is 1.1 nominal. It should be somewhat stable but it is NOT callibrated. Once I measured it on my ATMega and it was 1.082V (if you trust my DMM). Worst of all is the temp sensor which is ABOUT 1mV/°C and +/-10°C (according the datasheet). It's funny you point at source of up to 1‰ error and not all those other much more important problems.
And I also forgot to mention inaccuracy of the ADC itself which is also more important than the "right" divisor.

You're doing this backwards. Instead of converting ADC counts to voltages, you should be converting the voltages to ADC counts based on your chosen reference (1.1V). In other words, use formula (b) but solve for VHT instead of VDT.

The implementation of the above statement has lead to arrive at the right conclusion that no normalization is required on the given response points (Table-28.2 of data sheet) of the sensor:

1. Based on response points of Table-28.2 (A(VDT1, T1) = A(0.314V, 250C); B(VDT2, T2) = B(0.380V, 850C); and C(VDT, T) = the unknown point to be determined), we have response equation as:

T = 909.0909*VDT - 260.4545 (Original Post)-----------------------------------------(1)

2. Replacing VDT by 1.1*ADCT/1024, we get:

T = 909.09091.1(1/1024)ADCT - 260.4545
==> T = 0.9765
ADCT - 260.4545 ------------------------------------------------(1A)
==> T104 = 9765ADCT - 2604545
==> T*104 = 2625h * ADCT - 27BE01h ---------------------(2)

The above equation (2) agrees with the following equation (3) what the data sheet (Page-316) has said:

T = {[ADCH<<8)|ADCL] - TOS}/k
==> T = (ADCT - TOS)/k
==> T = k-1*ADCT - k-1*TOS --------(3)

Here:
k-1 = fixed co-efficient (gain of the system) = 2625h from Egn.(2).
k-1T0S = fixed co-efficienttemperature sensor offset (offset of the system) = 27BE01h from Eqn.(2).

3. Validity check of Eqn.(2) for 850C by substitution:
Table-28.2 of data sheet has shown that at 850C temperature, the temperature sensor produces VDT = 380 mV. From this VDT, we get:
ADCT = 0.3801024/1.1 =~ 353.745 =~ 0162h.

After putting the value of ADCT in Eqn.(2), we get:
T104 = 2625h * 0162h - 27BE01h
==> T
104 = 34BF2Ah - 27BE01h
==> T104 = D0129h
==> T
104 = 8522650C

==> T = 85.22650C (proved)

4. The next job is to make the real measurement using Arduino UNO and see that the display shows sensible result indicating the internal temperature of the ATmega328 within +/- 100C.

The derivation looks correct.

I will note for completeness's sake that 1 check is not enough to check a linear equation like this. If you check just one point, there is a chance that you picked the one point shared between the real function and the improperly calculated one. 2 points are needed to uniquely specify a line, so you need to test two points here.

Calculated with the (25, 0.314) point gives a result of 24.6835, so I looks like that equation is correct.

The (-45, 0.242) point gives a result of -40.7, so it looks like the sensor deviates from linear at lower temperatures. And indeed, when I graph the 3 points they do not form a perfectly straight line. Unfortunately the datasheet does not have a graph with the temperature sensor output fully characterized, so the best you could do is a piecewise conversion function. Use one equation when the temperature is above 25, and another when it's below.

The datasheet only promises +/- 10oC accuracy for the temperature measurement. It's not meant to be good, it's just meant to be in the ballpark. If temperature is an important variable for your project (like for environment monitoring or process control), you should use an external sensor IC. Even an LM35 has more than 10x better accuracy.

First of all, thanks for availing the opportunity to pick up the fragrances of pleasure by doing the remaining 2-point checks which were, in fact, my job.

I have made a test run of the measurement process using the equation T = 0.9765*ADCT - 260.4545 and the Serial Monitor; the read out is about 79.170C. The room temperature is about 270C. When I put my fingers over the chip, the temperature seems to be changing!

The ATmega328's internal temperature measurement task is a part of a larger demonstrative project of ATmega328 based System Design using Arduino UNO of the 140 senior level students of electrical engineering. The aim of the project:

1. Observe the limitation of the Arduino in its inability to access ADC Channel-8 for internal temperature.

2. Theory of two-pointt calibration of a real sensor.

3. Compute 32-bit fixed point (amplified) temperature signal.

4. Converting 32-bit Binary temperature into equivalent BCD temperature by Horner Rule. Development of bcd adjustment algorithm for correcting incorrect BCD number into correct BCD number.

5. Converting BCD temperature into cc-coded temperature, and finally

6. Transferring the cc-coded temperature onto 4-digit multiplexed type 7-segment display unit at 3-sec interval.

As a demonstrator, I assist the students!

Once the projects are done by the students, I will post the photos in this thread, if allowed.

Any suggestion in respect of alternative ways/methods/algorithms for realizing the project would be highly appreciated!

GolamMostafa:
First of all, thanks for availing the opportunity to pick up the fragrances of pleasure by doing the remaining 2-point checks which were, in fact, my job.

I think you reached a little too far there for a fancy compliment. A "fragrance" typically refers to a nice smell, like flowers or perfume. "Fragrances of pleasure" sounds a bit erotic.

Most of the time I can understand the meaning of your broken English, but this one is just weird.

I have made a test run of the measurement process using the equation T = 0.9765*ADCT - 260.4545 and the Serial Monitor; the read out is about 79.170C. The room temperature is about 270C. When I put my fingers over the chip, the temperature seems to be changing!

Did you type that number incorrectly? 50 degrees of error is way too much.

How are you reading the temperature sensor? If you are doing analogRead(8), it won't work. Here are some lines pulled from the analogRead() function in the core:

if (pin >= 14) pin -= 14; // allow for channel or pin numbers
  ...
ADMUX = (analog_reference << 6) | (pin & 0x07);

The subtraction allows the symbols A0-A5 (defined as digital pins 14-19) to be used in analogRead(), so that A0 becomes channel 0, A1 becomes channel 1, etc. This part only gets in the way of trying to set the internal reference as the input, since that's channel 14. And it's easy to work around, since you can just add A0 to the intended channel number and it will be subtracted out. The temp sensor is channel 8, so it won't be affected by this. Just be aware that it's there.

It's the second line that's the real problem. It is the one thing in the Arduino core that I can say legitimately infuriates me. Masking the pin channel with 0x7 means that no matter what argument you pass into the function, only channels 0-7 can be selected. The temperature sensor (channel 8), the internal reference (channel 14, useful for trying to measure the Arduino's own supply voltage), and GND (channel 15) are impossible to select with analogRead().

Because the channel selection is masked, if you use the statement analogRead(8), you are actually selecting channel 0, which is pin A0. Since you've probably got that unconnected for this test, the reading will be pretty random.

If you are properly selecting the temperature input, then you might have a controller with a internal reference on the lower end of the tolerance range, and a temperature sensor reading higher than average.

Once the projects are done by the students, I will post the photos in this thread, if allowed.

Photos are definitely allowed.

Any suggestion in respect of alternative ways/methods/algorithms for realizing the project would be highly appreciated!

If the aim is to explore the limitations of the method itself and not just the Arduino software, a good exercise could be to have the students all share their results with each other, or have a few groups share them with you to write them up on a whiteboard, so they can see how the results vary over multiple chips and get a better idea of how rough and imprecise this sensor really is.

If resources allow it, another phase of the activity can be to use a more accurate external reference to see if that improves the results. Calculations can be made about how much inaccuracy is from the internal reference and how much is from the temperature sensor.

The datasheet doesn't say, but I'm pretty sure the temperature sensor is just a few diodes in series with a current source, like this diagram from a PIC datasheet:
screenshot.28.jpg

That could lead into a discussion of what better ways might exist to measure temperature, such as an NTC resistor or a thermocouple.

screenshot.28.jpg

I have read your message many many times; as I read more, I enjoy more both technically and aesthetically, and in the long run I (as a non-native) attribute everything to the amazing power of the English Language and its vocabulary. (I was/am sure about the purity of my compliments.)

//------------------------------------------------------------------------------------------------------------------

1. I executed the following codes as a Test Run when the Serial Monitor showed 79.170C. The program contains few debugging lines.

void setup() 
{
 Serial.begin(9600);

 ADCSRA = 0x86; //250 kHz ADC Clock
 ADMUX = 0xC8; // 1.1V internal reference, right-shift internal temp sensor Channel-8
 delay(100);  // wait for a while for the channel to stabilize 

//---- single conversion; discard the first reading-------------
 bitSet(ADCSRA, 6);                         // Start ADC  conversion by putting LH at the ADSC bit
 while (bitRead(ADCSRA, 6) !=LOW)  //checking if conversion done
    ;
 int x = ADCL;
 int y = ADCH;
 
}

void loop() 
{

 bitSet(ADCSRA, 6);
 while (bitRead(ADCSRA, 6) !=LOW)
    ;
 int x1 = ADCL;
 int y1 = ADCH;
  
 Serial.println(x1, HEX);       //debug : ADCL = 0x5C
 Serial.println(y1, HEX);       //debug : ADCH = 0x01
 unsigned long ADCT = ADCW;     // reading 16-bit but storing in 32-bit format
 Serial.println(ADCT, HEX);     //debug : ADCT = 0x015C
 
 //Manual Computation: T*10E+4 = 0x2625*ADCT - 0x27BE01 = 33DA4C - 27BE01 = 0xC1C4B ----> 79.3675 deg C 
 unsigned long x2 = 0x2625*ADCT - 0x27BE01;   //C1C4B (unsigned log for confining the value to unsigned)

 Serial.println(x2, HEX);    //C1C4B
 float x3 = (float)(0x2625*ADCT - 0x27BE01)/10000;  //Temperature
 Serial.println(x3, 2);      // Temp = 79.36 deg C

 delay(3000); // temperature sampling time 3-sec
}

2. I think that I will give up the plan of using the internal temperature sensor (it is bad!) of the ATmega328 for the upcoming student project; instead, I will be using the LM35 that you have prescribed. Or an NTC thermistor and make it 2-point calibrated sensor using a secondary calibrator.

**3.**One of the reasons for choosing the internal sensor of the ATmega328 is that the sensor has 2-point known responses, and it will help me to demonstrate to the students --
(a) The meaning and necessity of calibration of a real sensor
(b) The application of the offset and gain (shifting and rotation) in order to make an virtual alignment of the actual response with the ideal response.

**4.**LM35 sensor is directly calibrated to temperature and there is no opportunity to derive the y= mx + c curve for it.

//-----------------------------------------------------------------------------------------------------------------

inTB.ino (1.13 KB)

I don't remember the temperature sensor being that bad when i tried it before, but that was a while ago. I'll try again when I get home today.

You shouldn't have to mess with ADCSRA, the Arduino core will already have that set up to the right prescaler before setup() is executed.

unsigned long ADCT = ADCW;     // reading 16-bit but storing in 32-bit format

You already read ADCL and ADCH before this. I don't know if this statement will work properly. Change it to:

unsigned long ADCT = (y1<<8) | x1;     // reading 16-bit but storing in 32-bit format

AHH!!!! I took my time to write a post about what I did, but due to trying to attach a photo that I didn't compress, I lost half of it. I'm not typing it again, here's the summary.

My ambient temperature is 25 degrees Celcius.

I double checked the math, and I got the same results. It's not the formula.

I thought it might be self-heating, so I modified the sketch to reduce power consumption as much as possible. No change.

Then I grabbed 8 other ATmega328P boards (1 more UNO, 3 3.3V Pro Minis, 2 5V Pro Minis, 1 Adafruit Metro, 1 Solarbotics Ardweeny), and they all calculated the temperature to be in the 80s or 90s. One of the Pro Minis was even reporting a temperature of 100!

So not only does the internal temperature sensor have very poor tolerance, the output is nowhere near what the datasheet says it should be. Terrible.

OK, and I would like to give you a thank by clicking on the Karma for all the works you shared with us.

Based on the recommendation of an AVR note:

1. I cranked down the clkSYS to 1 MHz by programming the CLKPR-register, the temperature came down from 790C to 750C. I kept the ADC conversion clock to 250 KHz.

2. I operated the ADC in 'Noise Reduction Mode' with clkCPU=16 MHz and clkADC=250 K, the result is same as Step-1.
//--------------------------------------------------------------------------------------------------------------------

Just as a curiosity, I measured the internal reference of the operating ADC (picking up from AREF point) using another Arduino UNO, and I found it to be 1.063 V. After the application of the correction, the temperature came down to 690C from 790C.

We have about 140 Arduino UNO Kits that belong to the students. We will measure the internal temperatures of all these Kits using the same program and will record the variations.

In accordance with an application note AN103Page-4 found in the net, the internal temperature of the chip --
The temp sensor measures the temperature of the die of the device, which is likely to be a few degrees warmer than the surrounding ambient temperature due to device power dissipation.

The ATmega328 is terribly far off!

Even if the datasheet is not accurate, as long as the output is consistent with respect to temperature, that can be fixed by characterizing the output yourself. Measure the output of the sensor at 2 or 3 different temperatures without the range you are trying to measure.

Unfortunately, the large amount of chip-to-chip variation means that each controller would need to be individually characterized and calibrated if you wanted any better than 15 degrees of accuracy. As a learning exercise that's fine, and it also serves as a practical example of how to decide if something is good enough or not for a particular use. Just because it's in the features list doesn't mean its specs are any good.

Maybe the datasheet is not correct here. In my ATTiny85 datasheet the description of temperature sensor is a bit different:

The measured voltage has a linear relationship to the temperature as described in Table 17-2 The sensitivity is approximately 1 LSB/°C and the accuracy depends on the method of user calibration. Typically, the measurement accuracy after a single temperature calibration is ±10°C, assuming calibration at room temperature. Better accuracies are achieved by using two temperature points for calibration.

I think this holds for ATMega too. The ADCs are not identical (the Tiny has possibility of differential measuring) but the temp sensor itself is probably the same. So probaly you should callibrate at least at one point if you want somewhat accurate temperature (+/- 10 °C over the whole temperature range - but more accurate close to the callibrating temp).

Also if you are not interested in absolute value of the temperature but only relative change the sensor may be useful. For example quick increase may indicate something is wrong with cooling and you should turn off the load.

I'm not sure how accurate that is. How cold can canned air get when you turn it upside down and use it as freeze spray?


Using the equation Golam calculated from the datasheet function, I was able to get Frosty the Arduino's reported temperature to go from 85oC down to 7oC. Assuming the linearity is the same as the datasheet and it's just a matter of the offset voltage being different, an 80 degree delta from my normal ambient temperature would be equivalent to about -55oC with the freeze spray.

Apparently that's not as ridiculous as I originally thought, since I found a few pages that suggest freeze spray can go down to about -50oC in temperature.

Even if the datasheet is not accurate, as long as the output is consistent with respect to temperature, that can be fixed by characterising the output yourself. Measure the output of the sensor at 2 or 3 different temperatures without the range you are trying to measure.

The following is the response equation for binary temperature T in terms of ADC value (Post #6). (From the studies of Post #16, #17, and #18, we have understood that the temperature sensor of the ATmega328 is active, and we have decided to consider an 'unaccounted offset' of 500C for the temperature sensor at our own responsibility. Alternatively, we will re-calibrate (characterising the output) the temperature sensor using LM35 or a secondary calibrator.)

==> T*104= 2625h * ADCT - 27BE01h ---------------------(2)

We wish show the current temperature value on cc-type 7-segment display unit (Fig-1 of OP) in decimal format. Is there any way (algorithm) to convert the binary-coded temperature (Eqn. 2) directly into cc-coded temperature and show it on the cc(common cathode)-type 7-segment display unit? Or we need to go through the intermediate stage of converting binary-coded temperature into BCD-coded temperature; then, converting the BCD-coded temperature into cc (common cathode)-coded temperature consulting Look up Table (BCD digit vs cc-code); then, transferring the cc-coded temperature onto the cc-type display unit.

What is "cc-coded"? I'm not familiar with that term.