Teensy 3 Noob question about analog read

Status
Not open for further replies.

v4d3n

Member
analogread() seems to have a lot of error in it. With multiple pots, it get's worse.

Even with A0 to ground I get numbers 0 to 5. I've also tried A9.

Is there are way to make it more accurate? The examples I've seen online make it it look very accurate...no variance between the 0 to 1024...


Thank you!
 
A couple of things...

What resolution are you reading at?

Have you tried putting a 0.1uF capacitor from the input to GND?

How quickly are you reading? Are you averaging or decimating?

Also, have you added capacitors for the Aref pin?

You may be picking up spurious signals...
 
Last edited:
When it comes to analog signals, lots of things can create noise.

Maybe if you post a photo of your actual build, a schematic (if it's complex), and the actual code (if you're doing anything else), would let us give you better advice.
 
Thank you for the replies.

I don't have any capacitors. I'll pick some up in a bit.
I kind of get the capcitor from the input to ground. It would "empty" the reading?
I don't understand your other statement about Aref. Hook it to what?

Care to educate me? :) Us ME's only got really basic EE stuff in college....and that was years ago.

Anything that makes the readings better will be great!

As for schematic, there isn't much to it. Power the Teensy (3.3V) to the pot. Ground from the Teensy (I've tried AGND and GND).
Signal to pin A9 (also tried A0).

Note: I was using the 5v like the tutorial shows, but it hits 1024 at 3.3v. I don't see a difference in accuracy.

My best luck so far has been taking the signal and picking it out of a group. (for example a A9 value of 512 to 522 is position 0, 532 to 542 is 1, etc). It's dynamic so I can change just the group size to see what happens. It's not bad.
I also have a dead zone programmed in, so the wiggle in the joystick and pedals don't cause me to drift.
I then take the group number and convert it to a 0 to 1024 then send it to the computer (Joystick.Z(modedVal)).

Anything to help reduce the noise would be great! It would reduce the group size (or eliminate the need for it) and deadzone.


This is the code I am using while I test the pots.
Code:
 pinMode(9, INPUT);
  val = analogRead(9);
  Serial.print("Position: ");
  Serial.println(val);
  delay(500);
 
I just discovered AnalogReadRes().

I'll try the capacitors, sampling faster, and different bit rates.
I'm going to try to sample at a much faster rate and average them.

It's not in the reference help file...
 
There's also a function called analogReadAverging() on Teensy 3.0. It controls automatic averaging done in the ADC. The max is 32, so use analogReadAveraging(32).

However, if you have a ground loop or other signal quality issue, it's best to fix the actual analog problem.
 
The capacitor from the input to ground did the trick :)

Thanks for analogReadAveraging, I'll use that.

Thank you!
 
For an audio-sampling input, I had really nice results with the following config:
- no smoothing capacitor, just direct from an opamp (schematic here: https://github.com/hughpyle/teensy-povwand/blob/master/schematic.png)
- analogReference(EXTERNAL); // because my input voltage was typically >1.2v
- analogReadResolution(10); // anything more seemed like overkill
- analogReadAveraging(4);

and then triggering the ADC sampler from the PIT (interrupt timer) that was controlling the loop, by setting
// 0101 PIT trigger 1
SIM_SOPT7 = ( SIM_SOPT7 & 0xFFF0 ) + 5;

See page 235 of the reference manual pdf (chapter 12: System Integration Module) for the documentation on the SIM_SOPT registers.
 
Hello,
I am experiencing a similar behavior as in the first post. I am reading temperature with a thermistor and my circuit and code are very similar than this tutorial from Adafruit. My setup works with the Arduino Micro; with the Teensy 3.0, the readings are always off by a few degrees (checking with a calibrated thermometer) and very noisy (I tried many combinations of Averaging and analog resolutions). If however I add a 0.1 micro Farad Capacitor between GND and the Thermistor, the temperature is correct and much more stable.
I understand the capacitor impact to stabilize readings, however I am puzzled by the difference in raw values! Average values should be similar with or without capacitor I think.
Does someone has good explanation or guideline for consistent and accurate analog reading?
 
If you'll post the exact part number of the thermistor (and where to buy it), and a photo of how you wired it, plus any other necessary wiring details, I'll get the parts and try to duplicate this problem here.

I can only investigate if I can exactly replicate the situation here, so please post very specific info about exactly how you wired this.
 
I understand the capacitor impact to stabilize readings, however I am puzzled by the difference in raw values! Average values should be similar with or without capacitor I think.

Not necessarily. Consider a set-up where the ADC is fed with a constant DC voltage plus a high frequency sine-wave signal. The average voltage read will be the DC voltage plus the RMS value of the sine wave. Remember that these are single-ended signals between GND and Vcc. Its not the same as a twin-rail +Vcc, GND, -Vcc set-up where you can assume high frequency signals have no DC component.

Add a capacitor that shunts this frequency to ground, and not only does the variation reduce but the mean value changes also.

Not saying this is what happens in your case, but it is at least an explanation of how it is possible.

A second possibility - if you are switching between multiplexed ADC inputs, and the ADC has a single sample and hold capacitor (rather than one per multiplexed input) and the output impedence of the sensor is high (which is likely, for a thermistor) then the sample and hold capacitor may not have time to fully charge before being read. Adding an external capacitor means the sample and hold capacitor can charge more quickly and get the right reading. For slowly varying signals, a way around this is to discard the first reading after switching inputs; then average the following ones. A better way is to use a unity gain, rail-to-rail op-amp buffer between the sensor and the ADC. The ADC then sees a low impedence source and can charge the sample-and-hold capacitor rapidly.

And of course if the sensor is (part of) a potential divider between some voltage and ground, that voltage needs to be stable. Vcc, especially if it comes from the USB power of a computer and is not being regulated, can be very noisy. Using a separate, clean analog Vcc power supply is probably the best way to reduce noise and variability. On Teensy 3.0, the USB voltage goes through a 3.3V regulator so will be cleaner than using the USB voltage directly as Teensy 2.0 and ++ 2.0 do. If you use a separate power supply, be sure to tie the ground to the Teensy ground (either directly or through an inductor).

These approaches can be combined. Some experimentation is in order to see what is the largest source of variation.

When I did this for a multi-analog-input project (using an Arduino Mega2560, so 5V Vcc) the largest single improvement was using a simple regulated power supply instead of Vcc from the computer USB. Comparatively minor gains from using buffers. In that set-up I did not need additional capacitance on the ADC inputs. In contrast, even the most elaborate software averaging schemes (discard first two readings, discard highest and lowest of the next 16 and average the 14 remaining) had little impact, as the main problem was noisy Vcc.
 
Not necessarily. Consider a set-up where the ADC is fed with a constant DC voltage plus a high frequency sine-wave signal. The average voltage read will be the DC voltage plus the RMS value of the sine wave. Remember that these are single-ended signals between GND and Vcc. Its not the same as a twin-rail +Vcc, GND, -Vcc set-up where you can assume high frequency signals have no DC component.

Add a capacitor that shunts this frequency to ground, and not only does the variation reduce but the mean value changes also.

Adding a sinewave to a DC value doesn't change the average (it's not DC + RMS value). If the ADC is working 'normally', then the average should be the same with and without a capacitor. However, if you have long wires, you could be picking up so much interference that the ADC can't work properly (i.e. the resultant signal when the interference is added exceeds its conversion range). Another possibility is that you are getting aliasing (the ADC is converting correctly, but the samples of the input signal may not be representative of the true average).

In all these types of applications, it's best to use a capacitor to filter.
 
Thank you all for explanations. I don't think this has to do with cable length or DC input noise, I also tried a lab power supply with connection to AREF, same result.
Here is a picture of my simplified circuit where the behavior is observed. I am using Termistor from Murata model NXFT15WF104FA, these are 100KOhm at 25 degree Celsius (available at Mouser for example). Not only noise considerably increase, but also values are quite different if I remove the capacitor.
IMG_1947.JPG

Here is the sample code, mostly from Adafruit Tutorial:

Code:
#define BCOEFFICIENT 4250 //Thermistor B coefficient
#define ANALOG 4095
#define RESIST 100000 // value in Ohm of the resistor devider
long readvalue; 
float temp;
float resist1;
String concat;

void setup(){ 

  Serial.begin(9600); 
  analogReadRes(12);
  analogReadAveraging(10);
  delay(100);
} 

void loop() { 
  readvalue = analogRead(A1);
  Serial.print(readvalue); 
  Serial.print(" ");
  
  // convert the value to resistance
  resist1 = ((float)ANALOG / (float)readvalue) - 1.0; //12bit = 4096
  resist1 = (float)RESIST / resist1;

  concat = String(int(Celsius(resist1)*100));
  Serial.println(concat);

  delay(100); 
} 

float Celsius(float val) 
{
  // Convert resistance to Celsius
  float steinhart;
  steinhart = val / RESIST;                    // (R/Ro)
  steinhart = log(steinhart);                   // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                  // 1/B * ln(R/Ro)
  steinhart += 1.0 / (25 + 273.15);     // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;                // convert to Celsius  
  return steinhart;
}


My final project has 12 thermistors from A0 to A11, analog reading is pretty stable with the addition of capacitors and way of without. Same behavior on all pins.

By the way, are there numbers for A10 and A11? I wanted to use a loop on all Analog pins.
 
I forget what sets the analog reference in the ADC, but shouldn't you do that ?

Also, perhaps ANALOG should be 4096 ?

You also have two divide-by-zero hazards lurking there. Best to trap for them.
 
Adding a sinewave to a DC value doesn't change the average (it's not DC + RMS value).

Ah, my apologies to anyone whom I may have misled through my misunderstanding.
So, mains interference (for example) on a line at or near GND might take the value negative?
 
A 100k impedance on the ADC input is quite a large value. If you had a sensitive AC-coupled scope on that A/D input pin, I bet you would see a large negative spike at the moment the Teensy's ADC is activated and the input sampling capacitor is connected to the pin. (at least, I have seen this in other, similar situations). Connecting a capacitor causes that spike to become smaller in amplitude, and the final output of the ADC will increase and become a better approximation to the average DC value. In other words, I agree with Nantonos' post above.

If you do a more rapid ADC process (more readings per second) you have to supply more average current to that input sampling cap, which will cause a larger DC error. You can reduce the error by using a lower impedance sensor, for example a 10k thermistor or smaller, or use a buffer opamp.
 
Last edited:
Following your explanations I made a quick (and very educative) experiment. I replaced the thermistor by a resistor to make a simple voltage divider.
I measured 300 samples at 10Hz sampling rate, with 3 voltage dividers, 100K-100K then 10K-10K, finally 1K-1K.
I measured once without capacitor, than with a 0.1uF capacitor.
At 12bit, the average should be around 2048 taking into account the resistors variation. Except for the 100K divider without capacitors, all configurations are quite good I think. It is worth noting that the best result is 10K without capacitor.

Screen Shot 2013-01-08 at 9.39.48 PM.png
 
Hi all, I want to make a query, I can use directly in a detector Hall Teensy 3?, I have a 3.5v differential voltage., going from 0.85 to 4.2V.
I have to put some protective resistance eg 220 Ohm.?.
according to specifications, the analog inputs have 14 to 16 bits, so I have to have a minimum resolution of 8192-16384 steps, correct?, thanks.
 
I measured 300 samples at 10Hz sampling rate, with 3 voltage dividers, 100K-100K then 10K-10K, finally 1K-1K.
I measured once without capacitor, than with a 0.1uF capacitor.
At 12bit, the average should be around 2048 taking into account the resistors variation. Except for the 100K divider without capacitors, all configurations are quite good I think. It is worth noting that the best result is 10K without capacitor.

No, the best result is 10k with capacitor (slightly higher variation, but a more accurate mean).
 
I have a question similar to the OP's, but it's not very complicated, though I have no clue what it is i'm possibly doing wrong.

It involves the teensy 3.0, using the 'tutorial' parts kit from PJRC, and the stock temperature code in the 4th tutorial. The issue i'm coming across is when following the tutorial, the temperature is flat out wrong. After creating the voltage divider with the thermister and 10k resistor, I verified the divider voltage was correct using a DMM (~2.5vdc), and changing the temperature indeed caused a voltage change, so i'm fairly certain it's not a wiring issue. Though i'm also certain that the room isn't 119 degrees Fahrenheit either. heh.. Touching the thermister increases the temperature, and applying ice makes it drop.. So it does work. It's just not correct.

While i'm aware that the tutorials were written for the AVR based teensy's. Is there something about the 32bit ARM version that could be causing this?

I've tried 5 or 6 different analog pins, with the same result on each.


**edit** after staring at it for a while.. I think I realized what the problem is.. the 2.0's used a 5v Vref while the 3.0 uses 3.3v Which was causing the resulting output to be skewed way high when reading identical voltages. I need to either change the formula in the code to celsius = 25 + (code - 776) / 11.3; or drive the voltage divider with 3.3v, instead of 5v, to make the temperature read properly using a teensy 3.0 right?
 
Last edited:
I need to either change the formula in the code to celsius = 25 + (code - 776) / 11.3; or drive the voltage divider with 3.3v, instead of 5v, to make the temperature read properly using a teensy 3.0 right?

Yes, exactly. The resistors should be connected to 3.3 volts, not 5 volts. The Teensy 3.0 board by default uses the 3.3 volts as its reference (the voltage that will give 100% reading), so if you connect the resistors to 3.3 volts, you should get the same reading as Teensy 2.0 gives with 5 volts. Even though the actual voltage at the pin is different, the result should scale properly and end up the same.

I've added an update to tutorial 4 to my to-do list.
 
Hello, im a newb to this forum, but I was just looking over this thread & I noticed in the setup image above there is no ground wire from GND of the μC to the (-) rail of the breadboard on the right side. This may explain the noise your observing, as this would allow floating voltages to creep into the measurements.

Please correct me if im wrong..
 
Hi Everyone,

This is my first post in the forums. I'm in the middle of building what will be a 10 channel CV to Midi converter, and I'm having a bit of trouble with the noise/jittery voltage issues at the Analogue input pins (as dealt with in earlier posts in this thread). When I was just doing one channel, and after putting a .1 uF capacitor between the input pin and ground (as described above), the single channel read became very smooth. Now that I've added a second channel, I'm getting some of the old noisy behavior, though it is not nearly as bad as it was with the first channel before I added the cap. Any ideas on how I could improve this and make both channels as smooth as the original one was?

This thread has been really helpful so far. Thanks for sharing your knowledge!

Here is a description of the circuit:

The voltage is coming from a eurorack module, so I have a simple circuit that uses a 1k trimpot to clamp the voltage down to just below 3.3v (from the original <5v). The left pin of the trimpot is connected to ground, the right pin is connected to positive volts from the 3.5 mm jack, and the wiper is connected to an analogue input on the teensy. The ground on the jack is connected to ground as well. There a .1uf cap between the analogue input and ground. I have two instances of this exact circuit: one that goes to A0 and one that goes to A3.

And here is the code:

Code:
/* USB MIDI AnalogControlChange Example

   You must select MIDI from the "Tools > USB Type" menu
   http://www.pjrc.com/teensy/td_midi.html

   This example code is in the public domain.
*/

#include <Bounce.h>

// the MIDI channel number to send messages
const int channel = 1;

// the MIDI continuous controller for each analog input
const int controllerA0 = 10; // 10 = pan position
//const int controllerA1 = 11; // 11 = volume/expression
const int controllerA2 = 91; // 91 = reverb level
//const int controllerA3 = 93; // 93 = chorus level

void setup() {
}

// store previously sent values, to detect changes
int previousA0 = -1;
//int previousA1 = -1;
int previousA2 = -1;
//int previousA3 = -1;

elapsedMillis msec = 0;

void loop() {
  // only check the analog inputs 50 times per second,
  // to prevent a flood of MIDI messages
  
analogReference(EXTERNAL); // because my input voltage was typically >1.2v
 analogReadResolution(10); // anything more seemed like overkill
 analogReadAveraging(4);
  if (msec >= 20) {
    msec = 0;
    int n0 = analogRead(A0) / 8;
   // int n1 = analogRead(A1) / 8;
    int n2 = analogRead(A2) / 8;
    //int n3 = analogRead(A3) / 8;
    // only transmit MIDI messages if analog input changed
    if (n0 != previousA0) {
      usbMIDI.sendControlChange(controllerA0, n0, channel);
      previousA0 = n0;
    }
    //if (n1 != previousA1) {
     // usbMIDI.sendControlChange(controllerA1, n1, channel);
     // previousA1 = n1;
  //  }
    if (n2 != previousA2) {
     usbMIDI.sendControlChange(controllerA2, n2, channel);
      previousA2 = n2;
   }
   // if (n3 != previousA3) {
     // usbMIDI.sendControlChange(controllerA3, n3, channel);
      //previousA3 = n3;
   // }
  }

  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
  while (usbMIDI.read()) {
    // ignore incoming messages
  }
}
 
Status
Not open for further replies.
Back
Top