Skip to content

Instantly share code, notes, and snippets.

@OrganicIrradiation
Created March 23, 2015 09:56
Show Gist options
  • Save OrganicIrradiation/e6cc9f132bc17ab97243 to your computer and use it in GitHub Desktop.
Save OrganicIrradiation/e6cc9f132bc17ab97243 to your computer and use it in GitHub Desktop.
Arduino FIO 2 Channel LCD Oscilloscope
#include "U8glib.h"
#include <EEPROM.h>
// Variables you might want to play with
unsigned int timePeriod = 65; // 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 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 HQadcReadingsA[numOfSamples];
unsigned int HQadcReadingsB[numOfSamples];
byte adcReadingsA[numOfSamples];
byte adcReadingsB[numOfSamples];
float voltageConst = 0.052381; // Scaling factor for converting 0-63 to V
float avgVA = 0.0;
float maxVA = 0.0;
float minVA = 0.0;
float ptopVA = 0.0;
float avgVB = 0.0;
float maxVB = 0.0;
float minVB = 0.0;
float ptopVB = 0.0;
const byte theAnalogPinA = 7; // Data read pin, channel A
const byte theAnalogPinB = 6; // Data read pin, channel B
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_2X u8g(lcdSCK, lcdMOSI, lcdCS, lcdA0, lcdRESET);
// HW SPI:
U8GLIB_MINI12864_2X u8g(lcdCS, lcdA0, lcdRESET);
// 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;
// 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
}
// Collect ADC readings
for (i=0; i<numOfSamples; i++) {
// Takes 35 us with high speed ADC setting
HQadcReadingsA[i] = analogRead(theAnalogPinA);
HQadcReadingsB[i] = analogRead(theAnalogPinB);
if (timePeriod > 65)
delayMicroseconds(timePeriod-65);
}
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 (HQadcReadingsA[i]>>4 < 0b111111) adcReadingsA[i] = HQadcReadingsA[i]>>4 & 0b111111;
else adcReadingsA[i] = 0b111111;
if (HQadcReadingsB[i]>>4 < 0b111111) adcReadingsB[i] = HQadcReadingsB[i]>>4 & 0b111111;
else adcReadingsB[i] = 0b111111;
} else if (voltageRange == 2) {
if (HQadcReadingsA[i]>>3 < 0b111111) adcReadingsA[i] = HQadcReadingsA[i]>>3 & 0b111111;
else adcReadingsA[i] = 0b111111;
if (HQadcReadingsB[i]>>3 < 0b111111) adcReadingsB[i] = HQadcReadingsB[i]>>3 & 0b111111;
else adcReadingsB[i] = 0b111111;
} else if (voltageRange == 3) {
if (HQadcReadingsA[i]>>2 < 0b111111) adcReadingsA[i] = HQadcReadingsA[i]>>2 & 0b111111;
else adcReadingsA[i] = 0b111111;
if (HQadcReadingsB[i]>>2 < 0b111111) adcReadingsB[i] = HQadcReadingsB[i]>>2 & 0b111111;
else adcReadingsB[i] = 0b111111;
}
}
// Average Voltage
avgVA = 0;
for (i=0; i<numOfSamples; i++)
avgVA = avgVA + adcReadingsA[i];
avgVA = (avgVA / numOfSamples) * voltageConst;
avgVB = 0;
for (i=0; i<numOfSamples; i++)
avgVB = avgVB + adcReadingsB[i];
avgVB = (avgVB / numOfSamples) * voltageConst;
// Maximum Voltage
maxVA = 0;
for (i=0; i<numOfSamples; i++)
if (adcReadingsA[i]>maxVA) maxVA = adcReadingsA[i];
maxVA = maxVA * voltageConst;
maxVB = 0;
for (i=0; i<numOfSamples; i++)
if (adcReadingsB[i]>maxVB) maxVB = adcReadingsB[i];
maxVB = maxVB * voltageConst;
// Minimum Voltage
minVA = 63;
for (i=0; i<numOfSamples; i++)
if (adcReadingsA[i]<minVA) minVA = adcReadingsA[i];
minVA = minVA * voltageConst;
minVB = 63;
for (i=0; i<numOfSamples; i++)
if (adcReadingsB[i]<minVB) minVB = adcReadingsB[i];
minVB = minVB * voltageConst;
// Peak-to-Peak Voltage
ptopVA = maxVA - minVA;
ptopVB = maxVB - minVB;
}
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 sampling period (currently: ");
Serial.print(timePeriod, DEC); Serial.print(")\n");
Serial.print(" 2 - 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(" 3 - 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 sampling frequency\n");
Serial.print(" 0 - 15.4 kHz (65 us/sample)\n");
Serial.print(" 1 - 10 kHz (100 us/sample)\n");
Serial.print(" 2 - 5 kHz (200 us/sample)\n");
Serial.print(" 3 - 2.5 kHz (400 us/sample)\n");
Serial.print(" 4 - 1.25 kHz (800 us/sample)\n");
do { } while (Serial.available() == 0);
dataByte = Serial.read();
if (dataByte == '0') timePeriod = 65;
else if (dataByte == '1') timePeriod = 100;
else if (dataByte == '2') timePeriod = 200;
else if (dataByte == '3') timePeriod = 400;
else if (dataByte == '4') timePeriod = 800;
} else if (inByte == '2') {
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 == '3') {
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, "AveA");
u8g.drawStr(0, 11+vTextShift, "MaxA");
u8g.drawStr(0, 17+vTextShift, "MinA");
u8g.drawStr(0, 23+vTextShift, "P2PA");
u8g.drawStr(0, 29+vTextShift, "AveB");
u8g.drawStr(0, 35+vTextShift, "MaxB");
u8g.drawStr(0, 41+vTextShift, "MinB");
u8g.drawStr(0, 47+vTextShift, "P2PB");
u8g.drawStr(0, 53+vTextShift, "Tm");
u8g.drawStr(0, 59+vTextShift, "R");
// Draw dynamic text
dtostrf(avgVA, 3, 2, buffer);
u8g.drawStr(20, 5+vTextShift, buffer);
dtostrf(maxVA, 3, 2, buffer);
u8g.drawStr(20, 11+vTextShift, buffer);
dtostrf(minVA, 3, 2, buffer);
u8g.drawStr(20, 17+vTextShift, buffer);
dtostrf(ptopVA, 3, 2, buffer);
u8g.drawStr(20, 23+vTextShift, buffer);
dtostrf(avgVB, 3, 2, buffer);
u8g.drawStr(20, 29+vTextShift, buffer);
dtostrf(maxVB, 3, 2, buffer);
u8g.drawStr(20, 35+vTextShift, buffer);
dtostrf(minVB, 3, 2, buffer);
u8g.drawStr(20, 41+vTextShift, buffer);
dtostrf(ptopVB, 3, 2, buffer);
u8g.drawStr(20, 47+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(20, 53+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(36,0,36,63);
for (i=0; i<63; i+=5) {
u8g.drawPixel(82,i);
}
for (i=0; i<91; i+=5) {
u8g.drawPixel(i+36,32);
}
// Draw ADC readings
if (linesNotDots == true) {
for (i=1; i<numOfSamples; i++) {// Draw using lines
u8g.drawLine(adcReadingsA[i-1]+46,63-adcReadingsB[i-1],
adcReadingsA[i]+46,63-adcReadingsB[i]);
}
} else {
for (i=2; i<numOfSamples; i++) {// Draw using points
u8g.drawPixel(adcReadingsA[i]+46,63-adcReadingsB[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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment