I'm tried this on a couple of nanos, and get varying ADCs, shown in the attached images
I'm trying to read from the ADC which is jumpered direct to ground (so should always read 0v or extremely close to it), but the values keep varying. The following show the serial port output from the ADC on Pin 2, which is not stable, and drops as it is read, and in the case of the 9600 serial the ADC reading never drops below 180 = 0.87V. I get similiar issues with non-buffered reads, with delays, and it's even worse if I attempt to probe a +ve voltage (rather than just sampling from ground) - the reading never approaches anywhere near the true voltage. I also tried with a pulldown resistor from probe to ground but it didn't really help.
Can anyone help me - is it my code, my hardware, or both
Originally the code was taken from one of the poor-man's oscilloscope variants and heavily modified by me to improve display and features, but even the original showed the same behaviour. I've included both arduino and processing code (in the next post as it otherwise exceeds maximum size) as they go together. (NB the time along the bottom isn't accurately aligned with the signal.
Sampling rate is approx 220us/sample(=1 pixel width) and the red vertical lines are pauses in sampling for the upload to the pc.
// The Arduino code.
#define ANALOG_IN 23 // A1
//#define BUFFER_SIZE 800
//int valArr[BUFFER_SIZE];
#define BUFFER_SIZE 400
int valArr[BUFFER_SIZE][2];
void setup() {
// initialize serial communication:
// Serial.begin(9600); // use the slowest feasible speed if reading ADC and sending syncroniously
Serial.begin(115200); // use the slowest feasible speed if reading ADC and sending syncroniously
Serial.println("/ **** SCRIPT: oscilloscopeZoomable **** /");
Serial.println(TCCR0B);
// initialize the button pin as a input:
pinMode(ANALOG_IN, INPUT);
//**** TIMER INITIALIZATION **** /
//Serial.println("initialize Timer1");
noInterrupts(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0 - the Timer/Counter Control Registers- hold setup values. They will be 0, 1, or 2 depending on the timer being addresed
TCCR1B = 0; // same for TCCR1B
//For 16MHz:
//Prescale Time per counter tick Max Period
//Bit CS10 CS11 CS12 per tick max duration
// 0 0 0 0 No clock
// 1 0 0 1 1 0.0625uS 8.192 mS
// 2 0 1 0 8 0.5uS 65.536 mS
// 3 0 1 1 64 4uS 524.288 mS
// 4 1 0 0 256 16uS 2097.152 mS
// 5 1 0 1 1024 64uS 8388.608mS
//In general:
// Max Period = (Prescale)*(1/Frequency)*(2^17)
// Time per Tick = (Prescale)*(1/Frequency)
// Set CS10, CS11, CS12 bits for 8 prescaler:
//this will mean 2000 ticks/millisecond
// TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS11);
// TCCR1B |= (1 << CS12);
// enable global interrupts:
interrupts();
}
void loop() {
// asynchronous read/upload of data
// marker for start of asynchronous zone
valArr[0][1] = 1055;
//store each value in a buffer
TCNT1=0;
for (int i=1; i<BUFFER_SIZE; i++) {
valArr[i][0] = TCNT1;
// valArr[i][1] = digitalRead(ANALOG_IN);
valArr[i][1] = analogRead(ANALOG_IN);
//delay(10); // analogRead seems to use quite a bit of power, so get sag with repeated readings too close together
}
for (int i=0; i<BUFFER_SIZE; i++) {
Serial.write( 0xff ); // header to ensure high and low bit correctly ordered
Serial.write( (valArr[i][0] >> 8) & 0xff );
Serial.write( valArr[i][0] & 0xff );
Serial.write( (valArr[i][1] >> 8) & 0xff );
Serial.write( valArr[i][1] & 0xff );
}
delay(1);
}
void loop0() {
// syncronious read/upload of data
int val = digitalRead(ANALOG_IN);
// int val = analogRead(ANALOG_IN);
Serial.write( 0xff );
Serial.write( 0 );
Serial.write( 0 );
Serial.write( (val >> 8) & 0xff );
Serial.write( val & 0xff );
}
/*
* Oscilloscope
* Gives a visual rendering of analog pin 0 in realtime.
*
* This project is part of Accrochages
* See http://accrochages.drone.ws
*
* (c) 2008 Sofian Audry (info@sofianaudry.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import processing.serial.*;
// This needs to be set to the port your arduino is communicating on.
// a list of ports will be printed to the console when the script is initiated
short portIndex = 1; /* determines the USB port used */
Serial port; // Create object from Serial class
int val; // Data received from the serial port
int minVal=9999;
int maxVal=0;
int[][] values;
float hZoom = 1.0f;
float vZoom = 1.0f;
float vOffset = 0.0f;
float vOffsetStep = 40.0f; // do not set this to zero the steps won't work
float sampleRes = 1023.0f; // NB high and low bits are sent by the arduino but the ADC only has 10bit resolution
//int serialSpeed = 9600; // NB high and low bits are sent by the arduino but the ADC only has 10bit resolution
int serialSpeed = 115200; // NB high and low bits are sent by the arduino but the ADC only has 10bit resolution
int stepVal = 1;
int stepHgt = (480-10-10)/10;
boolean paused = false;
void setup()
{
// print a list of the serial ports:
println("Serial Ports available:");
printArray(Serial.list());
println("Keys: + or - to zoom horizontal, * or / to zoom vertical, 8 or 2 to move screen up or down");
size(1280, 480);
// Open the port that the board is connected to and use the same speed (9600 bps)
port = new Serial(this, Serial.list()[portIndex], serialSpeed);
values = new int[width][2];
smooth(); // this is default so not strictly necessary
// read the first few seconds of data and discard, as it's not stable
int m = millis();
while (m > millis()-4000) {
if (port.available() >= 1)
port.read();
}
}
int getY(int val) {
// print(val);
// print(" ");
// print(maxVal);
// print(" ");
// println(minVal);
// scale the value to match the screen size
// println((float)(val-minVal)/(maxVal-minVal));
// println((int)(height - (float)(val-minVal)/(maxVal-minVal) * (height - 1)*vZoom + vOffset -1));
// println(val / sampleRes);
return (int)(height - (float)(val-minVal)/(maxVal-minVal) * (height - 1)*vZoom + vOffset -1);
// scale the value to match the screen size
// return (int)(height - val / sampleRes * (height - 1)*vZoom + vOffset -1);
}
void drawLines() {
stroke(255); //Sets the color used to draw lines and borders around shapes
int displayWidth = (int) (width / hZoom);
int k = width - displayWidth;
// loop through the list of values and draw them
int x0 = 0;
int y0 = getY(values[k][1]);
for (int i=1; i<displayWidth; i++) {
k++;
if (values[k][1] > sampleRes) {
// draw a red line to mark the start of the buffer dump
stroke(255, 0, 0); // line colour red
int x3 = (int) (i * (width-1) / (displayWidth-1));
line(x3, 0, x3, height);
stroke(255); //Sets the color used to draw lines and borders around shapes
} else {
int x1 = (int) (i * (width-1) / (displayWidth-1));
int y1 = getY(values[k][1]);
line(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
}
}
// Place text for y axis
if (maxVal==1 & minVal==0) {
text("HIGH",0,15);
text("LOW",0,height-10);
} else {
stepVal = (maxVal - minVal)/10;
for (int i=0;i<11;i++) {
text((maxVal - i*stepVal) + "=" + (5*(maxVal - i*stepVal)/sampleRes) + "V",0,0+15+ i*stepHgt);
}
text(minVal + "=" + (5*minVal/sampleRes) + "V",100,height-10);
}
// NB not accurate if display zoomed
for (int i=1; i<displayWidth; i+=displayWidth/10) {
// Place text for the x axis
int x1 = (int) (i * (width-1) / (displayWidth-1));
int t1 = values[i][0];
text(t1 + "=" + (t1*0.5) + "us",i,480-20);
}
}
void drawGrid() {
stroke(255, 0, 0); // line colour red
line(0, height/2, width, height/2); // draw a line across the middle of the screen
}
void keyReleased() {
switch (key) {
case ' ':
if (paused) { noLoop(); }
else { loop(); }
paused = !paused;
break;
case '+':
hZoom *= 2.0f;
if ( (int) (width / hZoom) <= 1 )
hZoom /= 2.0f;
println(hZoom);
break;
case '-':
hZoom /= 2.0f;
if (hZoom < 1.0f)
hZoom *= 2.0f;
println(hZoom);
break;
case '*':
vZoom *= 2.0f;
if ( (int) (width / vZoom) <= 1 )
vZoom /= 2.0f;
println(vZoom);
break;
case '/':
vZoom /= 2.0f;
if (vZoom < 1.0f)
vZoom *= 2.0f;
println(vZoom);
break;
case '8':
vOffset += (vOffsetStep*vZoom);
println(vOffset);
break;
case '2':
vOffset -= (vOffsetStep*vZoom);
println(vOffset);
break;
}
}
void pushValue(int time, int value) {
for (int i=0; i<width-1; i++) {
values[i][0] = values[i+1][0];
values[i][1] = values[i+1][1];
}
values[width-1][0] = time;
values[width-1][1] = value;
}
void draw()
{
background(0);
drawGrid();
while (port.available() >= 5) {
int tim = 0;
int val = -1;
while (port.available() >= 5) {
if (port.read() == 0xff) {
tim = (port.read() << 8) | (port.read());
val = (port.read() << 8) | (port.read());
break;
}
}
// println(val);
if (val != -1) {
if (val <= sampleRes) {
if (maxVal < val) {
maxVal = val;
if (minVal >= maxVal) {minVal = maxVal -1;}
print(minVal); print(" "); println(maxVal);
}
if (minVal > val) {
minVal = val;
if (maxVal <= minVal) {maxVal = minVal +1;}
print(minVal); print(" "); println(maxVal);
}
} else {
println("bufferstart");
}
pushValue(tim,val);
}
}
drawLines();
}
Duh, obvious mistake, I was using a digital pin initially to test in my code, then switched to an analog pin but used the physical pin number, not the arduino number.