ADC varying value on repeated read (poor-man's oscilloscope)

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 );
}

Serial speed: 115200

Serial speed: 9600

  /*
 * 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();
}

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.

Use the ReadAnalogVoltage example that comes with the IDE to display raw ADC values. As you say, they should be 0.

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.

Seems to work OK now.