Arduino Simple Oscilloscope


This example takes advantage of the µPanel capability to implement dynamic and real-time panels. The presented code implements a simple oscilloscope, with input channel and sample rate selectable by the user. The sample rate can be chosen between 1 Hz and 1 kHz.

Hardware

  • Arduino UNO Board
  • ESP-01 WiFi module (with µPanel Firmware)
  • ESP-01 Breadboard adapter
  • Breadboard wires (4 lines, Male-Female)

 

 

µPanel definition 

The application implements 3 completely different panels: 1) splash screen, 2) settings and 3) oscilloscope panel.

1) Splash screen HCTML definition:

D!822;{^*30%80,100!822,411{ht2,000,1*14T:&#956Panel;}/3{*5T:Mobile Interactive;_T:Universal Panel;}_{*7T:Oscilloscope;_*6T#A33:for Arduino UNO;}}/20*15B0:START;

2) Settings panel HCTML definition:

Panel Header: D!822;/5*12{^tTk%90!611*15:SETTINGS;//
Box Macro Definition: K1:{p25!822,411-%90<Td,-8.5!822k%28^:?;_*12Tfb:Selected: ;M??:?;_|$
Box 1: J1(Channel,AN0)/{^S1!F00,800p10%20r20;|s1+.0T:0;|s1+.1T:1;|s1+.2T:2;|s1+.3T:3;|s1+.4T:4;|s1+.5T:5;}}_|/
Box 2: J1(Frequency,1000 Hz)/{%90^|s1+.6T:1;|s1+.7T:10;|s1+.8T:100;|s1+.9T:1000;}}}/
Panel Footer: 18*15B0%90!F44,822r20#FFF:START;

3) Oscilloscope panel HCTML definition:

D!822;/5*12{^t%95!611*13T:CHANNEL ;M1:;}/G0%95,70*12:::Samples:[V]:0F0:FFF:FFF:822:411;
//{^%95|B1%40!F44,822r20#FFF:SETTINGS;|B2%40!F44,822r20#FFF:EXIT;}


 
Application splash screen
 
Settings Panel
 
Runtime Screenshot


Arduino Code

#define FOREVER -1            // Constant for wait forever

String Msg;                   // Received Message
char Page = 0;                // Current Application Panel 
char Channel = 0;             // Selected analog input channel
int Rate = 1000;              // Selected sample rate

void setup() {

  Serial.begin(57600);         // Initialise serial
  delay(3000);                 // Let's the module start
  Serial.println("");          // Discarge old partial messages
  
}

/*****************************************************
* This function waits a data message from the uPanel

* Input: timeout_ms time to wait for message
*        -1 for forever
* Return: 0 = Timeout, 1 = Message received
******************************************************/
int WaitMessage(int timeout_ms)
{
  int c;
  unsigned long entrytime = millis();
  static char KeepBuffer = 0;

  if (!KeepBuffer) Msg = "";                             // The buffer contains a partial message?
  KeepBuffer = 0;                                        // if not, clear buffer. Clear keep-flag anyway.

  do
  {
    while ((c = Serial.read()) > '\n') Msg += (char) c;  // Read incoming chars, if any, until new line
    if (c == '\n')                                       // is message complete?
    {
      if (Msg.substring(0,1).equals("#")) return 1;      // if it is a data message return 1
      Msg = "";                                          // otherwise, wait for another one
    }
  } while ((timeout_ms < 0) || (millis()-entrytime < timeout_ms));  // has max time passed?
      
  KeepBuffer = 1;                                        // We timed-out, so keep the received partial message
  return 0;                                              // return 0 for timeout
}

void DisplaySplashScreen()        // Send the splash screen cointaining the Start button
{
   Serial.print("$P:D!822;{^*30%80,100!822,411{ht2,000,1*14T:&#956Panel;}/3{*5T:Mobile Interactive;_T:Universal Panel;}_");
   Serial.println("{*7T:Oscilloscope;_*6T#A33:for Arduino UNO;}}/20*15B0:START;");

   while (WaitMessage(FOREVER))
   {
       if (Msg.substring(0,4).equals("#B0P")) { Page = 1; break;}    // has start been presed? Change page and exit
   }

}

void DisplaySettings()
{
   Serial.print("$P:D!822;/5*12{^tTk%90!611*15:SETTINGS;//K1:{p25!822,411-%90<Td,-8.5!822k%28^:?;_*12Tfb:Selected: ;M??:?;_|$");
   Serial.print("J1(Channel,AN"); 
   Serial.print(Channel,DEC);
   Serial.print(")/{^S1!F00,800p10%20r20;|s1+.0T:0;|s1+.1T:1;|s1+.2T:2;|s1+.3T:3;|s1+.4T:4;|s1+.5T:5;}}");
   Serial.print("_|/J1(Frequency,");
   Serial.print(Rate,DEC);
   Serial.println(" Hz)/{%90^|s1+.6T:1;|s1+.7T:10;|s1+.8T:100;|s1+.9T:1000;}}}/18*15B0%90!F44,822r20#FFF:START;");
  
   while (WaitMessage(FOREVER))
   {
       // Manage channel selection
       if (Msg.substring(0,9).equals("#.EVT:0:1")) { Channel = 0; Serial.println("#M0AN0"); }
       if (Msg.substring(0,9).equals("#.EVT:1:1")) { Channel = 1; Serial.println("#M0AN1"); }
       if (Msg.substring(0,9).equals("#.EVT:2:1")) { Channel = 2; Serial.println("#M0AN2"); }
       if (Msg.substring(0,9).equals("#.EVT:3:1")) { Channel = 3; Serial.println("#M0AN3"); }
       if (Msg.substring(0,9).equals("#.EVT:4:1")) { Channel = 4; Serial.println("#M0AN4"); }
       if (Msg.substring(0,9).equals("#.EVT:5:1")) { Channel = 5; Serial.println("#M0AN5"); }

       // Manage Rate selection
       if (Msg.substring(0,9).equals("#.EVT:6:1")) { Rate = 1;    Serial.println("#M11 Hz"); }
       if (Msg.substring(0,9).equals("#.EVT:7:1")) { Rate = 10;   Serial.println("#M110 Hz"); }
       if (Msg.substring(0,9).equals("#.EVT:8:1")) { Rate = 100;  Serial.println("#M1100 Hz"); }
       if (Msg.substring(0,9).equals("#.EVT:9:1")) { Rate = 1000;  Serial.println("#M11000 Hz"); }

       if (Msg.substring(0,4).equals("#B0P")) { Page = 2; break;}   // has start been pressed? Change page and exit
       
   }
  
}

void DisplayOscilloscope()
{
  
   // Send Oscilloscope panel
   Serial.print("$P:D!822;/5*12{^t%95!611*13T:CHANNEL ;M1:;}/G0%95,70*12:::Samples:[V]:0F0:FFF:FFF:822:411;");
   Serial.println("//{^%95|B1%40!F44,822r20#FFF:SETTINGS;|B2%40!F44,822r20#FFF:EXIT;}");

   int Interval = 1000 / Rate;    // Compute the sampling interval
   unsigned int Counter = 0;      // Reset sampling counter

   Serial.print("#M1AN");         // Update Oscilloscope panel header 
   Serial.println(Channel,DEC);   // with the selected channel

   while (1)
   {
       if (WaitMessage(Interval))  // Wait until it's time for a new sample or incoming data
       {
         if (Msg.substring(0,4).equals("#B1P")) { Page = 1; return;}  // Settings button? exit
         if (Msg.substring(0,4).equals("#B2P")) { Page = 0; return;}  // Exit button? exit
       }
     
       int Sample = analogRead(A0+Channel);            // Acquire the analog input channel
       float Voltage = ((float) Sample)/1024.0 * 5.0;  // Transform LSB into Voltage
       
       Serial.print("#G0P:");            // Add a point to the plot
       Serial.print(Counter++,DEC);      // Send the sample number
       Serial.print(",");                // separator
       Serial.println(Voltage,3);        // Send the acquired voltage
   
   } 
  
}


void loop() {
  
  // Display the correct panel page
  if (Page == 0) DisplaySplashScreen();          // Send Application Splash Screen
  if (Page == 1) DisplaySettings();              // Send Settings panel  
  if (Page == 2) DisplayOscilloscope();          // Send Oscilloscope panel 
  
}