Go Down

Topic: Programming Signal Analyzer/ Oscilloscope (Read 307 times) previous topic - next topic

BLACKAVID

Oct 12, 2018, 03:20 pm Last Edit: Oct 12, 2018, 04:49 pm by BLACKAVID
Hey ho folks!
I'm completely new to Arduino and I could need help in programming an "Oscilloscopy-thing"

OK first: I'm electrical engineer and have no big programming skills, so I won't be able to write it on my own (I wouldn't ask for it).
I'm building a analog synthesizer right now and wanted to give a small "cherry" on top by adding kinda like an oscilloscope to it.

But nothing of the internets programm codes fits to the purpose.
To explain my problem:
I wanted to visualize the signal of the main output as a gimmick to the build. That means to show the scratched triangle, square, saw waves to have a imagination to the signals.
That means that the shown signal MUST be the same level and the same frequency (getting normalized) all the time when I'm playing the different notes. I don't know if this is possible to do without further hardware. I don't need to see any frequencies so the time-area is enough for that small purpose.

Another cool thing would be to have a start screen where it displays some seconds the name of the synth and then starting the signal analyzer.

I got a code that I found somewhere deep on the internet, but I can't find it again to write the developer. Maybe some of you geeky professionals (or semis :D) could rewrite/ improve the code to my needs. I would be so glad to show this on other community boards (rights to the developer).

As a refer I posting this link to a Dreadbox Medusa Synth. You can see that the screen on the right sometimes shows of the signal, no matter which note you're playing https://www.youtube.com/watch?v=kVF9_Mnes-o

Code: [Select]
#define FILENAME "TFTGraph3"
#include <TFT.h>  // Arduino LCD library
#include <SPI.h>

// pin definition for the Uno
#define cs   10
#define dc   9
#define rst  8
#define quiet false

TFT TFTscreen = TFT(cs, dc, rst);
byte h = TFTscreen.height();
byte w = TFTscreen.width();
byte b[160];
boolean f = false;
int dt; // microseconds

void setup() {
  Serial.begin(9600);
  Serial.println(FILENAME);
  Serial.println(w);
  Serial.println(h);
  ADCSRA = 132;   // set prescale to 16, see http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/
  // initialize the display
  TFTscreen.begin();
  for (int i = 0; i < w; i++) b[i] = -1; // avoid erasing on the first go
  // clear the screen with a pretty color
  clearScreen();
}

//==========================================================================00

void loop() {
  int a[160]; // "double buffering"
  const byte sensorPin = A0;
  long t1, t2;
  t1 = micros();
  // sampling:
  for (int i = 1; i < w-1; i++) {
    a[i] = analogRead(sensorPin);
    // delay if desired
  }
  t2 = micros();
  dt = t2 - t1;
  Serial.println(dt);
  // displaying:
  if (f) {
    for (int i = 1; i < w-1; i++) {
      TFTscreen.stroke(0, 0, 0); // erase old
      TFTscreen.point (i, b[i]);
      b[i] = map (a[i], 0, 1023, h-2, 1);
      // zero should be at the bottom, 5 volts at the top
      TFTscreen.stroke(255, 200, 0); // print new
      TFTscreen.point (i, b[i]);
    }
  }
  else {
    for (int i = 1; i < w-1; i++) {
      TFTscreen.stroke(0, 0, 0); // erase old
      TFTscreen.point (i, b[i]);
      b[i] = map (a[i], 0, 1023, h-2, 1);
      TFTscreen.stroke(255, 200, 0); // print new
      TFTscreen.point (i, b[i]);  
    }
  }
  f = !f;
  grid();
  // trigger:
  /* edge triggered: */
  int v1 = analogRead(sensorPin);
  int v2 = analogRead(sensorPin);
  // wait for rising edge:
  while (v2 - v1 < 2) {
    v1 = v2;
    v2 = analogRead(sensorPin);
  }
  // wait for falling edge
  while (v1 - v2 < 2) {
    v1 = v2;
    v2 = analogRead(sensorPin);
  }
  /* alternative use level triggering:
  while (analogRead(sensorPin) > 512);
  while (analogRead(sensorPin) < 512);
  /* */
}

void clearScreen() {
  TFTscreen.background(0, 0, 0);
  TFTscreen.stroke(255, 0, 0);
  TFTscreen.rect(0, 0, w, h);
}

void grid() { // dotted vertical lines
  // display the axes:
  TFTscreen.stroke(255, 0, 0); // red
  // horizontal lines:
  for (int i = 1; i < 5; i++) {
    int b = 6;
    int x = 3;
    while (x < w) {
      TFTscreen.line(x, i*h/5, x + b, i*h/5);
      x = x + 2 * b;
    }
  }
  // vertical  lins:
  long div = 500; // microseconds
  int dx = div * (w - 2) / dt;
  int x = 0;
  while (x < w) {
    int b = 6;
    x = x + dx;
    int y = 2;
    while (y < h)  {
      TFTscreen.line(x, y, x, y + b);
      y = y + 2 * b;
    }
  }  
  // print margins:
  byte h1 = 3*h/5;
  TFTscreen.stroke(0,0,0); // background color
  TFTscreen.fill(0,0,0);
  TFTscreen.rect(w-30,h1-8,29,7);
  /*TFTscreen.stroke(255,255,255); // white
  TFTscreen.text("0",    1, h1-8);
  TFTscreen.text("0.5 ms", w-36, h1-8);
  TFTscreen.text("/div",   w-24, h1+1);  
  TFTscreen.text("0V",   1,  h-8);
  TFTscreen.text("5V",   1,    1);*/  
}


P.S. Which board would be the most fitting for this project (reading speed, bit solution etc.). I don't know where they difference each other (chip is the same mostly)

Greetings Avid

jarnoldbrown

I think what you want is quite complicated.
Is the synth polyphonic or monophonic?
If it's polyphonic, I would say forget it.
Even if monophonic, the program will have to auto detect a single cycle of whatever waveform you are producing. You might be able to do this by looking for zero crossings, I guess it depends on the waveforms.
But to put this in perspective, I have a digtal scope that attaches to my PC, and it has an Auto mode. It sometimes works fairly well, and sometimes not so well. Takes a fair amount of time to lock as well.

As I said, it depends on how complex your waveforms will be. You might have to resort to some sort of self correlation to extract the frequency.

Once you have a complete cycle, the normalizing would be fairly simple.
Are you looking to pay for this? If so, PM me and we could discuss further.

John

Go Up