Share My Creation PC Oscilloscope

Low frequency oscilloscope for PC using Arduino Uno or Nano. The input is to pin A0 of the Arduino which connected to PC via USB .Bandwidth up to 5KHz. The sampling is done by the Arduino ADC in a speed of about 36K sampling per sec. The Arduino software is mostly in C code in purpose to speed up the ADC on expense of conversion accuracy. The Arduino takes 62 samples of input to create one trace. For lower frequencies a delay for each sample gives slower sweep. Input is DC or AC not acceding 5V.
The Analogue Comparator of the Arduino (pins 6, 7) is used to detect zero crossing of input signal, it triggers start of sampling the trace when signal is rising.
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private sp As Serial
    Private astream As AsyncStreams
    Private bc As ByteConverter
    Private cmb1 As ComboBox
    Private Label1 As Label
    Dim yp=128, tc As Int
    Private Canvas1 As Canvas
    Private Pane1 As Pane

    Private Button1 As Button
    Private Slider1 As Slider
    Private sweep(1), sam(200) As Byte
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    sp.Initialize("")
    cmb1.Items.AddAll(sp.ListPorts)

End Sub

Sub Slider1_ValueChange (Value As Double)
    sweep(0)=Slider1.Value
End Sub

Sub cmb1_SelectedIndexChanged(Index As Int, Value As Object)
    Try
        sp.Open(cmb1.Value)
        sp.SetParams(9600,8,1,0)
        astream.Initialize(sp.GetInputStream, sp.GetOutputStream, "astream")
        Label1.Text = "Port Open"
        drawScreen
    Catch
        Label1.Text = "Port is busy"
        Log("Port error")
    End Try

End Sub

Sub drawScreen
    Canvas1.DrawRect(0,0,300,256,fx.Colors.Green,True,0)
    Canvas1.DrawLine(0,128,300,128,fx.Colors.White, 1dip)
    Canvas1.DrawLine(150,0,150,256,fx.Colors.LightGray, 1dip)
End Sub

Sub AStream_NewData (Buffer() As Byte)
    Dim x1, y1, x2, y2, inB As Int
  
    'Log(Buffer.Length)
    bc.ArrayCopy(Buffer,0,sam,tc,Buffer.Length)    'add arrays to length of 62 bytes
    tc=tc+Buffer.Length
    If tc > 61 Then
        tc=0
        drawScreen
        For i=0 To 61
            inB=sam(i)
            x1=i*5-5
            x2=x1+5
            y2=128-inB
            y1=yp
            Canvas1.DrawLine(x1, y1, x2, y2, fx.Colors.Red, 1dip)
            yp=y2
        Next
        astream.Write(sweep)
    End If
  
End Sub

Sub Button1_Click
    cmb1.Items.Clear
    cmb1.Items.AddAll(sp.ListPorts)
End Sub
B4X:
Sub Process_Globals
    Public in4 As Pin
    Public in5 As Pin
    Public range As UInt
    Private Timer1 As Timer
End Sub

Private Sub AppStart
    RunNative ("setADC",Null)
    Timer1.Initialize("Timer1_Tick", 500)
    Timer1.Enabled = True

End Sub

Private Sub Timer1_Tick
    RunNative ("scope_lp",Null)
  
End Sub

#if C
void setADC(B4R::Object* o)
{
    //baud rate=9600
  UCSR0A |= (1<<U2X0);   //fast rate
  UBRR0H = 0;
  UBRR0L = 207;    //9600->207  115200->16
  UCSR0B |= (1<<RXEN0)|(1<<TXEN0); //rx and tx enabled

    //ADC
  DIDR0 |= _BV(ADC0D) |  _BV(AIN0D) |  _BV(AIN1D);  //digital input disabled for ADC and COMP
  ADCSRA |= _BV(ADPS2) | _BV(ADEN); //prescaler=16 250KHz
  ADMUX |= _BV(REFS0);
}
#End if

#if C
void scope_lp(B4R::Object* o)
{ 
   unsigned char i, out[62], dh, range=100;
 
     if( (UCSR0A & (1<<RXC0)) ) {range = UDR0;}   //check bytes received

           //trigger when input high
    i=0;
    while ((ACSR & (1<<ACO)) && i<62){delayMicroseconds(range*10); ++i;} // Wait for low COMPERATOR output
    i=0;
    while (!(ACSR & (1<<ACO)) && i<62){delayMicroseconds(range*10); ++i;} // Wait for high COMP out

      //sample 62 readings
    for(i=0;i<62;++i){ 
    ADCSRA |=_BV(ADSC);   //start conversion
    while ( !( ADCSRA & (1<<ADIF)) ){} // Wait for conversion to complete

    out[i]=ADCL;
    dh = ADCH;
    ADCSRA |=_BV(ADIF);   //reset interrupt
    delayMicroseconds(range*10);  //slower sweep for low freq
    }
  
      //send 62 bytes
   for(i=0;i<62;++i){
    while ( !( UCSR0A & (1<<UDRE0)) ){} // Wait for empty transmit buffer
    UDR0 = out[i];  // send the data
  }

}
#End if
 

Attachments

  • scope_b4j.zip
    31.2 KB · Views: 375
  • scop_b4r.zip
    1.3 KB · Views: 366
  • scope400.png
    scope400.png
    22.1 KB · Views: 1,759
  • scope_trig.png
    scope_trig.png
    4.2 KB · Views: 391
Last edited:
Top