Osiloskop

OSİLOSKOP
Osiloskop nedir? Basitçe elektrik akımının ya da sinyalinin görünür hale gelmiş şekli denebilir kanaatimce.
Kullanılan Malzemeler: Arduino mega, 2.6 inç renkli tft ekran (spfd 5408), çeşitli kablolar.
Osiloskop yapmak için epey bir araştırma yaptıktan sonra çalışan bir osiloskop programı buldum. Tabiki 5V'a kadar gerilim ölçümü yapabilmektedir.



Arduino Yazılımı (Sketch):

/**
  This code is compiled by Vaupell ("Eqvaliser") search youtube.
  From
  Original Oscilloscope link :
  http://n.mtng.org/ele/arduino/oscillo-j.html
  Original TFT display link :
  http://www.smokeandwires.co.nz/blog/a-2-4-tft-touchscreen-shield-for-arduino/
  Original Library availible here :
  https://github.com/Smoke-And-Wires/TFT-Shield-Example-Code
  EDIT “SWTFT.cpp” to change model.
  #include “mega_24_shield.h” if you are using a mega
  or
  #include “uno_24_shield.h”
**/
// MEGA SETUP!!!
#include <SPFD5408_Adafruit_GFX.h>    // Core graphics library
#include <SPFD5408_Adafruit_TFTLCD.h> // Hardware-specific library
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
// optional
#define LCD_RESET A4
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
int pwmSignal1 = 22;
int pwmSignal2 = 23;
//SWTFT tft;
// If using the shield, all control and data lines are fixed, and
// a simpler declaration can optionally be used:
// SWTFT tft;
#define txtLINE0   0
#define txtLINE1   16
#define txtLINE2   30
#define txtLINE3   46
const int LCD_WIDTH = 320;
const int LCD_HEIGHT = 240;
const int SAMPLES = 270;
const int DOTS_DIV = 30;
const int ad_sw = 3;                    // Analog 3 pin for switches
const int ad_ch0 = A10;                   // Analog 4 pin for channel 0
const int ad_ch1 = A11;                   // Analog 5 pin for channel 1
const unsigned long VREF[] = {150, 300, 750, 1500, 3000}; // reference voltage 5.0V ->  150 :   1V/div range (100mV/dot)
// It means 5.0 * DOTS_DIV = 150. Use 4.9 if reference voltage is 4.9[V]
//                        -> 300 : 0.5V/div
//                        -> 750 : 0.2V/div
//                        ->1500 : 100mV/div
//                       -> 3000 :  50mV/div
const int MILLIVOL_per_dot[] = {33, 17, 6, 3, 2}; // mV/dot
const int MODE_ON = 0;
const int MODE_INV = 1;
const int MODE_OFF = 2;
const char *Modes[] = {"NORM", "INV", "OFF"};
const int TRIG_AUTO = 0;
const int TRIG_NORM = 1;
const int TRIG_SCAN = 2;
const int TRIG_ONE  = 3;
const char *TRIG_Modes[] = {"Auto", "Norm", "Scan", "One"};
const int TRIG_E_UP = 0;
const int TRIG_E_DN = 1;
#define RATE_MIN 0
#define RATE_MAX 13
const char *Rates[] = {"F1-1", "F1-2 ", "F2  ", "5ms", "10ms", "20ms", "50ms", "0.1s", "0.2s", "0.5s", "1s", "2s", "5s", "10s"};
#define RANGE_MIN 0
#define RANGE_MAX 4
const char *Ranges[] = {" 1V ", "0.5V", "0.2V", "0.1V", "50mV"};
unsigned long startMillis;
byte data[4][SAMPLES];                   // keep twice of the number of channels to make it a double buffer
byte sample = 0;                         // index for double buffer
///////////////////////////////////////////////////////////////////////////////////////////////
// Define colors here
#define BGCOLOR  BLACK
#define GRIDCOLOR WHITE
#define CH1COLOR  BLUE
#define CH2COLOR  YELLOW
// Declare variables and set defaults here
// Note: only ch1 is available with Aitendo's parallel 320x240 TFT LCD
byte range0 = RANGE_MIN, ch0_mode = MODE_ON;  // CH0
short ch0_off = 204;
byte range1 = RANGE_MIN, ch1_mode = MODE_ON;  // CH1
short ch1_off = 204;
byte rate = 3;                                // sampling rate
byte trig_mode = TRIG_AUTO, trig_lv = 30, trig_edge = TRIG_E_UP, trig_ch = 1; // trigger settings
byte Start = 1;  // Start sampling
byte menu = 0;  // Default menu
///////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  pinMode(pwmSignal1, OUTPUT);
  analogWrite(pwmSignal1, 150);
  pinMode(pwmSignal2, OUTPUT);
  analogWrite(pwmSignal2, 25);
  tft.reset();
  uint16_t identifier = tft.readID();
  tft.begin(identifier);
  tft.setRotation(3);
  tft.fillScreen(BGCOLOR);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.setCursor(5, 60);
  tft.print("Arduino Osiloskop");
  tft.setCursor(5, 90);
  tft.print("spfd5408 TFT LCD (320x240)");
  tft.setCursor(5, 120);
  tft.print("2015-2017(c)");
  tft.setCursor(5, 150);
  tft.print("Aytekin TUZLALI, Aug, 2017");
  delay(4000);
  tft.fillScreen(BGCOLOR);
  Serial.begin(9600);
  DrawGrid();
  DrawText();
}
void CheckSW() {
  static unsigned short oain[2];
  static unsigned long Millis = 0, oMillis = 0;
  unsigned long ms;
  unsigned short ain = analogRead(ad_sw);
  return;
  ms = millis();
  if ((ms - Millis) < 5)
    return;
  Millis = ms;
  if (!(abs(oain[0] - oain[1]) > 10 && abs(oain[1] - ain) < 2)) {
    oain[0] = oain[1];
    oain[1] = ain;
    return;
  }
  oain[0] = oain[1];
  oain[1] = ain;
  if (ain > 950 || (Millis - oMillis) < 200)
    return;
  oMillis = Millis;
  // Serial.println(ain);
  int sw;
  for (sw = 0; sw < 10; sw ++) {
    const int sw_lv[] = {889, 800, 700, 611, 514, 419, 338, 231, 132, 70};
    if (ain > sw_lv[sw])
      break;
  }
  // Serial.println(sw);
  switch (menu) {
    case 0:
    default:
      menu0_sw(sw);
      break;
    case 1:
      menu1_sw(sw);
      break;
    case 2:
      menu2_sw(sw);
      break;
  }
  DrawText();
}
void menu0_sw(int sw) {
  switch (sw) {
    case 0:
      // START/HOLD
      if (Start)
        Start = 0;
      else
        Start = 1;
      break;
    case 1:
      // CH0 RANGE -
      if (range0 < RANGE_MAX)
        range0 ++;
      break;
    case 2:
      // CH1 RANGE -
      if (range1 < RANGE_MAX)
        range1 ++;
      break;
    case 3:
      // RATE FAST
      if (rate > 0)
        rate --;
      break;
    case 4:
      // TRIG MODE
      if (trig_mode < TRIG_ONE)
        trig_mode ++;
      else
        trig_mode = 0;
      break;
    case 5:
      // SEND
      SendData();
      break;
    case 6:
      // TRIG MODE
      if (trig_mode > 0)
        trig_mode --;
      else
        trig_mode = TRIG_ONE;
      break;
    case 7:
      // RATE SLOW
      if (rate < RATE_MAX)
        rate ++;
      break;
    case 8:
      // CH1 RANGE +
      if (range1 > 0)
        range1 --;
      break;
    case 9:
      // CH0 RANGE +
      if (range0 > 0)
        range0 --;
      break;
    case 10:
    default:
      // MENU SW
      menu ++;
      break;
  }
}
void menu1_sw(int sw) {
  switch (sw) {
    case 0:
      // START/HOLD
      if (Start)
        Start = 0;
      else
        Start = 1;
      break;
    case 1:
      // CH0 offset +
      if (ch0_off < 1023)
        ch0_off += 1024 / VREF[range0];
      break;
    case 2:
      // CH1 offset +
      if (ch1_off < 1023)
        ch1_off += 1024 / VREF[range1];
      break;
    case 3:
      // trigger level +
      if (trig_lv < 60)
        trig_lv ++;
      break;
    case 4:
    case 6:
      // TRIG EDGE
      if (trig_edge == TRIG_E_UP)
        trig_edge = TRIG_E_DN;
      else
        trig_edge = TRIG_E_UP;
      break;
    case 5:
      // SEND
      SendData();
      break;
    case 7:
      // trigger level -
      if (trig_lv > 0)
        trig_lv --;
      break;
    case 8:
      // CH1 OFF -
      if (ch1_off > -1023)
        ch1_off -= 1024 / VREF[range1];
      break;
    case 9:
      // CH0 OFF -
      if (ch0_off > -1023)
        ch0_off -= 1024 / VREF[range0];
      break;
    case 10:
    default:
      // MENU SW
      menu ++;
      break;
  }
}
void menu2_sw(int sw) {
  switch (sw) {
    case 0:
      // START/HOLD
      if (Start)
        Start = 0;
      else
        Start = 1;
      break;
    case 1:
      if (ch0_mode < 2)
        ch0_mode ++;
      break;
    case 2:
      if (ch1_mode < 2)
        ch1_mode ++;
      break;
    case 3:
    case 7:
      // TRIG channel
      if (trig_ch == 0)
        trig_ch = 1;
      else
        trig_ch = 0;
      break;
    case 5:
      // SEND
      SendData();
      break;
    case 8:
      if (ch1_mode > 0)
        ch1_mode --;
      break;
    case 9:
      if (ch0_mode > 0)
        ch0_mode --;
      break;
    case 10:
      // MENU SW
      menu = 0;
      break;
    case 4:
    case 6:
    default:
      // none
      break;
  }
}
void SendData() {
  Serial.print(Rates[rate]);
  Serial.println("/div (30 samples)");
  for (int i = 0; i < SAMPLES; i ++) {
    Serial.print(data[sample + 0][i]*MILLIVOL_per_dot[range0]);
    Serial.print(" ");
    Serial.println(data[sample + 1][i]*MILLIVOL_per_dot[range1]);
  }
}
void DrawGrid() {
  for (int x = 0; x <= SAMPLES; x += 2) { // Horizontal Line
    for (int y = 0; y <= LCD_HEIGHT; y += DOTS_DIV) {
      tft.drawPixel(x, y, GRIDCOLOR);
      CheckSW();
    }
    if (LCD_HEIGHT == 240)
      tft.drawPixel(x, LCD_HEIGHT - 1, GRIDCOLOR);
  }
  for (int x = 0; x <= SAMPLES; x += DOTS_DIV ) { // Vertical Line
    for (int y = 0; y <= LCD_HEIGHT; y += 2) {
      tft.drawPixel(x, y, GRIDCOLOR);
      CheckSW();
    }
  }
}
void DrawText() {
  tft.setTextColor(WHITE);
  tft.setTextSize(1);
  tft.setCursor(SAMPLES - 3, 20);
  tft.print(Ranges[range1]);
  tft.println("/DIV");
  tft.setCursor(SAMPLES + 3, 30);
  tft.print(Rates[rate]);
  tft.println("/DIV");
  tft.setCursor(SAMPLES + 3, 40);
  tft.println(TRIG_Modes[trig_mode]);
  tft.setCursor(SAMPLES + 3, 50);
  tft.println(trig_edge == TRIG_E_UP ? "UP" : "DN");
  tft.setCursor(SAMPLES + 3, 60);
  tft.println(Modes[ch1_mode]);
  //  tft.setCursor(SAMPLES, 70);
  //  tft.println(trig_ch == 0 ? "T:1" : "T:2");
#if 0
  GLCD.FillRect(101, txtLINE0, 28, 64, WHITE); // clear text area that will be drawn below
  switch (menu) {
    case 0:
      GLCD.GotoXY(SAMPLES + 1, txtLINE0);        // locate curser for printing text
      GLCD.Puts(Ranges[range0]);
      GLCD.GotoXY(SAMPLES + 1, txtLINE1);        // locate curser for printing text
      GLCD.Puts(Ranges[range1]);
      GLCD.GotoXY(SAMPLES + 1, txtLINE2);        // locate curser for printing text
      GLCD.Puts(Rates[rate]);
      GLCD.GotoXY(SAMPLES + 1, txtLINE3);        // locate curser for printing text
      GLCD.Puts(TRIG_Modes[trig_mode]);
      break;
    case 1:
      GLCD.GotoXY(SAMPLES + 1, txtLINE0);        // locate curser for printing text
      GLCD.Puts("OF1");
      GLCD.GotoXY(SAMPLES + 1, txtLINE1);        // locate curser for printing text
      GLCD.Puts("OF2");
      GLCD.GotoXY(SAMPLES + 1, txtLINE2);        // locate curser for printing text
      GLCD.Puts("Tlv");
      GLCD.GotoXY(SAMPLES + 1, txtLINE3);        // locate curser for printing text
      GLCD.Puts(trig_edge == TRIG_E_UP ? "UP" : "DN");
      break;
    case 2:
      GLCD.GotoXY(SAMPLES + 1, txtLINE0);        // locate curser for printing text
      GLCD.Puts(Modes[ch0_mode]);
      GLCD.GotoXY(SAMPLES + 1, txtLINE1);        // locate curser for printing text
      GLCD.Puts(Modes[ch1_mode]);
      GLCD.GotoXY(SAMPLES + 1, txtLINE2);        // locate curser for printing text
      GLCD.Puts(trig_ch == 0 ? "T:1" : "T:2");
      break;
  }
#endif
}
void DrawGrid(int x) {
  if ((x % 2) == 0)
    for (int y = 0; y <= LCD_HEIGHT; y += DOTS_DIV)
      tft.drawPixel(x, y, GRIDCOLOR);
  if ((x % DOTS_DIV) == 0)
    for (int y = 0; y <= LCD_HEIGHT; y += 2)
      tft.drawPixel(x, y, GRIDCOLOR);
}
void ClearAndDrawGraph() {
  int clear = 0;
  if (sample == 0)
    clear = 2;
#if 0
  for (int x = 0; x < SAMPLES; x++) {
    GLCD.SetDot(x, LCD_HEIGHT - data[clear + 0][x], WHITE);
    GLCD.SetDot(x, LCD_HEIGHT - data[clear + 1][x], WHITE);
    GLCD.SetDot(x, LCD_HEIGHT - data[sample + 0][x], BLACK);
    GLCD.SetDot(x, LCD_HEIGHT - data[sample + 1][x], BLACK);
  }
#else
  for (int x = 0; x < (SAMPLES - 1); x++) {
    tft.drawLine(x, LCD_HEIGHT - data[clear + 0][x], x + 1, LCD_HEIGHT - data[clear + 0][x + 1], BGCOLOR);
    tft.drawLine(x, LCD_HEIGHT - data[clear + 1][x], x + 1, LCD_HEIGHT - data[clear + 1][x + 1], BGCOLOR);
    if (ch0_mode != MODE_OFF)
      tft.drawLine(x, LCD_HEIGHT - data[sample + 0][x], x + 1, LCD_HEIGHT - data[sample + 0][x + 1], CH1COLOR);
    if (ch1_mode != MODE_OFF)
      tft.drawLine(x, LCD_HEIGHT - data[sample + 1][x], x + 1, LCD_HEIGHT - data[sample + 1][x + 1], CH2COLOR);
    CheckSW();
  }
#endif
}
void ClearAndDrawDot(int i) {
  int clear = 0;
  if (i <= 1)
    return;
  if (sample == 0)
    clear = 2;
#if 0
  for (int x = 0; x < SAMPLES; x++) {
    GLCD.SetDot(x, LCD_HEIGHT - data[clear + 0][x], WHITE);
    GLCD.SetDot(x, LCD_HEIGHT - data[clear + 1][x], WHITE);
    GLCD.SetDot(x, LCD_HEIGHT - data[sample + 0][x], BLACK);
    GLCD.SetDot(x, LCD_HEIGHT - data[sample + 1][x], BLACK);
  }
#else
  tft.drawLine(i - 1, LCD_HEIGHT - data[clear + 0][i - 1], i, LCD_HEIGHT - data[clear + 0][i], BGCOLOR);
  tft.drawLine(i - 1, LCD_HEIGHT - data[clear + 1][i - 1], i, LCD_HEIGHT - data[clear + 1][i], BGCOLOR);
  if (ch0_mode != MODE_OFF)
    tft.drawLine(i - 1, LCD_HEIGHT - data[sample + 0][i - 1], i, LCD_HEIGHT - data[sample + 0][i], CH1COLOR);
  if (ch1_mode != MODE_OFF)
    tft.drawLine(i - 1, LCD_HEIGHT - data[sample + 1][i - 1], i, LCD_HEIGHT - data[sample + 1][i], CH2COLOR);
#endif
  DrawGrid(i);
}
void DrawGraph() {
  for (int x = 0; x < SAMPLES; x++) {
    tft.drawPixel(x, LCD_HEIGHT - data[sample + 0][x], CH1COLOR);
    tft.drawPixel(x, LCD_HEIGHT - data[sample + 1][x], CH2COLOR);
  }
}
void ClearGraph() {
  int clear = 0;
  if (sample == 0)
    clear = 2;
  for (int x = 0; x < SAMPLES; x++) {
    tft.drawPixel(x, LCD_HEIGHT - data[clear + 0][x], BGCOLOR);
    tft.drawPixel(x, LCD_HEIGHT - data[clear + 1][x], BGCOLOR);
  }
}
inline unsigned long adRead(byte ch, byte mode, int off)
{
  unsigned long a = analogRead(ch);
  a = ((a + off) * VREF[ch == ad_ch0 ? range0 : range1] + 512) >> 10;
  a = a >= (LCD_HEIGHT + 1) ? LCD_HEIGHT : a;
  if (mode == MODE_INV)
    return LCD_HEIGHT - a;
  return a;
}
void  loop() {
  if (trig_mode != TRIG_SCAN) {
    unsigned long st = millis();
    byte oad;
    if (trig_ch == 0)
      oad = adRead(ad_ch0, ch0_mode, ch0_off);
    else
      oad = adRead(ad_ch1, ch1_mode, ch1_off);
    for (;;) {
      byte ad;
      if (trig_ch == 0)
        ad = adRead(ad_ch0, ch0_mode, ch0_off);
      else
        ad = adRead(ad_ch1, ch1_mode, ch1_off);
      if (trig_edge == TRIG_E_UP) {
        if (ad >= trig_lv && ad > oad)
          break;
      } else {
        if (ad <= trig_lv && ad < oad)
          break;
      }
      oad = ad;
      CheckSW();
      if (trig_mode == TRIG_SCAN)
        break;
      if (trig_mode == TRIG_AUTO && (millis() - st) > 100)
        break;
    }
  }
  // sample and draw depending on the sampling rate
  if (rate <= 5 && Start) {
    // change the index for the double buffer
    if (sample == 0)
      sample = 2;
    else
      sample = 0;
    if (rate == 0) { // full speed, channel 0 only
      unsigned long st = millis();
      for (int i = 0; i < SAMPLES; i ++) {
        data[sample + 0][i] = adRead(ad_ch0, ch0_mode, ch0_off);
      }
      for (int i = 0; i < SAMPLES; i ++)
        data[sample + 1][i] = 0;
      // Serial.println(millis()-st);
    } else if (rate == 1) { // full speed, channel 1 only
      unsigned long st = millis();
      for (int i = 0; i < SAMPLES; i ++) {
        data[sample + 1][i] = adRead(ad_ch1, ch1_mode, ch1_off);
      }
      for (int i = 0; i < SAMPLES; i ++)
        data[sample + 0][i] = 0;
      // Serial.println(millis()-st);
    } else if (rate == 2) { // full speed, dual channel
      unsigned long st = millis();
      for (int i = 0; i < SAMPLES; i ++) {
        data[sample + 0][i] = adRead(ad_ch0, ch0_mode, ch0_off);
        data[sample + 1][i] = adRead(ad_ch1, ch1_mode, ch1_off);
      }
      // Serial.println(millis()-st);
    } else if (rate >= 3 && rate <= 5) { // .5ms, 1ms or 2ms sampling
      const unsigned long r_[] = {5000 / DOTS_DIV, 10000 / DOTS_DIV, 20000 / DOTS_DIV};
      unsigned long st0 = millis();
      unsigned long st = micros();
      unsigned long r = r_[rate - 3];
      for (int i = 0; i < SAMPLES; i ++) {
        while ((st - micros()) < r) ;
        st += r;
        data[sample + 0][i] = adRead(ad_ch0, ch0_mode, ch0_off);
        data[sample + 1][i] = adRead(ad_ch1, ch1_mode, ch1_off);
      }
      // Serial.println(millis()-st0);
    }
    ClearAndDrawGraph();
    CheckSW();
    DrawGrid();
    DrawText();
  } else if (Start) { // 5ms - 500ms sampling
    // copy currently showing data to another
    if (sample == 0) {
      for (int i = 0; i < SAMPLES; i ++) {
        data[2][i] = data[0][i];
        data[3][i] = data[1][i];
      }
    } else {
      for (int i = 0; i < SAMPLES; i ++) {
        data[0][i] = data[2][i];
        data[1][i] = data[3][i];
      }
    }
    const unsigned long r_[] = {50000 / DOTS_DIV, 100000 / DOTS_DIV, 200000 / DOTS_DIV,
                                500000 / DOTS_DIV, 1000000 / DOTS_DIV, 2000000 / DOTS_DIV,
                                5000000 / DOTS_DIV, 10000000 / DOTS_DIV
                               };
    unsigned long st0 = millis();
    unsigned long st = micros();
    for (int i = 0; i < SAMPLES; i ++) {
      while ((st - micros()) < r_[rate - 6]) {
        CheckSW();
        if (rate < 6)
          break;
      }
      if (rate < 6) { // sampling rate has been changed
        tft.fillScreen(BGCOLOR);
        break;
      }
      st += r_[rate - 6];
      if (st - micros() > r_[rate - 6])
        st = micros(); // sampling rate has been changed to shorter interval
      if (!Start) {
        i --;
        continue;
      }
      data[sample + 0][i] = adRead(ad_ch0, ch0_mode, ch0_off);
      data[sample + 1][i] = adRead(ad_ch1, ch1_mode, ch1_off);
      ClearAndDrawDot(i);
    }
    // Serial.println(millis()-st0);
    DrawGrid();
    DrawText();
  } else {
    CheckSW();
  }
  if (trig_mode == TRIG_ONE)
    Start = 0;
}


Hiç yorum yok:

Yorum Gönder