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.
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
Last edited: