# Temperature measurement with the RL78

Hello, today I will show you how to make use of the internal temperature sensor, internal voltage reference and the Analog-to-Digital Converter on the RL78/G13 devices. The application monitors the voltage output by the internal temperature sensor and by the internal voltage reference. By reading both voltages we can compensate the temperature sensor output according to the ADC power supply (which, in this case, is the same for the whole MCU).

The ADC module is set to operate in continuous mode, alternating between two inputs: the internal voltage reference (1.45V) and the internal temperature sensor (the ISR switches the input channel).

Supply voltage is calculated by reading the internal voltage output (1.45V) and considering the read value is proportional to the ADC power supply (further details are shown on my free portuguese book Microcontroladores RL78: Guia Básico). Measuring the supply voltage is necessary as the temperature sensor’s voltage output is a function of the system power supply voltage.

The temperature sensor’s voltage output is calculated by using the following equation (it is written in brazilian portuguese): Current temperature can be calculated with the following equation which uses the ADCR (ADC binary result) reading and supply voltage VDD (again the equation is written in portuguese): After some math, the application presents the supply voltage and ambient temperature on the RL78/G13 RSK’s LCD display.

This example also illustrates a technic of data formatting for display presentation (or whatever other media) by using integer variables to represent fractional data. The LCD_wrie_frac_int function receives an integer value as a parameter and prints out data using the following format: X.YY where X is the higher than 100 part and YY is the less than 100 part, which is considered the fractional part. That way, 100 is printed as 1.00 and 9999 is printed as 99.99. Values lower than 100 are considered less than 1.00.

Notice that our application also makes use of a fixed temperature offset value (“toff” variable). This is due to the needed calibration for the internal temperature sensor. We came to the value by experimentation. On a professional environment it would be needed some kind of production calibration, storing the calibration data onto the flash during manufacturing.

The following code was taken from my portuguese Microcontroladres RL78: Guia Básico book:

```#include "ior5f100le.h"
#include "ior5f100le_ext.h"
#include "intrinsics.h"
#include "myRL78.h"
#include "lcd_8x2.c"

// Watchdog config
#pragma location = "OPTBYTE"
__root __far const char opbyte0 = WDT_OFF;
// Low voltage detector config
#pragma location = "OPTBYTE"
__root __far const char opbyte1 = LVD_OFF;
// Selects internal 32MHz high speed oscillator
#pragma location = "OPTBYTE"
__root __far const char opbyte2 = FLASH_HS | CLK_32MHZ;
// Debug enabled, erases memory on password failure
#pragma location = "OPTBYTE"
__root __far const char opbyte3 = DEBUG_ON_ERASE;

/* Set the security ID */
#pragma location = "SECUID"
__root __far const char password = {0,0,0,0,0,0,0,0,0,0};

{
unsigned char display_update  : 1;
} bits;

unsigned int acc_vref, vref, acc_vtemp, vtemp, vdd;
int toff;
unsigned long long_data;

{
unsigned int result;
// adc_channel controls which channel will be selected
{ // adc_channel==1 => selects the temperature sensor (voltage reference was converted)
acc_vref += result - vref;  // accumulate the result, subtracs the average
vref = acc_vref >> 6;       // calculates the average from 64 results
} else
{
acc_vtemp += result - vtemp;  // accumulate the result, subtracts the average
vtemp = acc_vtemp >> 6;       // calculates the average from 64 results
}
}

#pragma vector = INTTM00_vect
__interrupt void TAU0_channel0_ISR(void)
{
bits.display_update = 1;  // updates display data every 500ms
}

void init(void)
{
ADPC = 0;         // no analog pin
// Sets up ADC (multiple conversions, one channel, software triggered)
TAU0EN = 1;       // TAU0 enabled
TPS0 = TAU_CK0_DIV1024; // CK0=31250Hz, CK1=32MHz, CK2=16MHz e CK3=125kHz
// TAU0 channel 0 on timer mode
TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_TIMER;
TDR00 = 15624;    // one interrupt every 500ms
TMMK00 = 0;       // TAU0 channel 0 interrupt enabled
TS0L = TAU_CH0;   // Start TAU0 channel 0
LCD_init(DISPLAY_8x5|_2LINES,DISPLAY_ON|CURSOR_OFF|CURSOR_FIXED);
acc_vref = vref = 0;
acc_vtemp = vtemp = 0;
__enable_interrupt(); // RL78 interrupts are enabled
}

/*
This function writes an integer value on the LCD. It uses a special formatting
in order to represent a fractional value with integers. The thousands and hundreds
digits are printed followed by a decimal point and tens and units digits.
Thus, an 1001 value is printed as 10.01
*/
void LCD_write_frac_int(unsigned int data)
{
unsigned char aux, space;
unsigned int sub = 10000;
aux = 0;
space = 1;
while (sub)
{
aux = 0;
while (data>=sub)
{
data -= sub;
aux++;
space = 0;
}
if (!space) LCD_write_char(aux+'0');
sub /= 10;
if (sub==10)
{
if (space) LCD_write_char('0');
LCD_write_char('.');
space = 0;
}
}
if (space) LCD_write_char('0');
}

void main(void)
{
init();
LCD_write_char('\f');         // clears display
toff = -500;                  // temperature offset (-5 celsius degrees)
while(1)
{
// if the display update is set
if (bits.display_update)
{
bits.display_update = 0;    // clears display update flag
LCD_pos_xy(0,0);            // cursor at line 0, column 0
LCD_write_string("V=");
long_data = 148480 / vref;  // VDD calculation
vdd = long_data;
LCD_write_frac_int(vdd);    // prints out VDD (5V = 5.00)
LCD_write_string("   ");    // erases remaining characters
LCD_pos_xy(0,1);            // cursor at line 1, column 0
LCD_write_string("T=");
// current temperature calculation
long_data = 2500 - ((long)vtemp*(long)vdd*100 - 10752000)/368 + toff;
LCD_write_frac_int(long_data);  // prints out the temperature
LCD_write_string("   ");    // erases remaining characters
}
}
}```