NTC Measurements

When dealing with low-cost, home made termometers, the choice often fall on the NTCs. These sensors are resistors which are varying their resistance in function of the temperature, with a negative trend: Negative Temperature Coefficient is their name, also known as Thermistor. That means higher the temperature, lower the resistance:

Thermistor Response Curve1.gif
A typical NTC curve (www.arroyinstruments.com)

We observe that this cheap sensor have the price to be non-linear at all. There are various methods to derive a method to interpret the correct temperature. Here I will go through the ones that are used to achieve quite reasonable precision without having/paying a calibration laboratory.

Look-Up Table approach

Usually the datasheet provides a set of values which are sampled from a sensor and correspond to our being inside their stated tolerance:


In this picture you can see the stated resistance at a certain temperature, and its tolerance. An immediate drawback, if no other tables are available, is that this table can bring a precision of up to 5°C only. The parameter “B” is called normally \beta.

Moreover, a sensor with a tolerance of 5%, refers to 25°C only. This error of the resistance must be added with the “\frac{\Delta R}{R} due to β toll.” factor in the table above, from now on called Δβ/β. Associated with it, there is the temperature coefficient, TCR (also known as \alpha), which describes how steep  is the curve. You may understand that with a very steep curve, so an high TCR, there is a little deviation of the temperature in the X axis, associated with a high variation of resistance on the Y axis therefore we have an high sensitivity. The situation is the opposite when reading high temperatures with a low TCR, the sensitivity drops rapidly.

The thermistor error of a punctual read is then devised as follow:

\frac{\Delta R_{therm}}{R_{therm}} = (((1 + \frac{\Delta R_{25^{\circ}C}}{R_{25^{\circ}C}}) \cdot (1 + \frac{\Delta \beta}{\beta})) - 1) \cdot 100               (eq. 1)

where R_{25^{\circ}C} is the resistance tolerance at the reference temperature (specified in the datasheet, here is 25°C), and  \beta  is a coefficient which characterize the NTC material, devised by measuring two different temperature (and is specified in the datasheet). If we need to keep the right tolerance after changing the sensor with another of the same model without calibration, we need to observe these tolerances. Combineing them with the TCR, we obtain the temperature’s punctual error:

\Delta T = \frac{\Delta R_{therm}}{R_{therm}} / TCR            (eq. 2)

Equation approach

There are a lot of methods which are used to linearize the behaviour , by linearizing the model. The most famous is the Steinhart-Hart equation, which uses a set of coefficients which are provided in two ways: from manufacturer, or can be devised by measuring 3 different temperatures and solving 3 equations for 3 unknowns. If these coeffients are not provided from manufacturer, one can use a more precise termometer, measure 3 temperatures and its resistance temperature, solving this equation for the S-H of 3rd order:


The sensor’s manufacturer adopted to experiment provides the coefficients up to 4th order, both for reversed anddirect measurement:


With a sensor stated to have 5% of tolerance, one can actually use the coefficient without the full decimal precision instead used (ideally) from the manufacturer, because the error provided by such formula is in the order of mK, while the final reading, due to various errors, is higher than 1.5K. I neglect this S-H error.

Error estimation

Assuming a negligible error from the S-H calculus that uses the parameters given by manufacturer, usually we use a microcontroller with an ADC and a voltage divider. The error from a common ADC is half LSB, so that

\frac{\Delta ADC}{ADC} \% = \frac{1}{2^{(N+1)}} = 0.5 LSB      (eq. 3)

The error of the voltage divider tends to be double of the two resistors used if are too much different, otherwise tends to be the mean of the two relative errors of the two resistors, like \frac{\Delta R1 + \Delta R2}{2}. See the graph, where 100% is the mean value between errors of the 2 resistors, and 200% represent the sum of the 2 errors:


These two resistors are used in this way, in which one is the Thermistor:


where at the reference temperature (provided by manufacturer and usually 25°C) the Rref and Rtherm have the same value (so we bought a matched thermistor with a certain resistance to reduce errors). Depending on your temperature range, you can se how varies the the ratio and see how greater can be considered the total error.

How greater is the error in my temperature range? The previous value of \frac{\Delta R_{therm}}{R_{therm}} and its TCR will lead to a temperature error like this:


in which the ADC and condition circuitry errors are NOT considered. But an idea of performance can be made if no calibration is performed (see later). If the resistance at the extremes of my range is not so different from the reference resistor (a normal fixed resistor in the schematic above), then it is not a mandatory to sum it up both errors of the two resistors, but can be a little less.

If I need to measure between 0°C and 100°C, the datasheet provides the additional error of the resistance due to the tolerance of β parameter, called Δβ/β. We will find that at 100°C there is low TCR and high relative error. ONLY NOW we can apply the worst case total error \Delta T = \frac{\Delta R}{R} / TCR with \frac{\Delta R}{R} = \frac{\Delta R_{therm 100^{\circ}C}}{R_{therm 100^{\circ}C}} + \frac{\Delta R_{ref}}{R_{ref}} , where R_{therm 100^{\circ}C} is the (eq. 1) at temperature of 100°C using the table from manufacturer, while Rref is the the fixed resistor in the schematic above and \frac{\Delta R_{ref}}{R_{ref}} its relative error.

TCR will be chosen to achieve the higher relative error, so will be the TCR at 100°C (as said before, the higher temperature of the range), along with the estimated resistance value at that temperature (of course..). You may see how the error can be greatly reduced if reading values with higher TCR at lower temperatures, and how small is it at 25°C. But the boundaries must contains the greater error tolerance, allowing the user to change the sensor in the field without recalibration.

With the calibration using the set of 3 equations above, all these errors are compensated, voltage divider included. The remaining one will be truncation error of the S-H coefficients due to the finite machine precision (whether is a PC or an MCU used to make the calibration),  the errors of the reference termometer and the intrinsic errors of the S-H model, the quantization error of the ADC (half LSB) and for sure others that I have missed. It is not trivial to quantify everything. And quantification, when talking about measures, is almost everything.

Where is the ADC?

We have found how greater is the error of the analog quantities. Now where is the least sensible part of the NTC curve? The one at the higher temperature, as said before (lower TCR). Until now I have estimated a certain error of the total voltage divider’s resistance.

Now is needed to find how an ADC error can mismatch the resistance. Let’s go at 100°C, using an S-H estimation or the Look-Up table, then calculate a sort of manual derivative, let’s say the value R_{therm} = R_{100^{\circ}C} + \Delta R, where ΔR is the immediate available step to achieve a temperature lower of a step equal to the required precision (if I want a precision of 1°C, then is the resistance at 99°C if I have the S-H equation, or it is the resistance at 95°C if I have a rough Look-Up table like the one in this article).

From the circuit of the voltage divider, we have V_{adc1} = V_{refADC} \cdot \frac {R_{100^{\circ}C}}{R_{100^{\circ}C}+R_{REF}} and V_{adc2} = V_{ref ADC} \cdot \frac {R_{100^{\circ}C} + \Delta R}{R_{100^{\circ}C} + \Delta R +R_{REF}}. The \frac{V_{adc1} - V_{adc2}}{V_{LSB}} is how many discrete steps can be sampled inside a ΔR variation. E.g., if 1LSB = 3mV (ADC provides 3mV/bit) and from 100°C to 99°C the variation read from ADC is 6mV, I can’t have an accuracy higher than 2LSB, meaning 0.5°C (2LSB to represent 1°C). If I am lower than 1LSB, I can’t discern my prefixed step lower than 1°C.

Saying the same more mathematically: consider the reference voltage applied to voltage divider to be 3V. And the datasheet provides a certain TCR at 100°C. Then the resistance at 99°C will be:

\Delta R_{1^{\circ}C} = R_{100^{\circ}C} - R_{100^{\circ}C} \cdot \frac{TCR_{100^{\circ}C}}{100}\cdot 1^{\circ}C

so that:

1.5mV \leq 3V \cdot \frac{R_{100^{\circ}C}}{R_{100^{\circ}C} + R_{REF}} - 3V \cdot \frac{R_{100^{\circ}C} - \Delta R_{1^{\circ}C}}{R_{100^{\circ}C} - \Delta R_{1^{\circ}C} + R_{REF}} = \Delta V_{1^{\circ}C}

Finally, the additional temperature error from the ADC is, in the worst case:

\Delta T_{ADC} = \frac {1^{\circ}C}{\frac{\Delta V_{1^{\circ}C}}{0.5LSB[V]}}          (eq. 4)


The final precision, from (eq.2) and (eq. 4), is:

\Delta T = \frac{\frac{\Delta{R}}{R}}{TCR_{100^{\circ}C}} + \Delta T_{ADC}

One can try and find out that with an ADC of N = 10 bit, and components at 5%, included the NTC, in range between 0°C-100°C, hardly can be achieved a precision lower than 3°C/4°C, despite the accuracy can be around 0.5°C/1°C, without calibration. But note that this low precision is due to the consideration of the range up to its most imprecise extreme: reducing the range to, let’s say, 60°C the precision can be improved a lot. Just keep that in mind when you read 25°C, or 150°C using an NTC.

2381 640 63103.jpg
The beauty and the beast

PWM and I2C libraries

clangI needed a flexible square waveform generator to test the behavior of a mosfet. I have in my hand a board with a PIC18 microcontroller (http://sangon.it/), so I wrote few lines of code for it. Of course, things are degenerated and I have been infected by the developer fever and is born the desire of reuse them without always opening the data-sheet. So a barely complete set of runtime variables which can be used in the provided functions has been implemented, which can be useful in a general purpose environment; only the more improbable settings, according to my opinion, are kept static with the need of recompiling libraries, if are changed.

So, in GitHub button below there are functions for all the capture/compare modules of the PIC18F47J53, but are very similar if needed to be expanded for other PIC18/xx microcontrollers. I wrote them to be compatible with the XC8 (link) compiler. The source files are timers.c and capturecompare.c with their relative haders. pwm.h is particular since simply combines the previous sources in a more elegant way.
The use is pretty straightforward, requires only to know the allowable range of variables or the implemented defines. The compiler automatically implement in memory only the functions used, but if it is not the case, a proper set of #defines is adopted, one per hardware module present on the MCU. A good requirement is to know the block diagram of the module used, in order to see the correspondences with the software, and reading the README for everything else.

I’ve put also  the first version of the I2C, since I wrote them for the DS Emulator… why not writing them in order to be reused again?

Click to follow on GitHub:github_logo

For sure I will implement the same libraries for the enhanced modules, which are still needed for my little dumb projects. Happy coding!

The anti-loud siren


What happens if some one try to piss off people and make them scream, and you can’t calm down them?
What happens if you are in a crowded environment where people start talking when they shouldn’t?
Or what happens if you are one of those people who talk constantly loud out, but wants to improve they ability to talk “normal”?
Or if your boss always scream at you?
WHAT if there is a solution to this?

Ok, after this junk styled presentation, I want to show a little project born and made in a week-end. So very stupid, but also nice, imho. It’s based on make some loud when there is too noise around and I decided to build it ‘cause sometimes people talks loudly and they didn’t notice that. Presented as a little joke for them, here is shown the anti-figher siren.


Here we are talking about a simple analog circuit which receive a signal from a microphone, bias and amplifying it, then put into a common emitter BJT which square it up to be read from a microcontroller – here an Atmega328 MCU, Arduino Duemilanove board.
I started by thinking about what is already available at home. And I realized that I can finally use that lonely LM358 (dual op-amp), then an BC337 was also available and a mic was re-born from.. I don’t remember, it was simply there, but with no mark helping to understand its capabilities.
That being said, after few suggestion of order of amplification of the preamplifier, I came up with a solution which magnifiying the signal up to 2550 times approximately, reduced accordingly by the potentiometer. This includes the second amplifier which amplifies of 12 times and drive the bjt, common emitter to work in saturation. The biasing of the final signal allow the BJT to act as a switch “normally closed”: in this way the signal which allow the MCU pin change is related to the “negative” wave of sound signal, and the digital value is not inverted.

Here the schematic, in Eagle:


Now, since this project was started in Friday morning, and I was pretending to finishing it by the weekend, the fastest and rough thing to do was to use Arduino and sketching a program that uses interrupt on the pin from the microphone and “tone-out” an alarm of 1 second on a buzzer. Actually, the alarm sounds like a siren, and to be honest I find it as cool as stupid.

Here the sketch:

 // Definition of interrupt names
#include < avr/io.h >
// ISR interrupt service routine
#include < avr/interrupt.h >

static uint8_t buzz = 0;
uint16_t i = 0;

ISR(PCINT2_vect) {
  buzz = 1;

void setup() {

  pinMode(4, INPUT);
  pinMode(5, OUTPUT);
  EIMSK = 0;
  PCICR = 0b00000100;
  PCMSK2 = 0b00010000; // pin4 digital arduino


void loop() {

  if (buzz){
    for (i = 2000; i<3000; i=i+10){
       tone(5, i);
    for (i = 3000; i>2000; i=i-10){
       tone(5, i);


The breadboarded version looks like this:


But the final work, if we can call it this way, is made on a prototyping board and overlapped to Arduino. Then fixed with some tape, can be hooked to an arm, like we can do with our smartphones when jogging, or can simply be put smewehere on the desk. This ugly superimposition of boards (and also glued with tape, but not applied when taking these pics), shows my main skill hadicap: enclosures. 🙂

Ah, components are not too close to board to allow me to eventually reuse them in the future, inside a breadboard. I know, I could avoid it, but it’s a trick in case of more expensive components which are mounted on temporary circuits without any socket – this is not the case, though.



The perfect final of every project – no matter what how stupid it is, is to build a final prototype all in a single board or in a system which is made for this purpose and nothing more (if it is not desired in the project, obviously). So, if an MCU is used, a proper smaller one should be used. Or in this case, one can have some more fun by building a detector and siren generation circuits without the use of a microcontroller, and put everything toghether, obtaining a nicer gadget… To keep people silent!