Created
March 23, 2015 09:56
-
-
Save OrganicIrradiation/e6cc9f132bc17ab97243 to your computer and use it in GitHub Desktop.
Arduino FIO 2 Channel LCD Oscilloscope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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