Ardino Uno Code
Ardino Uno Code
h>
#include <Adafruit_GFX.h>
//#include
<Adafruit_SSD1306.h>
#include <Adafruit_SH1106.h> //
https://github.com/wonho-maker/Adafruit_SH1106
#include <EEPROM.h>
#define
SCREEN_WIDTH 128 // OLED display width
#define SCREEN_HEIGHT 64
// OLED display height
#define REC_LENG 200 // size of wave data
buffer
#define MIN_TRIG_SWING 5 // minimum trigger swing.(Display
"Unsync" if swing smaller than this value
float
waveFreq; // frequency (Hz)
float waveDuty; // duty ratio
(%)
void setup() {
pinMode(2, INPUT_PULLUP); // button pussed interrupt
(int.0 IRQ)
pinMode(8, INPUT_PULLUP); // Select button
pinMode(9,
INPUT_PULLUP); // Up
pinMode(10, INPUT_PULLUP); // Down
//
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C) { // select 3C or 3D (set your OLED I2C address)
auxFunctions();
// Voltage measure (never return)
loadEEPROM(); // read
last settings from EEPROM
analogReference(INTERNAL); // ADC full scale = 1.1V
void loop() {
setConditions();
// set measurment conditions
digitalWrite(13, HIGH); // flash LED
dispHold();
delay(10);
} // loop cycle speed =
60-470ms (buffer size = 200)
}
switch (vRange) {
// setting of Vrange
case 0: { // Auto50V range
break;
}
case 2: { // 50V range
rangeMax = 50 / lsb50V;
// set full scale pixcel count number
rangeMaxDisp = 5000; // vartical scale
(set100x value)
rangeMin = 0;
rangeMinDisp = 0;
att10x = 1;
// use input attenuator
break;
}
case 3: { // 20V
range
rangeMax = 20 / lsb50V; // set full scale pixcel count number
rangeMaxDisp = 2000;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 1;
// use input attenuator
break;
}
case 4: { //
10V range
rangeMax = 10 / lsb50V; // set full scale pixcel count number
rangeMaxDisp = 1000;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 1;
// use input attenuator
break;
}
case 5: { //
5V range
rangeMax = 5 / lsb5V; // set full scale pixcel count number
rangeMaxDisp = 500;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0;
// no input attenuator
break;
}
case 6: { // 2V
range
rangeMax = 2 / lsb5V; // set full scale pixcel count number
rangeMaxDisp = 200;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0;
// no input attenuator
break;
}
case 7: { // 1V
range
rangeMax = 1 / lsb5V; // set full scale pixcel count number
rangeMaxDisp = 100;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0;
// no input attenuator
break;
}
case 8: { //
0.5V range
rangeMax = 0.5 / lsb5V; // set full scale pixcel count number
rangeMaxDisp = 50;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0;
// no input attenuator
break;
}
case 9: { //
0.5V range
rangeMax = 0.2 / lsb5V; // set full scale pixcel count number
rangeMaxDisp = 20;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0;
// no input attenuator
break;
}
}
}
void writeCommonImage() {
// Common screen image drawing
oled.clearDisplay(); // erase
all(0.4ms)
oled.setTextColor(WHITE); // write in white character
oled.drawFastHLine(51, 9, 3,
WHITE); // Max value auxiliary mark
oled.drawFastHLine(51, 63, 3, WHITE);
void readWave() {
// Record waveform to memory array
if (att10x == 1) { // if 1/10
attenuator required
pinMode(12, OUTPUT); // assign attenuator controle
pin to OUTPUT,
digitalWrite(12, LOW); // and output LOW (output 0V)
}
else { // if not required
pinMode(12, INPUT);
// assign the pin input (Hi-z)
}
switchPushed = false; //
Clear switch operation flag
break;
}
case 1: { // 100ms range
timeExec
= 800 + 60; // Approximate execution time(ms) Used for countdown until saving
to EEPROM
ADCSRA = ADCSRA & 0xf8; // clear bottom 3bit
switchPushed = false;
break; // abandon record(this
improve response)
}
}
break;
}
case 2: {
// 50ms range
timeExec = 400 + 60; // Approximate
execution time(ms)
ADCSRA = ADCSRA & 0xf8; // clear bottom 3bit
}
break;
}
case 3: { // 20ms range
}
case 6: { // 2ms range
timeExec = 16 + 60;
// Approximate execution time(ms)
ADCSRA = ADCSRA & 0xf8;
// clear bottom 3bit
ADCSRA = ADCSRA | 0x06; // dividing ratio = 64
(0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128)
for (int i = 0; i <
REC_LENG; i++) { // up to rec buffer size
waveBuff[i] = analogRead(0); // read
and save approx 56us
// delayMicroseconds(24); // timing adjustmet
}
case 7: { // 1ms range
timeExec = 8 + 60;
// Approximate execution time(ms)
ADCSRA = ADCSRA & 0xf8;
// clear bottom 3bit
ADCSRA = ADCSRA | 0x05; // dividing ratio = 16
(0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128)
for (int i = 0; i <
REC_LENG; i++) { // up to rec buffer size
waveBuff[i] = analogRead(0); // read
and save approx 28us
// delayMicroseconds(12); // timing adjustmet
}
case 8: { // 500us range
timeExec = 4 + 60;
// Approximate execution time(ms)
ADCSRA = ADCSRA & 0xf8;
// clear bottom 3bit
ADCSRA = ADCSRA | 0x04; // dividing ratio =
16(0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128)
for (int i = 0; i <
REC_LENG; i++) { // up to rec buffer size
waveBuff[i] = analogRead(0); // read
and save approx 16us
delayMicroseconds(4); // timing adjustmet
}
break;
}
case 9: { // 200us range
void
dataAnalize() { // get various information from wave form
int d;
long sum = 0;
// calculate average
dataAve = (sum + 10) /
20; // Average value calculation (calculated by 10 times to improve accuracy)
if (att10x == 1) {
// if 10x attenuator used
rangeMaxDisp = 100 * (rangeMax * lsb50V); // display
range is determined by the data.(the upper limit is up to the full scale of the ADC)
rangeMinDisp = 100 * (rangeMin * lsb50V); // lower depend on data, but zero or more
}
else { // if no attenuator used
rangeMaxDisp = 100
* (rangeMax * lsb5V);
rangeMinDisp = 100 * (rangeMin * lsb5V);
}
} else {
// if fix range
// Write necessary code here (none for
now)
}
}
trigSync = true;
if (trigP >= ((REC_LENG / 2) + 50)) { // If the trigger
is not found in range
trigP = (REC_LENG / 2); // Set it to the
center for the time being
trigSync = false; // set Unsync
display flag
}
if ((dataMax - dataMin) <= MIN_TRIG_SWING) { // amplitude of the
waveform smaller than the specified value
trigSync = false; //
set Unsync display flag
}
freqDuty();
}
void freqDuty() {
// detect frequency and duty cycle value from waveform data
int swingCenter;
// center of wave (half of p-p)
float p0 = 0;
// 1-st posi edge
float p1 = 0; // total length of cycles
float pPeriod;
// pulse period
float pWidth; // pulse width
int
p1Count = 0; // wave cycle count
int p2Count = 0;
// High time count
for (int i =
1; i < REC_LENG - 2; i++) { // scan all over the buffer
if (posiSerch == true) {
// posi slope (frequency serch)
if ((sum3(i) <= swingCenter) && (sum3(i + 1)
> swingCenter)) { // if across the center when rising (+-3data used to eliminate noize)
p1Count++;
}
lastPosiEdge = i + pFine; // record location
for Pw calcration
posiSerch = false;
}
} else { // nega slope serch
(duration serch)
if ((sum3(i) >= swingCenter) && (sum3(i + 1) <
swingCenter)) { // if across the center when falling (+-3data used to eliminate noize)
waveFreq = 1.0 /
((pgm_read_float(hRangeValue + hRange) * pPeriod) / 25.0); // frequency
waveDuty = 100.0 *
pWidth / pPeriod; // duty ratio
}
int sum3(int k) {
// Sum of before and after and own value
int m = waveBuff[k - 1] + waveBuff[k] +
waveBuff[k + 1];
return m;
}
oled.println(F("Mini"));
oled.setCursor(30, 20);
oled.println(F("Oscilloscope"));
oled.setCursor(55, 42);
oled.println(F("v1.1"));
oled.display();
delay(1500);
oled.clearDisplay();
oled.setTextSize(1); // After
this, standard font size
}
oled.setCursor(42, 11);
oled.print(F("Hold")); // Hold
oled.display(); //
}
void dispInf() { //
Display of various information
float voltage;
// display vertical sensitivity
oled.drawFastVLine(0, 5, 2, WHITE);
oled.drawFastVLine(26, 5, 2, WHITE);
}
//
horizontal sweep speed
oled.setCursor(34, 0); //
oled.print(hScale);
// display sweep speed (time/div)
if (scopeP == 1) { //
if scoped
oled.drawFastHLine(32, 7, 33, WHITE); // display scoped mark at the bottom
oled.drawFastVLine(32, 5, 2, WHITE);
oled.drawFastVLine(64, 5, 2, WHITE);
}
//
trigger polarity
oled.setCursor(75, 0); // at top center
if (trigD == 0)
{ // if positive
oled.print(char(0x18)); // up mark
} else {
oled.print(char(0x19)); // down mark ?
}
if
(scopeP == 2) { // if scoped
oled.drawFastHLine(71, 7, 13, WHITE); //
display scoped mark at the bottom
oled.drawFastVLine(71, 5, 2, WHITE);
oled.drawFastVLine(83, 5, 2, WHITE);
}
// average voltage
if (att10x == 1) {
// if 10x attenuator is used
voltage = dataAve * lsb50V / 10.0; //
50V range value
} else { // no!
voltage = dataAve *
lsb5V / 10.0; // 5V range value
}
if (voltage < 10.0) { //
if less than 10V
dtostrf(voltage, 4, 2, chrBuff); // format x.xx
} else {
// no!
dtostrf(voltage, 4, 1, chrBuff); // format
xx.x
}
oled.setCursor(98, 0); // around the top right
// vartical scale
lines
voltage = rangeMaxDisp / 100.0; // convart Max voltage
if (vRange == 1
|| vRange > 4) { // if range below 5V or Auto 5V
dtostrf(voltage, 4, 2,
chrBuff); // format *.**
} else { // no!
voltage = (rangeMaxDisp +
rangeMinDisp) / 200.0; // center value calculation
if (vRange == 1 || vRange > 4) {
// if range below 5V or Auto 5V
dtostrf(voltage, 4, 2, chrBuff); // format
*.**
} else { // no!
dtostrf(voltage, 4, 1, chrBuff);
// format **.*
}
oled.setCursor(0, 33);
oled.print(chrBuff);
// display the value
oled.setCursor(0, 57);
oled.print(chrBuff); // display the value
// display frequency, duty % or trigger missed
if (trigSync == false) { //
If trigger point can't found
oled.fillRect(92, 14, 24, 8, BLACK); // black paint
4 character
oled.setCursor(92, 14); //
oled.print(F("Hz"));
} else if (waveFreq < 1000.0) { // if less than
1000Hz
oled.print(waveFreq, 0); // display 999Hz
oled.print(F("Hz"));
} else if (waveFreq < 10000.0) { // if less than
10kHz
oled.print((waveFreq / 1000.0), 2); // display 9.99kH
oled.print(F("kH"));
} else { // if more
oled.print(F("kH"));
}
oled.fillRect(96, 21, 25, 10, BLACK); // erase
Freq area (as small as possible)
oled.setCursor(97, 23); // set
location
oled.print(waveDuty, 1); // display duty (High level ratio) in
%
oled.print(F("%"));
}
}
}
}
x = EEPROM.read(1); // hRange
if ((x < 0) || (9 < x)) { //
if out of 0-9
x = 3; // default value
}
hRange = x;
x
= EEPROM.read(2); // trigD
if ((x < 0) || (1 < x)) { // if
out of 0-1
x = 1; // default value
}
trigD = x;
x =
EEPROM.read(3); // scopeP
if ((x < 0) || (2 < x)) { // if
out of 0-2
x = 1; // default value
}
scopeP =
x;
}
oled.println(F("Battery voltage"));
oled.setCursor(35, 30);
//
oled.setTextSize(2); // double size character
oled.print(chrBuff);
oled.println(F("V"));
oled.display();
delay(150);
}
}
if (digitalRead(9) == LOW) { // if UP button pushed, 5V
range
analogReference(INTERNAL);
pinMode(12, INPUT); // Set the
attenuator control pin to Hi-z (use as input)
while (1) { //
do forever,
digitalWrite(13, HIGH); // flash LED
voltage =
analogRead(0) * lsb5V; // measure voltage
oled.clearDisplay(); //
erase screen (0.4ms)
oled.setTextColor(WHITE); // write in white character
oled.setCursor(26, 16); //
oled.setTextSize(1); //
by standerd size character
oled.println(F("DVM 5V Range"));
oled.setCursor(35, 30); //
oled.setTextSize(2); // double
size character
dtostrf(voltage, 4, 2, chrBuff); // display batterry voltage x.xxV
oled.print(chrBuff);
oled.println(F("V"));
oled.display();
analogReference(INTERNAL);
pinMode(12, OUTPUT); // Set the attenuator
control pin to OUTPUT
digitalWrite(12, LOW); // output LOW
while (1)
{ // do forever
digitalWrite(13, HIGH); //
flush LED
voltage = analogRead(0) * lsb50V; // measure voltage
oled.println(F("V"));
oled.display();
digitalWrite(13, LOW);
// stop LED flash
delay(150);
}
}
}
void pin2IRQ() {
// Pin2(int.0) interrupr handler
// Pin8,9,10,11 buttons are bundled with diodes
and connected to Pin2.
// So, if any button is pressed, this routine will start.
int x;
// Port information holding variable
x = PINB;
// read port B status
if ( (x & 0x07) != 0x07) { // if bottom 3bit is not all
Hi(any wer pressed)
saveTimer = 5000; // set EEPROM save timer to 5 secnd
vRange++; // V-range up !
if (vRange > 9) { // if upper
limit
vRange = 9; // stay as is
}
}
if (scopeP == 1) {
// if scoped hrizontal range
hRange++; // H-range up !
if ((x &
0x04) == 0) { // if DOWN button(Pin10) pusshed, and
if (scopeP == 0) {
// scoped vertical range
vRange--; // V-range DOWN
if
(vRange < 0) { // if bottom
vRange = 0; // stay as is
}
}
if (scopeP == 1) { // if scoped hrizontal range
hRange--;
// H-range DOWN
if (hRange < 0) { // if bottom
hRange = 0; // satay as is
}
}
if (scopeP == 2) {
// if scoped trigger porality
trigD = 1; // set trigger porality to
-
}
}