Мини осциллограф Arduino на LCD 5110

pooller
Offline
Зарегистрирован: 13.04.2014

Доброго времени суток всем!

Накопал в сети интересный девайс -осциллограф на ARDUINO

У меня как раз завалялись дома Arduino Pro Mini 328 - 3.3V/8MHz и графический LCD дисплей Nokia 5110 для Arduino

залил этот скетч:

/* 
 ###########################################################
 Title:       Arduino Oscilloscope
 Purpose:     Use a Nokia 3310 GLCD screen with the arduino
 Created by:  Fileark. see Fileark.com for more info.
 Note:        Please reuse, repurpose, and redistribute this code.
 Note:        This code uses the Adafruit PDC8544 LCD library  
 ###########################################################
 */

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);


// a bitmap of a 16x16 fruit icon
static unsigned char __attribute__ ((progmem)) logo16_glcd_bmp[]={
  0x06, 0x0D, 0x29, 0x22, 0x66, 0x24, 0x00, 0x01, 0x87, 0x00, 0x27, 0x6C, 0x20, 0x23, 0x06, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 

int channelAI = A0;      // select the input pin for the Oscilioscope
int scaleYAI = A1;       // select the input pin for the Y (horizontal) potentiometer
int scaleXAI = A2;       // select the input pin for the X (Vertical) potentiometer

int delayVariable = 0;   // define a variable for the Y scale / delay
int xVariable = 0;       // define a variable for the x scale 
int yCtr = 0;            // define a variable for the y counter used to collect y position into array
int posy = 0;            // define a variable for the y position of the dot 
int myArray[85];         // define an array to hold the data coming in 


void setup(void) 
{
  Serial.begin(9600);
  display.begin();
  // init done
  // you can change the contrast around to adapt the display
  // for the best viewing!
  display.setContrast(40);
  delay(2000);
  display.clearDisplay();   // clears the screen and buffer
}

void loop() 
{  
  delayVariable = analogRead(scaleYAI);
  delayVariable = (delayVariable/50);
  xVariable = analogRead(scaleXAI);
  xVariable = (xVariable/22); 

  for(yCtr = 0; yCtr < 85; yCtr += 1)   // the for loop runs from 0 and < 85, it fills the array with 84 records
  {                                 
    posy = analogRead(channelAI);       // read the value from the sensor:
    myArray[yCtr] = (posy/xVariable);   // scale the value based on the x scale potentiometer      
    delay (delayVariable);           // scale the y collection of data using the delay from the y potentiometer   
  }

  yCtr == 0;                           // set the counter to zero so we can use it again
  display.clearDisplay();                        // clear the LCD screen so we can draw new pixels

  for(yCtr = 0; yCtr < 85; yCtr += 1)  // for loop runs 84 times
  {
    display.drawPixel(yCtr, myArray[yCtr], BLACK); // draw the 84 pixels on the screen
  }

  display.display();                     // show the changes to the buffer
  yCtr == 0;                           // set the counter to zero so we can use it again

} 


Подключил дисплей как на картинке
все заработало, но на экране нет ни частоты ни амплитуды
 
Порылся еще в сети и нарыл осциллограф с другим экраном от NOKIA 3310
Но тут уже все отображается и частота и амплитуда 
скетч: 
#include "U8glib.h"
#include <EEPROM.h>
 
// Variables you might want to play with
byte useThreshold = 1;                  // 0 = Off, 1 = Rising, 2 = Falling
byte theThreshold = 128;                // 0-255, Multiplied by voltageConst
unsigned int timePeriod = 200;          // 0-65535, us or ms per measurement (max 0.065s or 65.535s)
byte voltageRange = 1;                  // 1 = 0-3.3V, 2 = 0-1.65V, 3 = 0-0.825V
byte ledBacklight = 100;
 
boolean autoHScale = true;             // Automatic horizontal (time) scaling
boolean linesNotDots = true;            // Draw lines between data points
 
// Variables that can probably be left alone
const byte vTextShift = 3;              // Vertical text shift (to vertically align info)
const byte numOfSamples = 100;          // Leave at 100 for 128x64 pixel display
unsigned int HQadcReadings[numOfSamples];
byte adcReadings[numOfSamples];
byte thresLocation = 0;                 // Threshold bar location
float voltageConst = 0.052381;          // Scaling factor for converting 0-63 to V
float avgV = 0.0;    
float maxV = 0.0;
float minV = 0.0;
float ptopV = 0.0;
float theFreq = 0;
 
const byte theAnalogPin = 7;             // Data read pin
 
const byte lcdLED = 6;                   // LED Backlight
const byte lcdA0 = 7;                    // Data and command selections. L: command  H : data
const byte lcdRESET = 8;                 // Low reset
const byte lcdCS = 9;                    // SPI Chip Select (internally pulled up), active low
const byte lcdMOSI = 11;                 // SPI Data transmission
const byte lcdSCK = 13;                  // SPI Serial Clock
 
// SW SPI:
//U8GLIB_MINI12864 u8g(lcdSCK, lcdMOSI, lcdCS, lcdA0, lcdRESET);
// HW SPI:
U8GLIB_MINI12864 u8g(lcdSCK, lcdMOSI, lcdCS, lcdA0, lcdRESET);
 
// High speed ADC code
// From: http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b...
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
 
void collectData(void) {
  unsigned int tempThres = 0;
  unsigned int i = 0;
 
  if (autoHScale == true) {
    // With automatic horizontal (time) scaling enabled,
    // scale quickly if the threshold location is far, then slow down
    if (thresLocation > 5*numOfSamples/8) {
      timePeriod = timePeriod + 10;
    } else if (thresLocation < 3*numOfSamples/8) {
      timePeriod = timePeriod - 10;
    } else if (thresLocation > numOfSamples/2) {
      timePeriod = timePeriod + 2;
    } else if (thresLocation < numOfSamples/2) {
      timePeriod = timePeriod - 2;
    }
  }
  // Enforce minimum time periods
  if (timePeriod < 35) {
    timePeriod = 35;
  }
   
  // Adjust voltage contstant to fit the voltage range
  if (voltageRange == 1) {
    voltageConst = 0.0523810; // 0-3.30V
  } else if (voltageRange == 2) {
    voltageConst = 0.0261905; // 0-1.65V
  } else if (voltageRange == 3) {
    voltageConst = 0.0130952; //0-0.825V
  }
   
  // If using threshold, wait until it has been reached
  if (voltageRange == 1) tempThres = theThreshold << 2;
  else if (voltageRange == 2) tempThres = theThreshold << 1;
  else if (voltageRange == 3) tempThres = theThreshold;
  if (useThreshold == 1) {
     i = 0; while ((analogRead(theAnalogPin)>tempThres) && (i<32768)) i++;
     i = 0; while ((analogRead(theAnalogPin)<tempThres) && (i<32768)) i++;
  }
  else if (useThreshold == 2) {
     i = 0; while ((analogRead(theAnalogPin)<tempThres) && (i<32768)) i++;
     i = 0; while ((analogRead(theAnalogPin)>tempThres) && (i<32768)) i++;
  }
 
  // Collect ADC readings
  for (i=0; i<numOfSamples; i++) {
    // Takes 35 us with high speed ADC setting
    HQadcReadings[i] = analogRead(theAnalogPin);
    if (timePeriod > 35)
      delayMicroseconds(timePeriod-35);
  }
  for (i=0; i<numOfSamples; i++) {
    // Scale the readings to 0-63 and clip to 63 if they are out of range.
    if (voltageRange == 1) {
      if (HQadcReadings[i]>>4 < 0b111111) adcReadings[i] = HQadcReadings[i]>>4 & 0b111111;
      else adcReadings[i] = 0b111111;
    } else if (voltageRange == 2) {
      if (HQadcReadings[i]>>3 < 0b111111) adcReadings[i] = HQadcReadings[i]>>3 & 0b111111;
      else adcReadings[i] = 0b111111;
    } else if (voltageRange == 3) {
      if (HQadcReadings[i]>>2 < 0b111111) adcReadings[i] = HQadcReadings[i]>>2 & 0b111111;
      else adcReadings[i] = 0b111111;
    }
    // Invert for display
    adcReadings[i] = 63-adcReadings[i];
  }
   
  // Calculate and display frequency of signal using zero crossing
  if (useThreshold != 0) {
     if (useThreshold == 1) {
        thresLocation = 1;
        while ((adcReadings[thresLocation]<(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
        thresLocation++;
        while ((adcReadings[thresLocation]>(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
     }
     else if (useThreshold == 2) {
        thresLocation = 1;
        while ((adcReadings[thresLocation]>(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
        thresLocation++;
        while ((adcReadings[thresLocation]<(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
     }
 
     theFreq = (float) 1000/(thresLocation * timePeriod) * 1000;
  }
   
  // Average Voltage
  avgV = 0;
  for (i=0; i<numOfSamples; i++)
     avgV = avgV + adcReadings[i];
  avgV = (63-(avgV / numOfSamples)) * voltageConst;
 
  // Maximum Voltage
  maxV = 63;
  for (i=0; i<numOfSamples; i++)
     if (adcReadings[i]<maxV) maxV = adcReadings[i];
  maxV = (63-maxV) * voltageConst;
 
  // Minimum Voltage
  minV = 0;
  for (i=0; i<numOfSamples; i++)
     if (adcReadings[i]>minV) minV = adcReadings[i];
  minV = (63-minV) * voltageConst;
 
  // Peak-to-Peak Voltage
  ptopV = maxV - minV;
}
 
void handleSerial(void) {
  char inByte;
  char dataByte;
  boolean exitLoop = false;
  do {
    // Clear out buffer
    do {
      inByte = Serial.read();
    } while (Serial.available() > 0);
   
    Serial.print("\nArduino LCD Oscilloscope\n");
    Serial.print(" 1 - Change threshold usage (currently: ");
      if (useThreshold == 0) Serial.print("Off)\n");
      else if (useThreshold == 1) Serial.print("Rise)\n");
      else if (useThreshold == 2) Serial.print("Fall)\n");
    Serial.print(" 2 - Change threshold value (currently: ");
      Serial.print(theThreshold, DEC); Serial.print(")\n");
    Serial.print(" 3 - Change sampling period (currently: ");
      Serial.print(timePeriod, DEC); Serial.print(")\n");
    Serial.print(" 4 - Change voltage range (currently: ");
      if (voltageRange == 1) Serial.print("0-3.3V)\n");
      else if (voltageRange == 2) Serial.print("0-1.65V)\n");
      else if (voltageRange == 3) Serial.print("0-0.825V)\n");
    Serial.print(" 5 - Toggle auto horizontal (time) scaling (currently: ");
      if (autoHScale == true) Serial.print("On)\n");
      else if (autoHScale == false) Serial.print("Off)\n");
    Serial.print(" 6 - Toggle line/dot display (currently: ");
      if (linesNotDots == true) Serial.print("Lines)\n");
      else if (linesNotDots == false) Serial.print("Dots)\n");
    Serial.print(" 8 - Exit\n");
     
    // Wait for input/response, refresh display while in menu
    do {
      collectData();
      // Picture Display Loop
      u8g.firstPage();  
      do { draw(); } while( u8g.nextPage() );
    } while (Serial.available() == 0);
    inByte = Serial.read();
     
    if (inByte == '1') {
      Serial.print("Change threshold usage\n");
      Serial.print(" 0 - Off\n");
      Serial.print(" 1 - Rise\n");
      Serial.print(" 2 - Fall\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') useThreshold = 0;
      else if (dataByte == '1') useThreshold = 1;
      else if (dataByte == '2') useThreshold = 2;
    } else if (inByte == '2') {
      Serial.print("Change threshold value (thresholds for 0-3.3V,0-1.65V,0-0.825V ranges)\n");
      Serial.print(" 0 - 32 (0.41V, 0.21V, 0.10V)\n");
      Serial.print(" 1 - 80 (1.04V, 0.52V, 0.26V)\n");
      Serial.print(" 2 - 128 (1.66V, 0.83V, 0.41V)\n");
      Serial.print(" 3 - 176 (2.28V, 1.14V, 0.57V)\n");
      Serial.print(" 4 - 224 (2.90V, 1.45V, 0.72V)\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') theThreshold = 32;
      else if (dataByte == '1') theThreshold = 80;
      else if (dataByte == '2') theThreshold = 128;
      else if (dataByte == '3') theThreshold = 176;
      else if (dataByte == '4') theThreshold = 224;
    } else if (inByte == '3') {
      Serial.print("Change sampling frequency\n");
      Serial.print(" 0 - 28 kHz (35 us/sample)\n");
      Serial.print(" 1 - 20 kHz (50 us/sample)\n");
      Serial.print(" 2 - 10 kHz (100 us/sample)\n");
      Serial.print(" 3 - 5 kHz (200 us/sample)\n");
      Serial.print(" 4 - 2.5 kHz (400 us/sample)\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') timePeriod = 35;
      else if (dataByte == '1') timePeriod = 50;
      else if (dataByte == '2') timePeriod = 100;
      else if (dataByte == '3') timePeriod = 200;
      else if (dataByte == '4') timePeriod = 400;
    } else if (inByte == '4') {
      Serial.print("Change voltage range\n");
      Serial.print(" 1 - 0-3.3V\n");
      Serial.print(" 2 - 0-1.65V\n");
      Serial.print(" 3 - 0-0.825V\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '1') voltageRange = 1;
      else if (dataByte == '2') voltageRange = 2;
      else if (dataByte == '3') voltageRange = 3;
    } else if (inByte == '5') {
      Serial.print("Toggle auto horizontal (time) scaling\n");
      Serial.print(" 0 - Off\n");
      Serial.print(" 1 - On\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') autoHScale = false;
      else if (dataByte == '1') autoHScale = true;
    } else if (inByte == '6') {
      Serial.print("Toggle line/dot display\n");
      Serial.print(" 0 - Lines\n");
      Serial.print(" 1 - Dots\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') linesNotDots = true;
      else if (dataByte == '1') linesNotDots = false;
    } else if (inByte == '8') {
      Serial.print("Bye!\n");
      exitLoop = true;
    }
  } while (exitLoop == false);
}
 
void draw(void) {
  int i;
  char buffer[16];
   
  u8g.setFont(u8g_font_micro);
   
  // Draw static text
  u8g.drawStr(0, 5+vTextShift, "Av");
  u8g.drawStr(0, 11+vTextShift, "Mx");
  u8g.drawStr(0, 17+vTextShift, "Mn");
  u8g.drawStr(0, 23+vTextShift, "PP");
  u8g.drawStr(0, 29+vTextShift, "Th");
  u8g.drawStr(24, 35+vTextShift, "V");
  u8g.drawStr(0, 41+vTextShift, "Tm");
  u8g.drawStr(4, 47+vTextShift, "ms/div");
  u8g.drawStr(20, 53+vTextShift, "Hz");
  u8g.drawStr(0, 59+vTextShift, "R");
   
  // Draw dynamic text
  if (autoHScale == true) u8g.drawStr(124, 5, "A");
  dtostrf(avgV, 3, 2, buffer);
  u8g.drawStr(12, 5+vTextShift, buffer);
  dtostrf(maxV, 3, 2, buffer);
  u8g.drawStr(12, 11+vTextShift, buffer);
  dtostrf(minV, 3, 2, buffer);
  u8g.drawStr(12, 17+vTextShift, buffer);
  dtostrf(ptopV, 3, 2, buffer);
  u8g.drawStr(12, 23+vTextShift, buffer);
  dtostrf(theFreq, 5, 0, buffer);
  u8g.drawStr(0, 53+vTextShift, buffer);
  if (useThreshold == 0) {
    u8g.drawStr(12, 29+vTextShift, "Off");
  } else if (useThreshold == 1) {
    u8g.drawStr(12, 29+vTextShift, "Rise");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  } else if (useThreshold == 2) {
    u8g.drawStr(12, 29+vTextShift, "Fall");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  }
  u8g.drawStr(8, 35+vTextShift, buffer);
  // Correctly format the text so that there are always 4 characters
  if (timePeriod < 400) {
    dtostrf((float) timePeriod/1000 * 25, 3, 2, buffer);
  } else if (timePeriod < 4000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 1, buffer);
  } else if (timePeriod < 40000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 0, buffer);
  } else { // Out of range
    dtostrf((float) 0.00, 3, 2, buffer);
  }
  u8g.drawStr(12, 41+vTextShift, buffer);
  if (voltageRange == 1) {
    u8g.drawStr(4, 59+vTextShift, "0-3.30");
  } else if (voltageRange == 2) {
    u8g.drawStr(4, 59+vTextShift, "0-1.65");
  } else if (voltageRange == 3) {
    u8g.drawStr(4, 59+vTextShift, "0-0.83");
  }
   
  // Display graph lines
  u8g.drawLine((128-numOfSamples),0,(128-numOfSamples),63);
  if (useThreshold != 0)
     for (i=29; i<127; i+=3)
        u8g.drawPixel(i,63-(theThreshold>>2));
  for (i=0; i<63; i+=5) {
     u8g.drawPixel(53,i);
     u8g.drawPixel(78,i);
     u8g.drawPixel(103,i);
     u8g.drawPixel(127,i);
  }
  // Threshold bar
  for (i=0; i<63; i+=3)
     u8g.drawPixel(thresLocation+(128-numOfSamples),i);
  // Draw ADC readings
  if (linesNotDots == true) {
    for (i=1; i<numOfSamples; i++) // Draw using lines
      u8g.drawLine(i+(128-numOfSamples)-1,adcReadings[i-1],i+(128-numOfSamples),adcReadings[i]);
  } else {
    for (i=2; i<numOfSamples; i++) // Draw using points
      u8g.drawPixel(i+(128-numOfSamples),adcReadings[i]);
  }
}
 
void setup() {
  u8g.begin();
  Serial.begin(9600);
   
  // Turn on LED backlight
  analogWrite(lcdLED, ledBacklight);
   
  #if FASTADC
    // set prescale to 16
    sbi(ADCSRA,ADPS2) ;
    cbi(ADCSRA,ADPS1) ;
    cbi(ADCSRA,ADPS0) ;
  #endif
  delay(100);
}
 
void loop() {
  collectData();
  // Picture Display Loop
  u8g.firstPage();  
  do { draw(); } while( u8g.nextPage() );
 
  // If user sends any serial data, show menu
  if (Serial.available() > 0) {
    handleSerial();
  }
 
  // rebuild the picture after some delay
  delay(100);
}

Если кто знает как переделать этот скетч c NOKIA 3310

 
const byte lcdLED = 6;                   // LED Backlight
const byte lcdA0 = 7;                    // Data and command selections. L: command  H : data
const byte lcdRESET = 8;                 // Low reset
const byte lcdCS = 9;                    // SPI Chip Select (internally pulled up), active low
const byte lcdMOSI = 11;                 // SPI Data transmission
const byte lcdSCK = 13;                  // SPI Serial Clock

под мой экран NOKIA 5110

// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)

Помогите разобраться, я уже себе весь мозг проел

 
 
pooller
Offline
Зарегистрирован: 13.04.2014

вот так этот девайс должен работать

http://semifluid.com/wp-content/uploads/2013/05/MVI_4205.mp4.mp4

danny222
Offline
Зарегистрирован: 16.04.2014

U8GLIB универсальная библиотека вроде как)

const byte lcdLED = 6;                   // LED Backlight
const byte lcdA0 = 9;                    // Data and command selections. L: command  H : data
const byte lcdRESET = 8;                 // Low reset
const byte lcdCS = 10;                    // SPI Chip Select (internally pulled up), active low
const byte lcdMOSI = 11;                 // SPI Data transmission
const byte lcdSCK = 13;                  // SPI Serial Clock
 
U8GLIB_PCD8544 u8g(13, 11, 10, 9, 8); // SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9, Reset = 8
 
с 29 по 39 строку в твоем примере
 
Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

При беглом осмотре, в 66 строке   yCtr == 0; // set the counter to zero so we can use it

Может там должно быть присваивание?

Geronimo
Offline
Зарегистрирован: 06.05.2013

Не имеет значения, следом идет цикл который сбросит в 0. Строка ничего не делает полезного или вредного.

dtvims
Offline
Зарегистрирован: 26.11.2012

Ключевое - это заменить U8GLIB_MINI12864 на U8GLIB_PCD8544

const byte lcdLED = 6;                   // LED Backlight
const byte lcdA0 = 7;                    // D/C - Data and command selections. L: command  H : data
const byte lcdRESET = 8;                 // RST- Low reset
const byte lcdCS = 9;                    // SCE - SPI Chip Select (internally pulled up), active low
const byte lcdMOSI = 11;                 // DIN(MOSI) - SPI Data transmission
const byte lcdSCK = 13;                  // SCK - SPI Serial Clock

а вот дальше начинаются проблемы, что разрешение экрана меньше чем надо :(

На фото дисплей 5110 с последней программой, а на дуине замкнут adc7 с d0(rx), таким образом на вход осцилографа подается сигнал с uart'а, куда бегут с компа буковки "а".

dtvims
Offline
Зарегистрирован: 26.11.2012

Был у меня дисплейчик побольше и за ту же цену, что 5110, см. http://we.easyelectronics.ru/lcd_gfx/podklyuchenie-tft-displeya-k-avr.html

Дисплей больше разрешением, даже чем тот, что в оригинальном примере, да еще и цветной. Правда ардуинка слишком медленно расчеты делает для вывода на экран, пришлось весь вывод на экран значительно переработать, стало приемлимо и красиво :) На экране ШИМ подсветки этого же дисплея.

Если кому понадобится, выложу код для данного дисплея.

pooller
Offline
Зарегистрирован: 13.04.2014

Сегодня приобрел вот такой экранчик:

 
Может кто знает как его подключить к этой схеме?
я уже устал ломать себе голову и издеваться над гуглом
 
 
 
dtvims
Offline
Зарегистрирован: 26.11.2012

По первой Вашей ссылке подключение. Передача данных по 8бит D0-D7. Последовательность инициализаци надо искать в даташите. Далее надо экспериментировать. В основном все покупают для подобных поделок дисплеи уже на плате с простым интерфейсом spi, а поскольку сразу все делают так, то и инфы на такие дисплеи больше.

pooller
Offline
Зарегистрирован: 13.04.2014

Я даже не задумывался, что возникнут такие сложности в подключении этого дисплея.

для подключения этого дисплея нужно применить ету схему? Я правильно понял? 

//U8GLIB_ST7920_128X64_1X u8g(8, 9, 10, 11, 4, 5, 6, 7, 18, 17, 16);   // 8Bit Com: D0..D7: 8,9,10,11,4,5,6,7 en=18, di=17,rw=16

 

dtvims
Offline
Зарегистрирован: 26.11.2012

Вариант Вы написали правильно, вот только Ваш дисплей в Возможно совместимых с данной библиотекой.

Есть вот такая темка http://forum.arduino.cc/index.php/topic,134689.0.html - может чем поможет.

pooller
Offline
Зарегистрирован: 13.04.2014

у меня для такого подключения не хватит ног на ардуине

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

почему не хватит? хватает же

pooller
Offline
Зарегистрирован: 13.04.2014

Если не трудно напишина какие ноги этот экран мне подключать? Там ведь есть и 16, 17,18 но на моей дуине такого нет(( 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

пины можно любые настроить для доп. управляющих. для основных из одного порта должно быть. тоесть оставляете как есть

а вот 16 17 18 меняете на свои

я бы так сделал. как в либе сделано надо смотреть

попробуйте проще. меняете на любые доступные и проверьте.

я не нашел соответствия одному порту на меге328 и 2560 для выводов данных. может и проглядел, но лучше проверье тупо вставляя свои пины

 

dtvims
Offline
Зарегистрирован: 26.11.2012

Идеально d0-d7 подключить целиком на 1 порт atmega, а остальные любые, ну кроме тех, что используются. Кстати, так и передача данных будет быстрее, чем по spi. Если ардуино на меге вроде 328-й то целиком ни одного порта не получается:  на PORTB сидит кварц, на С находится ADC, на D сидит UART, т.е. для идеала надо что-то более многоногое :(

Пинов должно хватить в любом случае. Только лучше базовый доступ к дисплею свой делать. Кстати, под переделку лучше использовать библиотеку adafruit, там на, мой взгляд, понятнеее что переписывать надо. Собственно, я на нее все и переделал себе, плюс немного оптимизации и получилось очень даже ничего :)

pooller
Offline
Зарегистрирован: 13.04.2014

Еще немного и я разобью этот дисплей об ету ардуину. 

Хоть как то бы подключить уже. Я уже задолбался, мозг пухнет

dtvims
Offline
Зарегистрирован: 26.11.2012

С таким подходом у Вас ничего не получится :(

С первого раза редко, что получается. Почитайте обсуждения профессионалов, которые говорят: подозрительно, что у меня все сразу заработало.

Поэтому самое оптимальное брать примеры, которые заведомо работают и повторять их. Для этого Вам надо для начала, прикупить дисплей, на который есть готовые примеры, а потом уже данный мучать, со знанием дела...

pooller
Offline
Зарегистрирован: 13.04.2014

Это у меня от того что я в тупик уткнулся, эмоции полезли мучать этот дисплей я то буду пока у меня не получится. Решил подключать по 8 бит, пока перепаял все провода, потом подключил и не чего не произошло. Дисплей как лежал без признаков жизни так и продолжал спокойно лежать. Я до трех часов ночи издевался над гуглом и над дисплеем, пока сам не выключился

Там на дисплее, как оказалось еще перемычка есть. Последовательный или паралельный 

 

dtvims
Offline
Зарегистрирован: 26.11.2012

Давайте переключим на последовательный режим и тогда ему будет соответствовать один из методов подключения ST7565

Значит 17 и 18 - это подсветка дисплея: Земля и питание(3.3В). Без подсветкы Вы врятли чего увидите на экране. На моем не видно ничего.

1 - GND

2 - VCC (3.3В)

6 - D/C

17 - sclk

16 - MOSI 

5 - CS - chip select

4 - reset

Более детально см. тут http://www.crystalfontz.com/controllers/Novatek_NT7534.pdf

UPD. Есть предположение, что заработает вот такой класс U8GLIB_NHD_C12864

pooller
Offline
Зарегистрирован: 13.04.2014

Вот спасибо за помощь. Хоть какой то сдвиг в этом деле. Я в тупик уже залез, не знал уже что дальше делать. Все идеи закончились. Сегодня приеду с работы домой, Сразу попробую подключить, так как вы написали.

dtvims
Offline
Зарегистрирован: 26.11.2012

Еще дополнение:

U8GLIB_NHD_C12864(sck, mosi, cs, a0 [, reset])  - Вариант SW SPI - програмный SPI

U8GLIB_NHD_C12864(cs, a0 [, reset]) - Вариант HW SPI - Хардварный. Разумеется - это лучше, потому как быстрее, только SCLK и MOSI подключаются строго на 11-й и 13-й пины дудки, см. примеры.

RESET - необязателен, его можно замкнуть с ресетом дуинки.

pooller
Offline
Зарегистрирован: 13.04.2014

подключил так, как вы написали. Не заработало (

Кто то не правильный или ардуинка или дисплей или я))

Завтра с самого утра займусь с начала проверять все что наподключал. Где то должен быть какой то косяк. Ардуинку проверял только что на дисплее от 5110 - все работает. Вот только заметил какие то крадковременные подвисания при работе программы осциллографа. может они и ранее были а я не замечал их. 

dtvims
Offline
Зарегистрирован: 26.11.2012

Подключение пинов я написал как написано в даташите. Мог пропустить какую-то деталь. Потом класс из библиотеки u8glib, совместим условно с Вашим дисплеем и может не стартовать из-за какой-нибудь пропущенной мелочи в инициализации, или может Вы пины на шлейфе не в ту сторону нумировали? Режим точно последовательный включили? Я в свое время долго мучал протокол ps/2 где в зависимости от компа идет разная инициализация устройства и если все не предусмотреть, то ничего и не работает и непонятно куда девается "искра внутреннего сгорания", потом все-таки нашел...

Подвисания и должны быть. Между обновлениями дисплея он делает всю пачку измерений. Если масштаб используется для высокой частоты, то измерения делаются без задержек, если низкой частоты, то чтобы не отображать одну прямую, делаются искуственные задержки между измерениями, вот и получается весьма заметная задержка.

pooller
Offline
Зарегистрирован: 13.04.2014

А при неправильной библиотеке на экране должно что то появляться? Просто сколько я не экспериментировал, диспей лежит без всяких признаков жизни, кроме подсветки

dtvims
Offline
Зарегистрирован: 26.11.2012

Чтобы что-то изменилось, нужна правильная последовательность инициализации. Если выбран неверно метод, дисплей не заработает. Надо курить внимательно даташит, ссылка выше. Но опять же, даташит верен, если верно указан контроллер монитора по Вашим ссылкам, бывает заказываешь одно, а там что-то поменяли на аналог... Попробуйте разобраться в даташите, проинициализируйте spi самостоятельно, и инициадизируйте дисплей по даташиту. Потренироваться можно на дисплее, который Вам уже получилось включить, просто, чтобы понять, что все делаете правильно.

pooller
Offline
Зарегистрирован: 13.04.2014

Подключал всеми способами (последовательным, параллельным) загружал все доступные мне библиотеки, и ни чего у меня не получилось. Лежит мой дисплей, без признаков жизни, хоть бы какую нибудь ерунду показал. А так, кроме подсветки ни чего не выдал. Буду мучать гугл, может там что накопаю.

dtvims
Offline
Зарегистрирован: 26.11.2012

Интересно, что вот тут http://www.e-tools.info/index.php?page=component_detail&id=3329 я нашел совершенно другую раскладку. Искал уже не от Ваших ссылок, а от фотгорафий дисплея.

Тогда получается вот так: 1-cs, 2-reset, 3-d/c, 12-scl, 13-mosi, 14-vcc, 15-gnd.

pooller
Offline
Зарегистрирован: 13.04.2014

а на такой дисплей 2,4" TFT LCD Touch shield

возможно установить осциллограф? 

я пытался воткнуть в скетч осциллографа библиотеки этого дисплея, что то у меня ни чего не вышло

dtvims
Offline
Зарегистрирован: 26.11.2012

А Вы примеры с ним просто отдельно пробовали?

Просто так работать не будет, надо переделывать всю работу с дисплеем из осцилографа.

Например, я убрал инициализацию u8g полностью и поставил вместо него свой класс с другим именем переменной, типа tft, потом заменил все вхождения методов из u8g на аналогичные методы из своего tft. При полной замене завелось сразу, только шрифты разъехались. Затем перерасчитал где и что выводить, чтобы выводилось более красиво. Затем стал оптимизировать вывод на дисплей, чтобы искличить моргание при перерисовке, чтобы все красиво и быстро работало.

pooller
Offline
Зарегистрирован: 13.04.2014

Я не правильно вопрос задал, но ответ получил именно тот, который и хотел услышать)))

пример с ним есть у меня рабочий рисовалка 

там к этому дисплею несколько библиотек есть но некоторые не могу запустить, какую то ошибку выдают при компиляции я погуглил, так и не понял, что он от меня хочет. А рисовалка запустилась нормально. Сын часа на два завис в рисовании на экране))) 

pooller
Offline
Зарегистрирован: 13.04.2014

я наивно думал, что можно скопировать ту часть скетча, где идет инициализация дисплея в скетч осциллографа и все заработает. 

pooller
Offline
Зарегистрирован: 13.04.2014

А можешь выложить свой скетч, со своим цветным дисплеем? Я попробую разобраться, что нужно изменить под библиотеку своего LCD 

 

dtvims
Offline
Зарегистрирован: 26.11.2012

Ну, например было u8g.drawStr(12, 17+vTextShift, buffer);

а надо tft.text(12, 17+vTextShift, buffer); - Это гипотетический пример. может быть разбито на 2 разных команды, типо установки координат, а отдельно вывод текста. См. Класс для Вашего дисплея.

UPD. Неудержался и заказал себе такой же дисплейчик. Недели через 2 перепишу код под него :)

pooller
Offline
Зарегистрирован: 13.04.2014

Я сам не удержался от покупки этого дисплейчика. Пока экспериментировал с подключением жки128x64 к ардуине случайно раздавил свой экран от нокии 5110. полез искать новый и купил 2,4" TFT LCD Touch shield и еще arduino uno к нему

dtvims
Offline
Зарегистрирован: 26.11.2012

Я сейчас хочу повторить данный осцилограф на stm32, по шустре будет в 4 раза. Думал убрать управление по uart'у и заменить на меню на дисплее и несколько кнопок. Тачскрин же прилично расширяет возможности, уже никакие кнопки делать не надо. Жаль только, что ждать придется, но цена вкусная :)

Меня смущает для ардуино, что дисплей сожрал почти все ноги.

Immortal
Offline
Зарегистрирован: 28.12.2013

dtvims, получилось что то на stm32 ?

Первоисточник второго показометра: http://www.semifluid.com/2013/05/28/arduino-fio-lcd-oscilloscope/

dtvims
Offline
Зарегистрирован: 26.11.2012

Получилось первое приближение с мониторчиком 5110, в режиме "все на авто, от 0 до 3.3В". От ADC у STM32 я ожидал большего. http://rukodelie-ds.ru/forum/viewtopic.php?f=13&t=734#p972 - тут пока кривое, но работающее решение.

Сейчас, приостановил эксперименты, т.к. занят и жду сенсорный дисплейчик (см.выше), что должен вот-вот приехать.

Immortal
Offline
Зарегистрирован: 28.12.2013

dtvims, Цветной экран справа это 128x160 на ST7735S?

Я думаю заказать экран побольше, без тача: 240x320 на ILI9341 за $5.57 http://www.elecfreaks.com/wiki/index.php?title=2.2S%22_TFT_LCD:_TFT01-2.2S и преобразователь уровней 3.3V <-> 5V. Тема на форуме

На сколько сложно будет переписать stm32-скетч под такой экран?

dtvims
Offline
Зарегистрирован: 26.11.2012

Да, справа все тот же экран, что я показывал тут на форуме, я его с ардуиной брал за эталон. Собственно источником сигнала служит шим с той же дуинки, через резистор, с парой кондесаторов на землю (можно их увидеть между дисплеями). Смотрел чтобы вид сигнала и расчет частоты были похожи. Конечно о какой-то точности говорить не приходится, калибровать просто не на чем :(

С точки зрения конкретного кода, что я сделал для stm32, то под другой дисплей надо переделать только 3 функции: вывод пикселя, вывод текста и очистку экрана. Но это решит только проблему взаимодействия с экраном. Больше по размеру и добавление цветов у др. дисплея, означает, что надо гнать больше данных по spi, что может сильно отразиться на скорости отображения и может появится сильно заметное мерцание, вот тут понадобится доп. оптимизация с отрисовкой. Я такую оптимизацию провел для дуинки: изменил функцию отрисовки линий с учетом конкретной задачи, стал обновлять только изменения (текст, только тот что изменился, лини стирать старые и сразу рисовать новые). Вариант настроек по usart'у меня как-то не очень устраивает, потому дальше надеюсь сделать на сенсорном экране меню с настройками. Еже хочу включить второй adc,  создать виртуальный usb-comport и гнать по нему данные вреальном времени, чтобы обрабатывать цифровые сигналы - эх, мечты...

 

P.s. а зачем Вам преобразователь уровней? Запускайте все на 3.3В! Stm32 так вообще на этом напряжении работает, дисплей тоже...

Immortal
Offline
Зарегистрирован: 28.12.2013

dtvims пишет:

а зачем Вам преобразователь уровней? Запускайте все на 3.3В! Stm32 так вообще на этом напряжении работает

Я думал его сначала на ардуине запустить. Знаю, что будет медленно - у меня уже есть 128x160 на ST7735S и он мерцает, при большем разрешении частота обновления упадет еще сильнее.

Stm32 у меня пока нету, выбираю какую плату заказать.

 

dtvims
Offline
Зарегистрирован: 26.11.2012

На ардуине должен быть переключатель или джампер, переводящий весь контроллер на питание от 3.3В.

Upd. Посмотрел на официальные платки и понял, что по ходу обладателями заветными переключателями или джамперами являются те кто купил или стронние аналоги или дешевые подделки - что-то тут не так :)

Immortal
Offline
Зарегистрирован: 28.12.2013

dtvims пишет:

Был у меня дисплейчик побольше и за ту же цену, что 5110, см. http://we.easyelectronics.ru/lcd_gfx/podklyuchenie-tft-displeya-k-avr.html

Если кому понадобится, выложу код для данного дисплея.

Интересно было бы посмотреть на код, у меня такой же экран.

dtvims пишет:

На ардуине должен быть переключатель или джампер, переводящий весь контроллер на питание от 3.3В.

3.3В найти не проблема. У меня есть и платка стабилизатора и мой "программатор" CP2102 имеет отдельные выводы с 3.3 и 5В

dtvims
Offline
Зарегистрирован: 26.11.2012

Для ST7735 я использовал библиотеку Adafruit и для нее доп. библиотеку Adafruit_ST7735. В последней кое что поменял/добавил "Adafruit_ST7735.cpp":

void Adafruit_ST7735::drawFastLine(int8_t x, int8_t y, int8_t h,int8_t l, uint16_t color){
  int8_t i,j,ih;
  if(abs(h)<5){
    drawLine(x, y, x+l-1,y+h, color);
    return;
  }
  if((x >= _width) || (y >= _height)) return;
  if((y+h-1) >= _height) h = _height-y;
  if((y+h) < 0) h = -y;
  if((x+l-1) >= _width) l = _width-x;
  j=h/l;
  for(i=0;i<l;i++){
	if(h>0){
	  if(i==l-1){
        setAddrWindow(x+i, y+i*j, x+i, y+h-1);
	    ih=h-i*j;
	  }else{
	    setAddrWindow(x+i, y+i*j, x+i, y+(i+1)*j-1);
	    ih=j;
	  }                     
	}else{
	  if(i==l-1){
        setAddrWindow(x+i, y+h, x+i, y+i*j-1);
	    ih=-(h-i*j);
	  }else{
	    setAddrWindow(x+i, y+(i+1)*j, x+i, y+i*j-1);
	    ih=-j;
	  }                     
	}
	uint8_t hi = color >> 8, lo = color;
	*rsport |=  rspinmask;
    *csport &= ~cspinmask;
	while (ih--) {
	  SPDR = hi;
      while(!(SPSR & _BV(SPIF)));
	  SPDR = lo;
	  while(!(SPSR & _BV(SPIF)));
	}
	*csport |= cspinmask;
  }
}

Соответсвенно в "Adafruit_ST7735.h" добавлено описание созданной функции "drawFastLine(int8_t x, int8_t y, int8_t h,int8_t l, uint16_t color),". Писал на скорую руку, только для работы с аппаратным SPI и только для быстрой отрисовки вертикальных линий отрисованных слева на право, во всех других случаях скорее всего будет рисоваться не корректно, но для конкретной задачи дает значительное ускорение.

Ну и сам код как-то  так:

//#include "U8glib.h"
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <EEPROM.h>
 
// Variables you might want to play with
byte useThreshold = 1;                  // 0 = Off, 1 = Rising, 2 = Falling
byte theThreshold = 128;                // 0-255, Multiplied by voltageConst
unsigned int timePeriod = 200;          // 0-65535, us or ms per measurement (max 0.065s or 65.535s)
byte voltageRange = 1;                  // 1 = 0-3.3V, 2 = 0-1.65V, 3 = 0-0.825V
byte ledBacklight = 100;
 
boolean autoHScale = true;             // Automatic horizontal (time) scaling
boolean linesNotDots = true;            // Draw lines between data points
 
// Variables that can probably be left alone
const byte vTextShift = 65;              // Vertical text shift (to vertically align info)
const byte numOfSamples = 128;          // Leave at 100 for 128x64 pixel display
unsigned int HQadcReadings[numOfSamples];
byte adcReadings[numOfSamples];
byte adcOldReadings[numOfSamples];
byte thresLocation = 0;                 // Threshold bar location
float voltageConst = 0.052381;          // Scaling factor for converting 0-63 to V
float avgV = 0.0;    
float maxV = 0.0;
float minV = 0.0;
float ptopV = 0.0;
float theFreq = 0;

byte OlduseThreshold = 1;                  
byte OldtheThreshold = 128;                
unsigned int OldtimePeriod = 200;
float OldavgV = 0.0;    
float OldmaxV = 0.0;
float OldminV = 0.0;
float OldptopV = 0.0;
float OldtheFreq = 0;
 
const byte theAnalogPin = 7;             // Data read pin
 
#define sclk 13
#define mosi 11
#define cs   10
#define dc   8
#define rst  7 
 
// SW SPI:
//U8GLIB_MINI12864 u8g(lcdSCK, lcdMOSI, lcdCS, lcdA0, lcdRESET);
// HW SPI:
//U8GLIB_PCD8544 u8g(lcdSCK, lcdMOSI, lcdCS, lcdA0, lcdRESET);
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst); 
 
// High speed ADC code
// From: <a href="http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b0f36&topic=6549.15" title="http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b0f36&topic=6549.15" rel="nofollow">http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b...</a>
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
 
void collectData(void) {
  unsigned int tempThres = 0;
  unsigned int i = 0;
 
  if (autoHScale == true) {
    // With automatic horizontal (time) scaling enabled,
    // scale quickly if the threshold location is far, then slow down
    if (thresLocation > 5*numOfSamples/8) {
      timePeriod = timePeriod + 10;
    } else if (thresLocation < 3*numOfSamples/8) {
      timePeriod = timePeriod - 10;
    } else if (thresLocation > numOfSamples/2) {
      timePeriod = timePeriod + 2;
    } else if (thresLocation < numOfSamples/2) {
      timePeriod = timePeriod - 2;
    }
  }
  // Enforce minimum time periods
  if (timePeriod < 35) {
    timePeriod = 35;
  }
   
  // Adjust voltage contstant to fit the voltage range
  if (voltageRange == 1) {
    voltageConst = 0.0523810; // 0-3.30V
  } else if (voltageRange == 2) {
    voltageConst = 0.0261905; // 0-1.65V
  } else if (voltageRange == 3) {
    voltageConst = 0.0130952; //0-0.825V
  }
   
  // If using threshold, wait until it has been reached
  if (voltageRange == 1) tempThres = theThreshold << 2;
  else if (voltageRange == 2) tempThres = theThreshold << 1;
  else if (voltageRange == 3) tempThres = theThreshold;
  if (useThreshold == 1) {
     i = 0; while ((analogRead(theAnalogPin)>tempThres) && (i<32768)) i++;
     i = 0; while ((analogRead(theAnalogPin)<tempThres) && (i<32768)) i++;
  }
  else if (useThreshold == 2) {
     i = 0; while ((analogRead(theAnalogPin)<tempThres) && (i<32768)) i++;
     i = 0; while ((analogRead(theAnalogPin)>tempThres) && (i<32768)) i++;
  }
 
  // Collect ADC readings
  for (i=0; i<numOfSamples; i++) {
    // Takes 35 us with high speed ADC setting
    HQadcReadings[i] = analogRead(theAnalogPin);
    if (timePeriod > 35)
      delayMicroseconds(timePeriod-35);
  }
  for (i=0; i<numOfSamples; i++) {
    // Scale the readings to 0-63 and clip to 63 if they are out of range.
    if (voltageRange == 1) {
      if (HQadcReadings[i]>>4 < 0b111111) adcReadings[i] = HQadcReadings[i]>>4 & 0b111111;
      else adcReadings[i] = 0b111111;
    } else if (voltageRange == 2) {
      if (HQadcReadings[i]>>3 < 0b111111) adcReadings[i] = HQadcReadings[i]>>3 & 0b111111;
      else adcReadings[i] = 0b111111;
    } else if (voltageRange == 3) {
      if (HQadcReadings[i]>>2 < 0b111111) adcReadings[i] = HQadcReadings[i]>>2 & 0b111111;
      else adcReadings[i] = 0b111111;
    }
    // Invert for display
    adcReadings[i] = 63-adcReadings[i];
  }
   
  // Calculate and display frequency of signal using zero crossing
  if (useThreshold != 0) {
     if (useThreshold == 1) {
        thresLocation = 1;
        while ((adcReadings[thresLocation]<(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
        thresLocation++;
        while ((adcReadings[thresLocation]>(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
     }
     else if (useThreshold == 2) {
        thresLocation = 1;
        while ((adcReadings[thresLocation]>(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
        thresLocation++;
        while ((adcReadings[thresLocation]<(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
     }
 
     theFreq = (float) 1000/(thresLocation * timePeriod) * 1000;
  }
   
  // Average Voltage
  avgV = 0;
  for (i=0; i<numOfSamples; i++)
     avgV = avgV + adcReadings[i];
  avgV = (63-(avgV / numOfSamples)) * voltageConst;
 
  // Maximum Voltage
  maxV = 63;
  for (i=0; i<numOfSamples; i++)
     if (adcReadings[i]<maxV) maxV = adcReadings[i];
  maxV = (63-maxV) * voltageConst;
 
  // Minimum Voltage
  minV = 0;
  for (i=0; i<numOfSamples; i++)
     if (adcReadings[i]>minV) minV = adcReadings[i];
  minV = (63-minV) * voltageConst;
 
  // Peak-to-Peak Voltage
  ptopV = maxV - minV;
}
 
void handleSerial(void) {
  char inByte;
  char dataByte;
  boolean exitLoop = false;
  do {
    // Clear out buffer
    do {
      inByte = Serial.read();
    } while (Serial.available() > 0);
   
    Serial.print("\nArduino LCD Oscilloscope\n");
    Serial.print(" 1 - Change threshold usage (currently: ");
      if (useThreshold == 0) Serial.print("Off)\n");
      else if (useThreshold == 1) Serial.print("Rise)\n");
      else if (useThreshold == 2) Serial.print("Fall)\n");
    Serial.print(" 2 - Change threshold value (currently: ");
      Serial.print(theThreshold, DEC); Serial.print(")\n");
    Serial.print(" 3 - Change sampling period (currently: ");
      Serial.print(timePeriod, DEC); Serial.print(")\n");
    Serial.print(" 4 - Change voltage range (currently: ");
      if (voltageRange == 1) Serial.print("0-3.3V)\n");
      else if (voltageRange == 2) Serial.print("0-1.65V)\n");
      else if (voltageRange == 3) Serial.print("0-0.825V)\n");
    Serial.print(" 5 - Toggle auto horizontal (time) scaling (currently: ");
      if (autoHScale == true) Serial.print("On)\n");
      else if (autoHScale == false) Serial.print("Off)\n");
    Serial.print(" 8 - Exit\n");
     
    // Wait for input/response, refresh display while in menu
    do {
      collectData();
      draw1();
      // Picture Display Loop
//!!!      u8g.firstPage();  
//      do { draw(); } while( 
//!!!      u8g.nextPage() 
//      );
    } while (Serial.available() == 0);
    inByte = Serial.read();
     
    if (inByte == '1') {
      Serial.print("Change threshold usage\n");
      Serial.print(" 0 - Off\n");
      Serial.print(" 1 - Rise\n");
      Serial.print(" 2 - Fall\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') useThreshold = 0;
      else if (dataByte == '1') useThreshold = 1;
      else if (dataByte == '2') useThreshold = 2;
    } else if (inByte == '2') {
      Serial.print("Change threshold value (thresholds for 0-3.3V,0-1.65V,0-0.825V ranges)\n");
      Serial.print(" 0 - 32 (0.41V, 0.21V, 0.10V)\n");
      Serial.print(" 1 - 80 (1.04V, 0.52V, 0.26V)\n");
      Serial.print(" 2 - 128 (1.66V, 0.83V, 0.41V)\n");
      Serial.print(" 3 - 176 (2.28V, 1.14V, 0.57V)\n");
      Serial.print(" 4 - 224 (2.90V, 1.45V, 0.72V)\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') theThreshold = 32;
      else if (dataByte == '1') theThreshold = 80;
      else if (dataByte == '2') theThreshold = 128;
      else if (dataByte == '3') theThreshold = 176;
      else if (dataByte == '4') theThreshold = 224;
    } else if (inByte == '3') {
      Serial.print("Change sampling frequency\n");
      Serial.print(" 0 - 28 kHz (35 us/sample)\n");
      Serial.print(" 1 - 20 kHz (50 us/sample)\n");
      Serial.print(" 2 - 10 kHz (100 us/sample)\n");
      Serial.print(" 3 - 5 kHz (200 us/sample)\n");
      Serial.print(" 4 - 2.5 kHz (400 us/sample)\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') timePeriod = 35;
      else if (dataByte == '1') timePeriod = 50;
      else if (dataByte == '2') timePeriod = 100;
      else if (dataByte == '3') timePeriod = 200;
      else if (dataByte == '4') timePeriod = 400;
    } else if (inByte == '4') {
      Serial.print("Change voltage range\n");
      Serial.print(" 1 - 0-3.3V\n");
      Serial.print(" 2 - 0-1.65V\n");
      Serial.print(" 3 - 0-0.825V\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '1') voltageRange = 1;
      else if (dataByte == '2') voltageRange = 2;
      else if (dataByte == '3') voltageRange = 3;
    } else if (inByte == '5') {
      Serial.print("Toggle auto horizontal (time) scaling\n");
      Serial.print(" 0 - Off\n");
      Serial.print(" 1 - On\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') autoHScale = false;
      else if (dataByte == '1') autoHScale = true;
    } else if (inByte == '8') {
      Serial.print("Bye!\n");
      exitLoop = true;
    }
    draw();
  } while (exitLoop == false);
}

void drawD(void) {
  char buffer[16];
  if(avgV!=OldavgV){
    tft.setTextColor(ST7735_BLACK);
    dtostrf(OldavgV, 3, 2, buffer);
    tft.setCursor(15, 5+vTextShift);
    tft.print(buffer);
    tft.setTextColor(ST7735_RED);
    dtostrf(avgV, 3, 2, buffer);
    tft.setCursor(15, 5+vTextShift);
    tft.print(buffer);
    OldavgV=avgV;
  }
  if(maxV!=OldmaxV){
    tft.setTextColor(ST7735_BLACK);
    dtostrf(OldmaxV, 3, 2, buffer);
    tft.setCursor(15, 2+11+vTextShift);
    tft.print(buffer);
    tft.setTextColor(ST7735_RED);
    dtostrf(maxV, 3, 2, buffer);
    tft.setCursor(15, 2+11+vTextShift);
    tft.print(buffer);
    OldmaxV=maxV;
  }
  if(minV!=OldminV){
    tft.setTextColor(ST7735_BLACK);
    dtostrf(OldminV, 3, 2, buffer);
    tft.setCursor(15, 4+17+vTextShift);
    tft.print(buffer);
    tft.setTextColor(ST7735_RED);
    dtostrf(minV, 3, 2, buffer);
    tft.setCursor(15, 4+17+vTextShift);
    tft.print(buffer);
    OldminV=minV;
  }
  if(ptopV!=OldptopV){  
    tft.setTextColor(ST7735_BLACK);
    dtostrf(OldptopV, 3, 2, buffer);
    tft.setCursor(15, 6+23+vTextShift);
    tft.print(buffer);
    tft.setTextColor(ST7735_RED);
    dtostrf(ptopV, 3, 2, buffer);
    tft.setCursor(15, 6+23+vTextShift);
    tft.print(buffer);
    OldptopV=ptopV;
  }
  if(theFreq!=OldtheFreq){
    tft.setTextColor(ST7735_BLACK);
    dtostrf(OldtheFreq, 5, 0, buffer);
    tft.setCursor(0, 16+53+vTextShift);
    tft.print(buffer);
    tft.setTextColor(ST7735_RED);
    dtostrf(theFreq, 5, 0, buffer);
    tft.setCursor(0, 16+53+vTextShift);
    tft.print(buffer);
    OldtheFreq=theFreq;
  }
  /*if (useThreshold == 0) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Off");
  } else if (useThreshold == 1) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Rise");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  } else if (useThreshold == 2) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Fall");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  }
  tft.setCursor(11, 10+35+vTextShift);
  tft.print(buffer);*/
  // Correctly format the text so that there are always 4 characters
if(timePeriod!=OldtimePeriod){
  tft.setTextColor(ST7735_BLACK);
  if (OldtimePeriod < 400) {
    dtostrf((float) OldtimePeriod/1000 * 25, 3, 2, buffer);
  } else if (OldtimePeriod < 4000) {
    dtostrf((float) OldtimePeriod/1000 * 25, 3, 1, buffer);
  } else if (OldtimePeriod < 40000) {
    dtostrf((float) OldtimePeriod/1000 * 25, 3, 0, buffer);
  } else { // Out of range
    dtostrf((float) 0.00, 3, 2, buffer);
  }
  tft.setCursor(15, 12+41+vTextShift);
  tft.print(buffer);
  
  tft.setTextColor(ST7735_RED);
  if (timePeriod < 400) {
    dtostrf((float) timePeriod/1000 * 25, 3, 2, buffer);
  } else if (timePeriod < 4000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 1, buffer);
  } else if (timePeriod < 40000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 0, buffer);
  } else { // Out of range
    dtostrf((float) 0.00, 3, 2, buffer);
  }
  tft.setCursor(15, 12+41+vTextShift);
  tft.print(buffer);
  OldtimePeriod=timePeriod;
}
  /*if (voltageRange == 1) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-3.30");
  } else if (voltageRange == 2) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-1.65");
  } else if (voltageRange == 3) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-0.83");
  } */
}
void drawT(void) {
  char buffer[16];
  tft.fillRect(0,vTextShift+5,45,150,ST7735_BLACK);
  tft.setTextColor(ST7735_RED);
  tft.setTextSize(1);
  tft.setCursor(0, 5+vTextShift);
  tft.print("Av");
  tft.setCursor(0, 2+11+vTextShift);
  tft.print("Mx");
  tft.setCursor(0, 4+17+vTextShift);
  tft.print("Mn");
  tft.setCursor(0, 6+23+vTextShift);
  tft.print("PP");
  tft.setCursor(0, 8+29+vTextShift);
  tft.print("Th");
  tft.setCursor(0, 10+35+vTextShift);
  tft.print("V");
  tft.setCursor(0, 12+41+vTextShift);
  tft.print("Tm");
  tft.setCursor(4, 14+47+vTextShift);
  tft.print("ms/div");
  tft.setCursor(31, 16+53+vTextShift);
  tft.print("Hz");
  tft.setCursor(0, 18+59+vTextShift);
  tft.print("R");
 
  // Draw dynamic text
  if (autoHScale == true) {
    tft.setCursor(120, 2);
    tft.print("A");
  }
  dtostrf(avgV, 3, 2, buffer);
  tft.setCursor(15, 5+vTextShift);
  tft.print(buffer);

  dtostrf(maxV, 3, 2, buffer);
  tft.setCursor(15, 2+11+vTextShift);
  tft.print(buffer);

  dtostrf(minV, 3, 2, buffer);
  tft.setCursor(15, 4+17+vTextShift);
  tft.print(buffer);

  dtostrf(ptopV, 3, 2, buffer);
  tft.setCursor(15, 6+23+vTextShift);
  tft.print(buffer);

  dtostrf(theFreq, 5, 0, buffer);
  tft.setCursor(0, 16+53+vTextShift);
  tft.print(buffer);

  if (useThreshold == 0) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Off");
  } else if (useThreshold == 1) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Rise");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  } else if (useThreshold == 2) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Fall");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  }
  tft.setCursor(11, 10+35+vTextShift);
  tft.print(buffer);
  // Correctly format the text so that there are always 4 characters
  if (timePeriod < 400) {
    dtostrf((float) timePeriod/1000 * 25, 3, 2, buffer);
  } else if (timePeriod < 4000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 1, buffer);
  } else if (timePeriod < 40000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 0, buffer);
  } else { // Out of range
    dtostrf((float) 0.00, 3, 2, buffer);
  }
  tft.setCursor(15, 12+41+vTextShift);
  tft.print(buffer);
  if (voltageRange == 1) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-3.30");
  } else if (voltageRange == 2) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-1.65");
  } else if (voltageRange == 3) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-0.83");
  } 
  OlduseThreshold = useThreshold;                  
  OldtheThreshold = theThreshold;                
  OldtimePeriod = timePeriod;
  OldavgV = avgV;    
  OldmaxV = maxV;
  OldminV = minV;
  OldptopV = ptopV;
  OldtheFreq = theFreq;
}
 
void draw(void) {
  tft.fillScreen(ST7735_BLACK);
  drawT();
  draw1();
}

void draw1(void) {
  int i;
  if (useThreshold != 0)
     for (i=0; i<127; i+=3){
        tft.drawPixel(i,63-(theThreshold>>2),ST7735_YELLOW);
        tft.drawPixel(i,63,ST7735_YELLOW);
     }
  for (i=0; i<63; i+=5) {
     tft.drawPixel(32,i,ST7735_YELLOW);
     tft.drawPixel(64,i,ST7735_YELLOW);
     tft.drawPixel(96,i,ST7735_YELLOW);
     tft.drawPixel(127,i,ST7735_YELLOW);
  }
  tft.drawFastLine(1+(128-numOfSamples)-1,adcOldReadings[0],adcOldReadings[1]-adcOldReadings[0],2, ST7735_BLACK);
  for (i=1; i<numOfSamples-1; i++){ // Draw using lines
      tft.drawFastLine(i+(128-numOfSamples),adcOldReadings[i],adcOldReadings[i+1]-adcOldReadings[i],2, ST7735_BLACK);
      tft.drawFastLine(i+(128-numOfSamples)-1,adcReadings[i-1],adcReadings[i]-adcReadings[i-1],2, ST7735_WHITE);
      adcOldReadings[i-1]=adcReadings[i-1];
  }
  tft.drawFastLine(127+(128-numOfSamples)-1,adcReadings[126],adcReadings[127]-adcReadings[126],2, ST7735_WHITE);
  adcOldReadings[126]=adcReadings[126];
  adcOldReadings[127]=adcReadings[127];
}
 
void setup() {
  Serial.begin(9600);
  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST7735_BLACK); 
  // Turn on LED backlight
  analogWrite(3, ledBacklight);
   
  #if FASTADC
    // set prescale to 16
    sbi(ADCSRA,ADPS2) ;
    cbi(ADCSRA,ADPS1) ;
    cbi(ADCSRA,ADPS0) ;
  #endif
  delay(100);
  draw();
}

int j=8;
 
void loop() {
  
  collectData();
  draw1();
  drawD();
  if (j==100){
    drawT();
    j=0;
  }
  j++;
 
  // If user sends any serial data, show menu
  if (Serial.available() > 0) {
    handleSerial();
  }
 
  // rebuild the picture after some delay
  delay(100); //Можно убрать
}

Настройка "соединять линиями или отображать точками" полностью отключена, только линиями рисуем. На 3-м пине ШИМ, который я подключал не к дисплею (вообше шимом напрямую лучше дисплей не подсвечивать, а давать питание на дисплей напрямую от источника питания), а через резистор в несколько килоОм к пину ADC, теперь Если между ADC и землей поставить конденсатор на 0.1мкф, то на графике получается красивое сглаживание :)

P.s. Забрал сегодня с почты сенсорный дисплей. Прикольная штука, жаль, что немного поцарапаный оказался :(, причем НЕ нашей почтой, ибо упакован был так, что выдержал бы взрыв :), с другой стороны всего около 8 баксов с доставкой.

UPD. В дисплейчике для согласования уровней используется логика hc245. Поискал в продаже, окалось, достаточно дешевый чип и есть в наличии. Можно использовать :)

Immortal
Offline
Зарегистрирован: 28.12.2013

Спасибо, попробую на своем экранчике вечером. А в закомментированных фрагментах №2 и 3, что там за логика?

dtvims
Offline
Зарегистрирован: 26.11.2012

Это я не стал делать отрисовку текста, что меняется только от настроек

Immortal
Offline
Зарегистрирован: 28.12.2013

Мини осциллограф работает отлично. Т.к. я уже наигрался с ST7735 низкая частота обновления экрана не огорчила.

Чувствую, пора заказывать экран с параллельным интерфейсом и Stm32 дискавери или другую плату АРМом и быстрым АЦП

dtvims
Offline
Зарегистрирован: 26.11.2012

У экрана частота обновления супер, просто spi  у дуины медленный.

Immortal
Offline
Зарегистрирован: 28.12.2013

Определился с экраном - буду брать 2.8 Inch 240 x 320 ili9325 can connect any 16 bit data bus, подключать буду к ATmega128 через преобразователь уровней, шить через ISP ардуиной. С Stm32 дискавери решил повременить, я полный ноль в армах и Stm32.

Сложно будет переписать скетч под такой экран? (u8glib этот контроллер не поддерживает, придется перейти на UTFT)

 

dtvims
Offline
Зарегистрирован: 26.11.2012

Adafruit обычно имеет доп. библиотечки под конкретные моники, а если нет, то легко самому набрасать, библиотека очень простая. U8glib достаточно сложная в добавлении новых дисплеев, но тоже можно погуглить и возможно найти код и для нужного дисплея.

dtvims
Offline
Зарегистрирован: 26.11.2012

pooller пишет:

а на такой дисплей 2,4" TFT LCD Touch shield

возможно установить осциллограф? 

Времени мало в последнее время, но вот набросал кое что на скорую руку:

1. Скачал пример http://misc.ws/wp-content/uploads/2013/11/TFTLCD.zip, который сразу не пошел, была ошибка компиляции, но есть решение вот тут: http://forum.arduino.cc/index.php?topic=185924.msg1380185#msg1380185

2. переделал скетч, сделал сразу несколько доп. правок: Коррекция автомасштабирования, чтобы поменьше скакал график на стабильном сигнале; убрал явный программный мусор (остатки прошлого); Переменная numOfSamples является по сути шириной сетки осциллографа.

3. Есть бага: при некотором увеличении numOfSamples (например до 255) начинается свистопляска, судя по всему просто заканчивается оперативная память и массив выборки ADC начинает наезжать на стек.

4. Если все-равно памяти мало, то можно увеличивать ширину линий и размеры шрифтов, благо места навалом.

#define LCD_CS A3    
#define LCD_CD A2    
#define LCD_WR A1   
#define LCD_RD A0    
#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

#include "TFTLCD.h"
#include <EEPROM.h>

TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);


 
// Variables you might want to play with
byte useThreshold = 1;                  // 0 = Off, 1 = Rising, 2 = Falling
byte theThreshold = 128;                // 0-255, Multiplied by voltageConst
unsigned int timePeriod = 200;          // 0-65535, us or ms per measurement (max 0.065s or 65.535s)
byte voltageRange = 1;                  // 1 = 0-3.3V, 2 = 0-1.65V, 3 = 0-0.825V
byte ledBacklight = 100;
 
boolean autoHScale = true;             // Automatic horizontal (time) scaling
boolean linesNotDots = true;            // Draw lines between data points
 
// Variables that can probably be left alone
const byte vTextShift = 65;              // Vertical text shift (to vertically align info)
const byte numOfSamples = 170;          // Leave at 100 for 128x64 pixel display
unsigned int HQadcReadings[numOfSamples];
byte adcReadings[numOfSamples];
byte adcOldReadings[numOfSamples];
byte thresLocation = 0;                 // Threshold bar location
float voltageConst = 0.052381;          // Scaling factor for converting 0-63 to V
float avgV = 0.0;    
float maxV = 0.0;
float minV = 0.0;
float ptopV = 0.0;
float theFreq = 0;

byte OlduseThreshold = 1;                  
byte OldtheThreshold = 128;                
unsigned int OldtimePeriod = 200;
float OldavgV = 0.0;    
float OldmaxV = 0.0;
float OldminV = 0.0;
float OldptopV = 0.0;
float OldtheFreq = 0;
 
const byte theAnalogPin = 7;             // Data read pin


// High speed ADC code
// From: <a href="http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b0f36&topic=6549.15" title="http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b0f36&topic=6549.15" rel="nofollow">http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b...</a>
#define FASTADC 1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
 
void collectData(void) {
  unsigned int tempThres = 0;
  unsigned int i = 0;
 
  if (autoHScale == true) {
    // With automatic horizontal (time) scaling enabled,
    // scale quickly if the threshold location is far, then slow down
    if (thresLocation > 5*numOfSamples/8) {
      timePeriod = timePeriod + 10;
    } else if (thresLocation < 3*numOfSamples/8) {
      timePeriod = timePeriod - 10;
    } else if (thresLocation > numOfSamples/2+1) {
      timePeriod = timePeriod + 2;
    } else if (thresLocation < numOfSamples/2-1) {
      timePeriod = timePeriod - 2;
    }
  }
  // Enforce minimum time periods
  if (timePeriod < 35) {
    timePeriod = 35;
  }
   
  // Adjust voltage contstant to fit the voltage range
  if (voltageRange == 1) {
    voltageConst = 0.0523810; // 0-3.30V
  } else if (voltageRange == 2) {
    voltageConst = 0.0261905; // 0-1.65V
  } else if (voltageRange == 3) {
    voltageConst = 0.0130952; //0-0.825V
  }
   
  // If using threshold, wait until it has been reached
  if (voltageRange == 1) tempThres = theThreshold << 2;
  else if (voltageRange == 2) tempThres = theThreshold << 1;
  else if (voltageRange == 3) tempThres = theThreshold;
  if (useThreshold == 1) {
     i = 0; while ((analogRead(theAnalogPin)>tempThres) && (i<32768)) i++;
     i = 0; while ((analogRead(theAnalogPin)<tempThres) && (i<32768)) i++;
  }
  else if (useThreshold == 2) {
     i = 0; while ((analogRead(theAnalogPin)<tempThres) && (i<32768)) i++;
     i = 0; while ((analogRead(theAnalogPin)>tempThres) && (i<32768)) i++;
  }
 
  // Collect ADC readings
  for (i=0; i<numOfSamples; i++) {
    // Takes 35 us with high speed ADC setting
    HQadcReadings[i] = analogRead(theAnalogPin);
    if (timePeriod > 35)
      delayMicroseconds(timePeriod-35);
  }
  for (i=0; i<numOfSamples; i++) {
    // Scale the readings to 0-63 and clip to 63 if they are out of range.
    if (voltageRange == 1) {
      if (HQadcReadings[i]>>4 < 0b111111) adcReadings[i] = HQadcReadings[i]>>4 & 0b111111;
      else adcReadings[i] = 0b111111;
    } else if (voltageRange == 2) {
      if (HQadcReadings[i]>>3 < 0b111111) adcReadings[i] = HQadcReadings[i]>>3 & 0b111111;
      else adcReadings[i] = 0b111111;
    } else if (voltageRange == 3) {
      if (HQadcReadings[i]>>2 < 0b111111) adcReadings[i] = HQadcReadings[i]>>2 & 0b111111;
      else adcReadings[i] = 0b111111;
    }
    // Invert for display
    adcReadings[i] = 63-adcReadings[i];
  }
   
  // Calculate and display frequency of signal using zero crossing
  if (useThreshold != 0) {
     if (useThreshold == 1) {
        thresLocation = 1;
        while ((adcReadings[thresLocation]<(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
        thresLocation++;
        while ((adcReadings[thresLocation]>(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
     }
     else if (useThreshold == 2) {
        thresLocation = 1;
        while ((adcReadings[thresLocation]>(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
        thresLocation++;
        while ((adcReadings[thresLocation]<(63-(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
     }
 
     theFreq = (float) 1000/(thresLocation * timePeriod) * 1000;
  }
   
  // Average Voltage
  avgV = 0;
  for (i=0; i<numOfSamples; i++)
     avgV = avgV + adcReadings[i];
  avgV = (63-(avgV / numOfSamples)) * voltageConst;
 
  // Maximum Voltage
  maxV = 63;
  for (i=0; i<numOfSamples; i++)
     if (adcReadings[i]<maxV) maxV = adcReadings[i];
  maxV = (63-maxV) * voltageConst;
 
  // Minimum Voltage
  minV = 0;
  for (i=0; i<numOfSamples; i++)
     if (adcReadings[i]>minV) minV = adcReadings[i];
  minV = (63-minV) * voltageConst;
 
  // Peak-to-Peak Voltage
  ptopV = maxV - minV;
}
 
void handleSerial(void) {
  char inByte;
  char dataByte;
  boolean exitLoop = false;
  do {
    // Clear out buffer
    do {
      inByte = Serial.read();
    } while (Serial.available() > 0);
   
    Serial.print("\nArduino LCD Oscilloscope\n");
    Serial.print(" 1 - Change threshold usage (currently: ");
      if (useThreshold == 0) Serial.print("Off)\n");
      else if (useThreshold == 1) Serial.print("Rise)\n");
      else if (useThreshold == 2) Serial.print("Fall)\n");
    Serial.print(" 2 - Change threshold value (currently: ");
      Serial.print(theThreshold, DEC); Serial.print(")\n");
    Serial.print(" 3 - Change sampling period (currently: ");
      Serial.print(timePeriod, DEC); Serial.print(")\n");
    Serial.print(" 4 - Change voltage range (currently: ");
      if (voltageRange == 1) Serial.print("0-3.3V)\n");
      else if (voltageRange == 2) Serial.print("0-1.65V)\n");
      else if (voltageRange == 3) Serial.print("0-0.825V)\n");
    Serial.print(" 5 - Toggle auto horizontal (time) scaling (currently: ");
      if (autoHScale == true) Serial.print("On)\n");
      else if (autoHScale == false) Serial.print("Off)\n");
    Serial.print(" 8 - Exit\n");
     
    // Wait for input/response, refresh display while in menu
    do {
      collectData();
      draw1();
    } while (Serial.available() == 0);
    inByte = Serial.read();
     
    if (inByte == '1') {
      Serial.print("Change threshold usage\n");
      Serial.print(" 0 - Off\n");
      Serial.print(" 1 - Rise\n");
      Serial.print(" 2 - Fall\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') useThreshold = 0;
      else if (dataByte == '1') useThreshold = 1;
      else if (dataByte == '2') useThreshold = 2;
    } else if (inByte == '2') {
      Serial.print("Change threshold value (thresholds for 0-3.3V,0-1.65V,0-0.825V ranges)\n");
      Serial.print(" 0 - 32 (0.41V, 0.21V, 0.10V)\n");
      Serial.print(" 1 - 80 (1.04V, 0.52V, 0.26V)\n");
      Serial.print(" 2 - 128 (1.66V, 0.83V, 0.41V)\n");
      Serial.print(" 3 - 176 (2.28V, 1.14V, 0.57V)\n");
      Serial.print(" 4 - 224 (2.90V, 1.45V, 0.72V)\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') theThreshold = 32;
      else if (dataByte == '1') theThreshold = 80;
      else if (dataByte == '2') theThreshold = 128;
      else if (dataByte == '3') theThreshold = 176;
      else if (dataByte == '4') theThreshold = 224;
    } else if (inByte == '3') {
      Serial.print("Change sampling frequency\n");
      Serial.print(" 0 - 28 kHz (35 us/sample)\n");
      Serial.print(" 1 - 20 kHz (50 us/sample)\n");
      Serial.print(" 2 - 10 kHz (100 us/sample)\n");
      Serial.print(" 3 - 5 kHz (200 us/sample)\n");
      Serial.print(" 4 - 2.5 kHz (400 us/sample)\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') timePeriod = 35;
      else if (dataByte == '1') timePeriod = 50;
      else if (dataByte == '2') timePeriod = 100;
      else if (dataByte == '3') timePeriod = 200;
      else if (dataByte == '4') timePeriod = 400;
    } else if (inByte == '4') {
      Serial.print("Change voltage range\n");
      Serial.print(" 1 - 0-3.3V\n");
      Serial.print(" 2 - 0-1.65V\n");
      Serial.print(" 3 - 0-0.825V\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '1') voltageRange = 1;
      else if (dataByte == '2') voltageRange = 2;
      else if (dataByte == '3') voltageRange = 3;
    } else if (inByte == '5') {
      Serial.print("Toggle auto horizontal (time) scaling\n");
      Serial.print(" 0 - Off\n");
      Serial.print(" 1 - On\n");
      do { } while (Serial.available() == 0);
      dataByte = Serial.read();
      if (dataByte == '0') autoHScale = false;
      else if (dataByte == '1') autoHScale = true;
    } else if (inByte == '8') {
      Serial.print("Bye!\n");
      exitLoop = true;
    }
    draw();
  } while (exitLoop == false);
}

void drawD(void) {
  char buffer[16];
  if(avgV!=OldavgV){
    tft.setTextColor(BLACK);
    dtostrf(OldavgV, 3, 2, buffer);
    tft.setCursor(15, 5+vTextShift);
    tft.print(buffer);
    tft.setTextColor(RED);
    dtostrf(avgV, 3, 2, buffer);
    tft.setCursor(15, 5+vTextShift);
    tft.print(buffer);
    OldavgV=avgV;
  }
  if(maxV!=OldmaxV){
    tft.setTextColor(BLACK);
    dtostrf(OldmaxV, 3, 2, buffer);
    tft.setCursor(15, 2+11+vTextShift);
    tft.print(buffer);
    tft.setTextColor(RED);
    dtostrf(maxV, 3, 2, buffer);
    tft.setCursor(15, 2+11+vTextShift);
    tft.print(buffer);
    OldmaxV=maxV;
  }
  if(minV!=OldminV){
    tft.setTextColor(BLACK);
    dtostrf(OldminV, 3, 2, buffer);
    tft.setCursor(15, 4+17+vTextShift);
    tft.print(buffer);
    tft.setTextColor(RED);
    dtostrf(minV, 3, 2, buffer);
    tft.setCursor(15, 4+17+vTextShift);
    tft.print(buffer);
    OldminV=minV;
  }
  if(ptopV!=OldptopV){  
    tft.setTextColor(BLACK);
    dtostrf(OldptopV, 3, 2, buffer);
    tft.setCursor(15, 6+23+vTextShift);
    tft.print(buffer);
    tft.setTextColor(RED);
    dtostrf(ptopV, 3, 2, buffer);
    tft.setCursor(15, 6+23+vTextShift);
    tft.print(buffer);
    OldptopV=ptopV;
  }
  if(theFreq!=OldtheFreq){
    tft.setTextColor(BLACK);
    dtostrf(OldtheFreq, 5, 0, buffer);
    tft.setCursor(0, 16+53+vTextShift);
    tft.print(buffer);
    tft.setTextColor(RED);
    dtostrf(theFreq, 5, 0, buffer);
    tft.setCursor(0, 16+53+vTextShift);
    tft.print(buffer);
    OldtheFreq=theFreq;
  }
  /*if (useThreshold == 0) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Off");
  } else if (useThreshold == 1) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Rise");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  } else if (useThreshold == 2) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Fall");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  }
  tft.setCursor(11, 10+35+vTextShift);
  tft.print(buffer);*/
  // Correctly format the text so that there are always 4 characters
if(timePeriod!=OldtimePeriod){
  tft.setTextColor(BLACK);
  if (OldtimePeriod < 400) {
    dtostrf((float) OldtimePeriod/1000 * 25, 3, 2, buffer);
  } else if (OldtimePeriod < 4000) {
    dtostrf((float) OldtimePeriod/1000 * 25, 3, 1, buffer);
  } else if (OldtimePeriod < 40000) {
    dtostrf((float) OldtimePeriod/1000 * 25, 3, 0, buffer);
  } else { // Out of range
    dtostrf((float) 0.00, 3, 2, buffer);
  }
  tft.setCursor(15, 12+41+vTextShift);
  tft.print(buffer);
  
  tft.setTextColor(RED);
  if (timePeriod < 400) {
    dtostrf((float) timePeriod/1000 * 25, 3, 2, buffer);
  } else if (timePeriod < 4000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 1, buffer);
  } else if (timePeriod < 40000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 0, buffer);
  } else { // Out of range
    dtostrf((float) 0.00, 3, 2, buffer);
  }
  tft.setCursor(15, 12+41+vTextShift);
  tft.print(buffer);
  OldtimePeriod=timePeriod;
}
  /*if (voltageRange == 1) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-3.30");
  } else if (voltageRange == 2) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-1.65");
  } else if (voltageRange == 3) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-0.83");
  } */
}
void drawT(void) {
  char buffer[16];
  tft.fillRect(0,vTextShift+5,45,150,BLACK);
  tft.setTextColor(RED);
  tft.setTextSize(1);
  tft.setCursor(0, 5+vTextShift);
  tft.print("Av");
  tft.setCursor(0, 2+11+vTextShift);
  tft.print("Mx");
  tft.setCursor(0, 4+17+vTextShift);
  tft.print("Mn");
  tft.setCursor(0, 6+23+vTextShift);
  tft.print("PP");
  tft.setCursor(0, 8+29+vTextShift);
  tft.print("Th");
  tft.setCursor(0, 10+35+vTextShift);
  tft.print("V");
  tft.setCursor(0, 12+41+vTextShift);
  tft.print("Tm");
  tft.setCursor(4, 14+47+vTextShift);
  tft.print("ms/div");
  tft.setCursor(31, 16+53+vTextShift);
  tft.print("Hz");
  tft.setCursor(0, 18+59+vTextShift);
  tft.print("R");
 
  // Draw dynamic text
  if (autoHScale == true) {
    tft.setCursor(120, 2);
    tft.print("A");
  }
  dtostrf(avgV, 3, 2, buffer);
  tft.setCursor(15, 5+vTextShift);
  tft.print(buffer);

  dtostrf(maxV, 3, 2, buffer);
  tft.setCursor(15, 2+11+vTextShift);
  tft.print(buffer);

  dtostrf(minV, 3, 2, buffer);
  tft.setCursor(15, 4+17+vTextShift);
  tft.print(buffer);

  dtostrf(ptopV, 3, 2, buffer);
  tft.setCursor(15, 6+23+vTextShift);
  tft.print(buffer);

  dtostrf(theFreq, 5, 0, buffer);
  tft.setCursor(0, 16+53+vTextShift);
  tft.print(buffer);

  if (useThreshold == 0) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Off");
  } else if (useThreshold == 1) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Rise");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  } else if (useThreshold == 2) {
    tft.setCursor(15, 8+29+vTextShift);
    tft.print("Fall");
    dtostrf((float) (theThreshold>>2) * voltageConst, 3, 2, buffer);
  }
  tft.setCursor(11, 10+35+vTextShift);
  tft.print(buffer);
  // Correctly format the text so that there are always 4 characters
  if (timePeriod < 400) {
    dtostrf((float) timePeriod/1000 * 25, 3, 2, buffer);
  } else if (timePeriod < 4000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 1, buffer);
  } else if (timePeriod < 40000) {
    dtostrf((float) timePeriod/1000 * 25, 3, 0, buffer);
  } else { // Out of range
    dtostrf((float) 0.00, 3, 2, buffer);
  }
  tft.setCursor(15, 12+41+vTextShift);
  tft.print(buffer);
  if (voltageRange == 1) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-3.30");
  } else if (voltageRange == 2) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-1.65");
  } else if (voltageRange == 3) {
    tft.setCursor(7, 18+59+vTextShift);
    tft.print("0-0.83");
  } 
  OlduseThreshold = useThreshold;                  
  OldtheThreshold = theThreshold;                
  OldtimePeriod = timePeriod;
  OldavgV = avgV;    
  OldmaxV = maxV;
  OldminV = minV;
  OldptopV = ptopV;
  OldtheFreq = theFreq;
}
 
void draw(void) {
  tft.fillScreen(BLACK);
  drawT();
  draw1();
}

void draw1(void) {
  int i,j;
//  tft.drawFastVLine((128-numOfSamples), 0, 63, ST7735_YELLOW);
  if (useThreshold != 0)
     for (i=0; i<numOfSamples; i+=3){
        tft.drawPixel(i,63-(theThreshold>>2),YELLOW);
        tft.drawPixel(i,63,YELLOW);
     }
  j=numOfSamples/4;
  for (i=0; i<63; i+=5) {
     tft.drawPixel(0,i,YELLOW);
     tft.drawPixel(j,i,YELLOW);
     tft.drawPixel(j+j,i,YELLOW);
     tft.drawPixel(j+j+j,i,YELLOW);
     tft.drawPixel(numOfSamples-1,i,YELLOW);
  }
  tft.drawLine(0,adcOldReadings[0],1,adcOldReadings[1], BLACK);
  for (i=1; i<numOfSamples-1; i++){ // Draw using lines
      tft.drawLine(i,adcOldReadings[i],i+1,adcOldReadings[i+1], BLACK);
      tft.drawLine(i-1,adcReadings[i-1],i,adcReadings[i], WHITE);
      adcOldReadings[i-1]=adcReadings[i-1];
  }
  tft.drawLine(numOfSamples-2,adcReadings[numOfSamples-2],i,adcReadings[numOfSamples-1], WHITE);
  adcOldReadings[numOfSamples-2]=adcReadings[numOfSamples-2];
  adcOldReadings[numOfSamples-1]=adcReadings[numOfSamples-1];
}
 
void setup() {
  Serial.begin(9600);
  tft.reset();
  tft.initDisplay();
  tft.setRotation(1);
  tft.fillScreen(BLACK); 
  // Turn on LED backlight
  //analogWrite(3, ledBacklight);
   
  #if FASTADC
    // set prescale to 16
    sbi(ADCSRA,ADPS2) ;
    cbi(ADCSRA,ADPS1) ;
    cbi(ADCSRA,ADPS0) ;
  #endif
  delay(100);
  draw();
}

int j=8;
 
void loop() {
  
  collectData();
  draw1();
  drawD();
  if (j==100){
    drawT();
    j=0;
  }
  j++;
 
  // If user sends any serial data, show menu
  if (Serial.available() > 0) {
    handleSerial();
  }
 
  // rebuild the picture after some delay
  delay(100);
}

На картинке наводка 50hz