Skip to content

Instantly share code, notes, and snippets.

@meditans
Created May 18, 2016 00:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save meditans/60719c92afcc0637a048a46d221d0bde to your computer and use it in GitHub Desktop.
Save meditans/60719c92afcc0637a048a46d221d0bde to your computer and use it in GitHub Desktop.
// Oscilloscope
// Input defined by ANALOG_IN
// SIG_OUT true puts a 2kHz wave on DIGITAL_OUT for testing.

#define ANALOG_IN 0
#define DIGITAL_OUT 13
bool SIG_OUT = true;

void setup() {
  Serial.begin(9600);
  //Serial.begin(115200);
  
  // Generate a signal to examine (testing)
  if(SIG_OUT){
    pinMode(DIGITAL_OUT, OUTPUT);
    
    // initialize timer1 
    noInterrupts();           // disable all interrupts
    TCCR1A = 0;  // Primo setting del timer1
    TCCR1B = 0;  // Secondo setting del timer1
    TCNT1  = 0;
  
    // OCR1A = 31250;            // compare match register 16MHz/256/2Hz
    OCR1A = 1599; // compare match register to get 10 MHz with no prescaler
    TCCR1B |= (1 << WGM12);   // CTC mode
    // TCCR1B |= (1 << CS12);    // 256 prescaler 
    TCCR1B |= (1 << CS10);    // no prescaler
    TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
    interrupts();             // enable all interrupts
  }
}

// Interrupt based
ISR(TIMER1_COMPA_vect){
  digitalWrite(DIGITAL_OUT, digitalRead(DIGITAL_OUT) ^ 1);   // Toggle
}

void loop() {
  int val = analogRead(ANALOG_IN);
  Serial.write( 0xff );
  Serial.write( (val >> 8) & 0xff );
  Serial.write( val & 0xff );
}

Infine, i file di processing, sempre dal sito precedente.

// * ------------------ HOT KEYS ------------------
final char T_UP       = 'w'; // Translate waveform up
final char T_DOWN     = 's'; //                    down
final char T_LEFT     = 'a'; //                    left
final char T_RIGHT    = 'd'; //                    right
final char Z_IN       = 'c'; // Horizontal zoom in
final char Z_OUT      = 'z'; //                 out
final char S_IN       = 'e'; // Vertical scale in
final char S_OUT      = 'q'; //                out
final char MGL_UP     = 'r'; // Minor grid lines increase
final char MGL_DOWN   = 'f'; //                  decrease
final char TOG_PAUSE  = 'p'; // Toggle pause (unpause resets waveform)
final char RESET_AXIS = ' '; // Reset axis settings
final char MEAS_TIME  = 'x'; // Adds and/or highlights vertical bars (time measurement)
final char BAR_LEFT   = ','; // Move highlighted vertical bar left (can also mouse click)
final char BAR_RIGHT  = '.'; //                               right
// * ----------------------------------------------

// * --------------- STARTING STATE ---------------
float zoom    = 1.0;
float scale   = 0.5;
int centerV   = 0;
int centerH   = 0;
int gridLines = 0;
int com_port  = 0;   // Index number in Serial.list
// * ----------------------------------------------

// Global vars
import processing.serial.*;
Serial port;                    // Create object from Serial class
int val;                        // Data received from the serial port
long valTime;                   // Time data was received
int[] values;
long[] times;
float voltage;
float measTime = 0;
int   timeMode = 0;
int[] timeBars = {0, 0};
PFont f;
boolean pause;

// Setup
void setup() {
  size(1280, 480);
  port = new Serial(this, Serial.list()[com_port], 9600);    // Com port specified here
  values = new int[width];
  times = new long[width];
  timeBars[0] = width/3;
  timeBars[1] = 2*width/3;
  pause = false;
  smooth();
  f = createFont("Arial", 16, true);
}

// Read value from serial stream
int getValue() {
  int value = -1;
  while (port.available () >= 3) {
    if (port.read() == 0xff) {
      value = (port.read() << 8) | (port.read());
    }
  }
  return value;
}

// Get a y-value for the datapoint, varies based on axis settings
int getY(int val) {
  return (int)(height/2 -(val-512+centerV)*scale / 1023.0f * (height - 1));
}

// Push the values in the data array
void pushValue(int value) {
  for (int i=0; i<width-1; i++)
    values[i] = values[i+1];
  values[width-1] = value;
}

// Push the timestamps in the time array
void pushTime(long time) {
  for (int i=0; i<width-1; i++)
    times[i] = times[i+1];
  times[width-1] = time;
}

// Draw waveform
void drawLines() {
  int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
  stroke(255,255,0);
  for (int i=0; i<width; i++) {
    x1 = round(width - ((width-i) * zoom) + centerH);
    y1 = getY(values[i]);
    if(i > 1)
      line(x0, y0, x1, y1);
    x0 = x1;
    y0 = y1;
  }
}

// Draw gridlines (bounds, minor)
void drawGrid() {
  // Get scaled values for bounds
  int pFive = getY(1023);
  int zero  = getY(0);

  // Draw voltage bounds
  stroke(255, 0, 0);
  line(0, pFive-1, width, pFive-1);
  line(0, zero+1, width, zero+1);

  // Add voltage bound text
  textFont(f, 10);
  fill(255, 0, 0);
  text("+5V", 5, pFive+12);
  text(" 0V", 5, zero-4);

  // Draw minor grid lines
  int gridVal = 0;
  stroke(75, 75, 75);
  for (int i = 0; i < gridLines; i++) {
    gridVal = getY(round((i+1.0)*(1023.0 / (gridLines+1.0))));
    line(0, gridVal, width, gridVal);
  }

  // Add minor grid line text
  if (gridLines > 0) {
    textFont(f, 16);
    fill(204, 102, 0);
    float scaleVal = truncate(5.0f / (gridLines+1), 3);
    text("Grid: " + scaleVal + "V", 1170, height-12);
  }
  
  // Print difference between vertical 'time' bars
  if (timeMode > 0) {
    textFont(f, 16);
    fill(204, 102, 0);
    
    int idx0 = round(width + (timeBars[0] - width - centerH)/zoom);
    int idx1 = round(width + (timeBars[1] - width - centerH)/zoom);
    
    // Ensure time bars are over a recorded portion of the waveform
    if(idx1 < 0 || idx0 < 0 || idx1 > (width-1) || idx0 > (width-1) || times[idx1] == 0 || times[idx0] == 0)
      text("Time: N/A", 30, height-12);
    else{
      float timeDiff = truncate((times[idx1] - times[idx0])/2000000.0,2);
      text("Time: " + timeDiff + "ms", 30, height-12);
    }
  }
}

// Draw vertical 'time bars' (seperate from above for better layering)
void drawVertLines(){
  stroke(75, 75, 75);
  if (timeMode == 1) {
    line(timeBars[1], 0, timeBars[1], height);
    stroke(100, 100, 255);
    line(timeBars[0], 0, timeBars[0], height);
  }
  else if (timeMode == 2) {
    line(timeBars[0], 0, timeBars[0], height);
    stroke(100, 255, 100);
    line(timeBars[1], 0, timeBars[1], height);
  }
}

// Truncate a floating point number
float truncate(float x, int digits) {
  float temp = pow(10.0, digits);
  return round( x * temp ) / temp;
}

// When a key is pressed down or held...
void keyPressed() {
  switch (key) {
  case T_UP: centerV += 10/scale; break;                     // Move waveform up
  case T_DOWN: centerV -= 10/scale; break;                   // Move waveform down
  case T_RIGHT: centerH += 10/scale; break;                  // Move waveform right
  case T_LEFT: centerH -= 10/scale; break;                   // Move waveform left
  case MGL_UP:                                               // Increase minor grid lines
    if (gridLines < 49)
      gridLines += 1;
    break;
  case MGL_DOWN:                                             // Decrease minor grid lines
    if (gridLines > 0)
      gridLines -= 1;
    break;
  case BAR_LEFT:                                             // Move the time bar left (also mouse click)
    if (timeMode == 1 && timeBars[0] > 0)
      timeBars[0] -= 1;
    else if (timeMode == 2 && timeBars[1] > 0)
      timeBars[1] -= 1; 
    break;
  case BAR_RIGHT:                                            // Move the time bar right (also mouse click)
    if (timeMode == 1 && timeBars[0] < width-1)
      timeBars[0] += 1;
    else if (timeMode == 2 && timeBars[1] < width-1)
      timeBars[1] += 1; 
    break;
  }
}

// When a key is released...
void keyReleased() {
  println(key+": "+(int)key);
  switch (key) {
  case Z_IN:                                                 // Zoom horizontal
    zoom *= 2.0f;
    if ( (int) (width / zoom) <= 1 )
      zoom /= 2.0f;
    break;
  case Z_OUT:                                                // Zoom horizontal
    zoom /= 2.0f;
    if (zoom < 1.0f)
      zoom *= 2.0f;
    break;
  case S_IN: scale*=2; break;                                // Scale vertical
  case S_OUT: scale /= 2; break;                             // Scale vertical
  case RESET_AXIS:                                           // Reset all scaling
    centerV = 0; centerH = 0;
    scale = 0.5; zoom  = 1; gridLines = 0;
    break;
  case MEAS_TIME: timeMode = (timeMode + 1) % 3; break;      // Change the vertical bars (off, left bar, right bar)
  case TOG_PAUSE:                                            // Toggle waveform pausing
    if (pause) {
      centerH = 0;
      for (int i=0; i<width; i++){
        values[i] = 0;                                       // Clear data on resume
        times[i] = 0;
      }
    }
    pause = !pause;
  }
}

// Use mouse clicks to quickly move vertical bars (if highlighted)
void mousePressed() {
  if(timeMode == 1)
    timeBars[0] = mouseX;
  else if(timeMode == 2)
    timeBars[1] = mouseX;
}

// Primary drawing function
void draw()
{
  background(0);
  drawGrid();
  // Get current voltage, time of reading
  val = getValue();
  valTime = System.nanoTime();
  
  // If not paused
  if (!pause && val != -1) {
    // Push value/time onto array
    pushValue(val);
    pushTime(valTime);
    
    // Print current voltage reading
    textFont(f, 16);
    fill(204, 102, 0);
    voltage = truncate(5.0*val / 1023, 1);
    text("Voltage: " + voltage + "V", 1170, 30);
  }
  drawLines();
  drawVertLines();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment