Last active
August 29, 2015 14:17
-
-
Save OrganicIrradiation/e8cda31673fc12509fd0 to your computer and use it in GitHub Desktop.
Arduino FIO 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
void setup() { | |
pinMode(2, OUTPUT); | |
pinMode(3, OUTPUT); | |
pinMode(4, OUTPUT); | |
pinMode(5, OUTPUT); | |
pinMode(6, OUTPUT); | |
pinMode(7, OUTPUT); | |
pinMode(8, OUTPUT); | |
pinMode(9, OUTPUT); | |
pinMode(10, OUTPUT); | |
pinMode(11, OUTPUT); | |
pinMode(12, OUTPUT); | |
pinMode(13, OUTPUT); | |
} | |
int i = 0; | |
void loop() { | |
digitalWrite(2, bitRead(i, 0)); | |
digitalWrite(3, bitRead(i, 1)); | |
digitalWrite(4, bitRead(i, 2)); | |
digitalWrite(5, bitRead(i, 3)); | |
digitalWrite(6, bitRead(i, 4)); | |
digitalWrite(7, bitRead(i, 5)); | |
digitalWrite(8, bitRead(i, 6)); | |
digitalWrite(9, bitRead(i, 7)); | |
digitalWrite(10, bitRead(i, 8)); | |
digitalWrite(11, bitRead(i, 9)); | |
digitalWrite(12, bitRead(i, 10)); | |
digitalWrite(13, bitRead(i, 11)); | |
i++; | |
if (i >= 4096) { | |
i = 0; | |
} | |
} |
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" | |
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); | |
void draw(void) { | |
// graphic commands to redraw the complete screen should be placed here | |
u8g.setFont(u8g_font_micro); | |
u8g.drawStr( 0, 20, "Hello World!"); | |
} | |
void setup() { | |
u8g.begin(); | |
} | |
void loop() { | |
// picture loop | |
u8g.firstPage(); | |
do { | |
draw(); | |
} while( u8g.nextPage() ); | |
// rebuild the picture after some delay | |
delay(1000); | |
} |
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 | |
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_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; | |
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 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++; | |
} | |
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); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment