#include "U8glib.h" #include // Variables you might want to play with byte useThreshold = 1; // 0 = Off, 1 = Rising, 2 = Falling byte theThreshold = 128; // 0-255, Multiplied by voltageConst byte theThHuck = 2; // Переменная для установки theThreshold unsigned int timePeriod = 200; // 0-65535, us or ms per measurement (max 0.065s or 65.535s) byte timePerHuck = 3; // Переменная для установки timePeriod byte voltageRange = 1; // 1 = 0-3.3V, 2 = 0-1.65V, 3 = 0-0.825V int pos = 0; // Position begin boolean infoMode = true; // Включение/отключение режима показывания информации boolean autoHScale = true; // Automatic horizontal (time) scaling // 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 = A6; // Data read pin int btnPin = 7; // кнопка переключения режима INFO int tUsagePin = 8; // кнопка переключения режима threshold usage int tValuePin = 9; // кнопка переключения режима threshold value int timePerPin = 10; // кнопка переключения временного периода int vRangePin = 11; // кнопка переключения voltage range int autoHSPin = 12; // кнопка переключения auto horizontal scaling U8GLIB_PCF8812 u8g(2, 3, 5, 4, 6); // High speed ADC code // From: http://forum.arduino.cc/index.php?PHPSESSID=e21f9a71b887039092c91a516f9b0f36&topic=6549.15 #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 < 10) { timePeriod = 10; } // Adjust voltage constant 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++; } // Collect ADC readings for (i=0; i 10) delayMicroseconds(timePeriod-10); // Scale the readings to 0-63 and clip to 63 if they are out of range. // Шкала показаний 0-63 и клип 63, если они находятся вне диапазона. 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]-pos; 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(63-(theThreshold>>2))) && (thresLocation(63-(theThreshold>>2))) && (thresLocation>2))) && (thresLocationminV) minV = adcReadings[i]; minV = (63-minV) * voltageConst; // Peak-to-Peak Voltage ptopV = maxV - minV; } //-------------------------------------------------------------- void draw_empty(void) { int i; char buffer[16]; u8g.setFont(u8g_font_micro); // Draw dynamic text if (autoHScale == true) u8g.drawStr(93, 5, "A"); // Display graph lines u8g.drawLine((96-numOfSamples),0,(96-numOfSamples),65); if (useThreshold != 0) for (i=0; i<96; i+=3) u8g.drawPixel(i,63-(theThreshold>>2)); for (i=2; i<=65; i+=5) { u8g.drawPixel(24,i); u8g.drawPixel(49,i); u8g.drawPixel(74,i); u8g.drawPixel(96,i); } // Threshold bar for (i=0; i<65; i+=3) u8g.drawPixel(thresLocation+(0),i); // Draw ADC readings for (i=1; i<96; i++) {// Draw using lines for 3410 // pos=pos+i; u8g.drawLine(i-1,adcReadings[i-1],i,adcReadings[i]); } } //========================================================== 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(93, 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 for (i=1; i<68; i++) { // Draw using lines for 3410 u8g.drawLine(i+(128-numOfSamples)-1,adcReadings[i-1],i+(128-numOfSamples),adcReadings[i]); } } //-------------------------------------------------------------- void setup() { u8g.begin(); pinMode(btnPin, INPUT); // кнопка [2] INFO tValuePin pinMode(tUsagePin, INPUT); // кнопка [8] useThreshold pinMode(tValuePin, INPUT); // кнопка [9] theThreshold, theThHuck pinMode(timePerPin, INPUT); // кнопка [10] timePeriod, timePerHuck pinMode(vRangePin, INPUT); // кнопка [11] voltageRange pinMode(autoHSPin, INPUT); // кнопка [12] autoHScale #if FASTADC // set prescale to 16 sbi(ADCSRA,ADPS2) ; cbi(ADCSRA,ADPS1) ; cbi(ADCSRA,ADPS0) ; #endif u8g.firstPage(); do { u8g.setFont(u8g_font_6x12); u8g.drawStr(0, 25, "Oscilloscope"); u8g.setFont(u8g_font_courB08); u8g.drawStr(72, 18, "nano"); u8g.setFont(u8g_font_7x14B); u8g.drawStr(3, 45, "best-chart.ru"); } while( u8g.nextPage() ); delay(1000); } void loop() { collectData(); // Picture Display Loop u8g.firstPage(); if (digitalRead(btnPin)== HIGH) // кнопка [7] INFO mode { if (infoMode == true) { infoMode = false; } else { infoMode = true; } } if (digitalRead(tUsagePin)== HIGH) { // кнопка [8] threshold usage useThreshold++; do { u8g.setFont(u8g_font_6x12); u8g.drawStr(1, 20, "Threshold usage:"); u8g.setFont(u8g_font_7x14B); if (useThreshold>=3) { useThreshold=0; } if (useThreshold == 0) u8g.drawStr(30, 40, "Off"); else if (useThreshold == 1) u8g.drawStr(30, 40, "Rise"); else if (useThreshold == 2) u8g.drawStr(30, 40, "Fall"); } while( u8g.nextPage() ); delay(500); } if (digitalRead(tValuePin)== HIGH) { // кнопка [9] threshold value theThHuck++; do { u8g.setFont(u8g_font_6x12); u8g.drawStr(1, 20, "Threshold value:"); u8g.setFont(u8g_font_courB08); if (theThHuck>=5) theThHuck=0; //u8g.setPrintPos(12,8); //u8g.print(theThHuck); if (theThHuck == 0) { theThreshold=32; u8g.drawStr(1, 40, "0.41v 0.21v 0.10v"); } else if (theThHuck == 1) { theThreshold=80; u8g.drawStr(1, 40, "1.04V 0.52v 0.26v"); } else if (theThHuck == 2) { theThreshold=128; u8g.drawStr(1, 40, "1.66v 0.83v 0.41v"); } else if (theThHuck == 3) { theThreshold=176; u8g.drawStr(1, 40, "2.28v 1.14v 0.57v"); } else if (theThHuck == 4) { theThreshold=224; u8g.drawStr(1, 40, "2.90v 1.45v 0.72v"); } } while( u8g.nextPage() ); delay(500); } if (digitalRead(timePerPin)== HIGH) { // кнопка [10] sampling frequency timePerHuck++; do { u8g.setFont(u8g_font_6x12); u8g.drawStr(5, 20, "Sampling freq:"); u8g.setFont(u8g_font_courB08); if (timePerHuck>=5) timePerHuck=0; if (timePerHuck == 0) { timePeriod = 400; u8g.drawStr(10, 40, "400 us/sample"); } else if (timePerHuck == 1) { timePeriod = 200; u8g.drawStr(10, 40, "200 us/sample"); } else if (timePerHuck == 2) { timePeriod = 100; u8g.drawStr(10, 40, "100 us/sample"); } else if (timePerHuck == 3) { timePeriod = 50; u8g.drawStr(10, 40, "50 us/sample"); } else if (timePerHuck == 4) { timePeriod = 10; u8g.drawStr(10, 40, "10 us/sample"); } } while( u8g.nextPage() ); delay(500); } if (digitalRead(vRangePin)== HIGH) { // кнопка [11] voltage range voltageRange++; do { u8g.setFont(u8g_font_6x12); u8g.drawStr(7, 20, "Voltage range:"); u8g.setFont(u8g_font_7x14B); if (voltageRange>=4) { voltageRange=1; } if (voltageRange == 1) u8g.drawStr(25, 40, "0-3.3v"); else if (voltageRange == 2) u8g.drawStr(25, 40, "0-1.65v"); else if (voltageRange == 3) u8g.drawStr(25, 40, "0-0.825v"); } while( u8g.nextPage() ); delay(500); } if (digitalRead(autoHSPin)== HIGH) { // кнопка [12] auto horizontal scaling do { u8g.setFont(u8g_font_6x12); u8g.drawStr(0, 20, "Auto time scaling:"); u8g.setFont(u8g_font_7x14B); if (autoHScale == true) { autoHScale = false; u8g.drawStr(30, 40, "Off"); } else { autoHScale = true; u8g.drawStr(30, 40, "On"); } } while( u8g.nextPage() ); delay(500); } if (infoMode == true) { do { draw(); } while( u8g.nextPage() ); } else { do { draw_empty(); } while( u8g.nextPage() ); } // rebuild the picture after some delay delay(100); }