Libreria/firmware SCPI per Arduino UNO che espone un piccolo strumento programmabile via seriale USB. Il firmware implementa misure analogiche, uscite digitali, PWM, servo, acquisizione multi-canale e trigger analogico/digitale con sintassi ispirata a SCPI.
OpenSCPI-Lab UNO trasforma un Arduino UNO in uno strumento controllabile via SCPI (Standard Commands for Programmable Instruments).
Funzioni principali attualmente implementate:
- identificazione e reset strumento
- selezione e lettura ingressi analogici
A0..A5 - lettura ADC grezza oppure tensione convertita in volt
- scansione di più canali analogici con
ROUT:SCAN+READ? - controllo uscite digitali sui pin
D2..D13 - controllo PWM sui pin
D9eD10 - controllo servo sui pin
D9eD10 - query servo: ultimo angolo impostato e stato attach
- trigger immediato, analogico o digitale
- gestione pendenza trigger (
TRIG:SLOP POS|NEG) anche su trigger digitale (edge) - abilitazione/disabilitazione delle risposte di conferma
OK - gestione errori SCPI tramite
SYST:ERR?e pulizia stato con*CLS - selezione riferimento ADC (
CAL:REF DEF|INT|EXT) e valore Vref software (CAL:VREF) - gestione avanzata GPIO con direzione/modalità (
DIG:MODE) e lettura ingresso (DIG:IN?) - (nuovo, firmware scope) acquisizione bufferizzata tipo oscilloscopio con pre-trigger e post-trigger (
INIT+FETC?) - (nuovo, firmware scope) stato acquisizione interrogabile (
ACQ:STAT?)
Il repository include ora tre firmware/documenti principali:
Arduino_SCPI.c: versione base/leggera (comandi SCPI essenziali)Arduino_SCOPE_SCPI.c: versione estesa con funzionalità scope (acquisizione bufferizzata)WEMOS_D1_R32_SCPI/WEMOS_D1_R32_SCPI.ino: variante ESP32 per WEMOS D1 R32README_D1R32.md: manuale operativo della variante WEMOS D1 R32
Questa documentazione mantiene i comandi comuni e aggiunge, in sezioni dedicate, le estensioni specifiche della versione
Arduino_SCOPE_SCPI.c.Per la variante ESP32/WEMOS D1 R32 vedi README_D1R32.md.
Il comportamento degli errori dipende dal firmware utilizzato:
- restituisce
ERRoppure stringhe semplici (es.ERR:TIMEOUT)
- restituisce
ERRcome risposta breve - il dettaglio errore è disponibile tramite:
SYST:ERR?
0,"No error"
-222,"Data out of range"
-221,"Settings conflict"
-250,"Timeout error"
Per evitare ambiguità:
Arduino_SCPI.cè davvero una versione base.- Può servire come punto di partenza per sviluppare un vostro firmware.
- molte estensioni documentate sotto sono solo per
Arduino_SCOPE_SCPI.c.
| Comando/famiglia | Arduino_SCPI.c (base) |
Arduino_SCOPE_SCPI.c (esteso) |
|---|---|---|
*IDN?, *RST, SYST:ACK |
✅ | ✅ |
*OPC?, *CLS, SYST:ERR? |
❌ | ✅ |
CAL:REF, CAL:VREF |
❌ | ✅ |
DIG:MODE, DIG:IN? |
❌ | ✅ |
TRIG:SLOP |
❌ | ✅ |
SOUR:SERVO?, SOUR:SERVO:ATT? |
❌ | ✅ |
ACQ:*, INIT, ABOR, FETC? |
❌ | ✅ |
Se usi il firmware base
Arduino_SCPI.c, i comandi non supportati rispondono con errore.
Lo strumento comunica tramite porta seriale USB.
- Baudrate:
115200 - Terminazione comando: newline
\n - Formato generale risposte:
- valori numerici o stringhe per le query
...? OKper i comandi di configurazione, se gli ACK sono abilitatiERRin caso di errore di comando/esecuzione
- valori numerici o stringhe per le query
Per il dettaglio errore usare sempre
SYST:ERR?(stile SCPI): il firmware mantiene l'ultimo errore e lo azzera dopo la lettura.
*IDN?\n
Per le acquisizioni multi-canale il flusso concettuale è:
Configurazione -> Trigger -> Acquisizione -> Lettura
In pratica:
- si definisce la lista di canali con
ROUT:SCAN - si configura l'eventuale trigger con
TRIG:* - si avvia la lettura con
READ?
Per la variante scope (Arduino_SCOPE_SCPI.c) è disponibile anche il flusso avanzato:
Configurazione -> Arm (INIT) -> Trigger + campionamento -> Fetch (FETC?)
| Canale SCPI | Pin Arduino |
|---|---|
| 0 | A0 |
| 1 | A1 |
| 2 | A2 |
| 3 | A3 |
| 4 | A4 |
| 5 | A5 |
| Canale SCPI | Pin Arduino |
|---|---|
| 0 | D2 |
| 1 | D3 |
| 2 | D4 |
| 3 | D5 |
| 4 | D6 |
| 5 | D7 |
| 6 | D8 |
| 7 | D9 |
| 8 | D10 |
| 9 | D11 |
| 10 | D12 |
| 11 | D13 / LED_BUILTIN |
Nota: i pin
D9eD10possono essere usati sia come uscite digitali sia come uscite PWM/servo.
| Canale SCPI | Pin Arduino |
|---|---|
| 0 | D9 |
| 1 | D10 |
Nota compatibilità: in questa sezione
*OPC?,*CLSeSYST:ERR?sono disponibili solo nel firmwareArduino_SCOPE_SCPI.c.
Restituisce l'identità dello strumento.
Risposta:
OpenSCPI-Lab,Arduino-UNO,<firmware-version>
> La stringa di versione dipende dal firmware caricato:
>
> - `Arduino_SCPI.c` (base): es. `1.2`
> - `Arduino_SCOPE_SCPI.c` (scope): es. `1.0-RC2`
Ripristina lo stato iniziale dello strumento:
- canale analogico corrente =
0 - trigger =
IMM - livello trigger =
2.5 - timeout trigger =
1000 ms - uscite digitali =
LOW - PWM =
0 - servo sganciati (
detach) - (firmware scope) fronte trigger =
POS - riferimento ADC =
DEFAULT,vRef = 5.0 - modalità digitali riportate a
OUT
Risposta: OK se gli ACK sono attivi.
Query di stato operazione completa:
1se non ci sono acquisizioni in corso (ACQ_IDLEoACQ_DONE)0se acquisizione armata/in corso
Azzera lo stato errore SCPI interno.
Restituisce e consuma l'ultimo errore SCPI in formato numerico+testo, ad esempio:
0,"No error"
-222,"Data out of range"
-221,"Settings conflict"
Il firmware può rispondere con OK dopo i comandi di configurazione. Per retrocompatibilità gli ACK sono attivi di default.
Abilita le risposte OK.
Disabilita le risposte OK.
Restituisce:
1= ACK attivi0= ACK disattivi
CAL:REFeCAL:VREFsono comandi solo diArduino_SCOPE_SCPI.c.
La versione baseArduino_SCPI.cusa conversione fissa a 5V (raw * (5.0 / 1023.0)).
Nel firmware Arduino_SCOPE_SCPI.c la conversione in volt usa:
V = raw * (vRef / 1024.0)
dove vRef dipende dalla configurazione SCPI:
CAL:REF DEF-> riferimento ADC default Arduino (tipicamente 5V su UNO alimentato USB)CAL:REF INT-> riferimento interno nominale 1.1VCAL:REF EXT-> riferimento esterno sul pin AREF/Vref (hardware esterno)CAL:VREF <val>-> imposta il valore numerico usato dal firmware per la conversione in volt
Se si usa INT o EXT senza aggiornare correttamente CAL:VREF, le misure in volt e le soglie trigger analogiche possono risultare errate.
In particolare con riferimento interno a 1.1V, segnali oltre il fondo scala saturano il convertitore: verificare cablaggio/attenuazione prima delle misure.
Imposta la sorgente di riferimento ADC:
DEF= default ArduinoINT= riferimento interno 1.1VEXT= riferimento esterno su pin Vref/AREF
Restituisce DEF, INT oppure EXT.
Imposta il valore di riferimento usato nei calcoli in volt.
- range ammesso firmware scope:
0.5 < value <= 6.0
Restituisce vRef con 3 decimali.
Il comando CAL:REF cambia il riferimento dell'ADC tramite analogReference(...).
- il riferimento ADC è globale, non per singolo canale
- quindi il cambio di
CAL:REFinfluenza tutti gli ingressi analogiciA0..A5 CAL:VREFmodifica solo il valore software usato per la conversione in volt
Il cambio di riferimento ADC non è sempre affidabile quando effettuato più volte durante l'esecuzione.
Durante i test è stato osservato che la sequenza:
CAL:REF INT
CAL:REF DEF
CAL:REF INT
può non ripristinare correttamente il riferimento interno senza reset del microcontrollore.
Questo comportamento è dovuto a limitazioni dell'ADC AVR e/o della libreria Arduino, non al parser SCPI.
Raccomandazioni:
- evitare cambi frequenti di CAL:REF
- impostare il riferimento una sola volta all'inizio
- scartare le prime letture dopo un cambio di reference
- se il riferimento interno non torna operativo: -- eseguire *RST -- oppure power-cycle della board
| Canale | Pin |
|---|---|
| 0 | A0 |
| 1 | A1 |
| 2 | A2 |
| 3 | A3 |
| 4 | A4 |
| 5 | A5 |
Seleziona il canale analogico corrente (0..5).
Esempio:
CONF:VOLT 2
Restituisce il canale analogico attualmente selezionato.
Legge la tensione sul canale correntemente configurato.
Legge direttamente il canale specificato (0..5) senza cambiare la configurazione corrente.
Restituisce il valore ADC grezzo del canale specificato (0..5), nel range:
0..1023
Restituisce in una singola riga le tensioni dei sei canali analogici.
Esempio:
1.0215,0.9785,0.1173,4.5015,0.0000,0.3324
Nota: nel firmware
Arduino_SCOPE_SCPI.cla conversione usa sempreraw * (vRef / 1024.0).
DIG:MODE,DIG:MODE?eDIG:IN?sono disponibili solo nel firmwareArduino_SCOPE_SCPI.c.
Nel firmware base restanoDIG:OUTeDIG:OUT?.
| Canale | Pin |
|---|---|
| 0 | D2 |
| 1 | D3 |
| 2 | D4 |
| 3 | D5 |
| 4 | D6 |
| 5 | D7 |
| 6 | D8 |
| 7 | D9 |
| 8 | D10 |
| 9 | D11 |
| 10 | D12 |
| 11 | D13 |
Imposta un'uscita digitale.
Prerequisito (solo firmware scope): il canale deve essere in modalità OUT (vedi DIG:MODE), altrimenti il firmware restituisce errore di modalità (SYST:ERR? -> -221).
<val>può essere0oppure1<ch>può essere indicato in due modi:- indice SCPI:
0..11 - pin fisico Arduino:
D2,D3, ...,D13
- indice SCPI:
Esempi:
DIG:OUT 3,1
DIG:OUT 3,0
DIG:OUT D13,1
DIG:OUT D13,0
DIG:OUT 9,1significa canale SCPI 9 -> pinD11DIG:OUT D9,1significa pin fisicoD9
Questa distinzione evita ambiguità fra indice logico e numero del pin Arduino.
Se si usa DIG:OUT su un pin PWM (D9 o D10):
- il corrispondente valore PWM viene aggiornato internamente a
255oppure0 - un eventuale servo collegato su quel canale viene disattivato (
detach)
Legge lo stato logico dell'uscita specificata.
Sono accettati sia gli indici SCPI sia i nomi pin D<n>.
Anche qui il canale deve essere in modalità OUT.
Configura la modalità del pin digitale:
INinput floatingOUTuscita digitalePULLUPinput con pull-up interna
<ch> accetta sia indice SCPI (0..11) sia pin (D2..D13).
Restituisce la modalità corrente: IN, OUT o PULLUP.
Legge direttamente il livello logico del pin (0/1) in modalità input.
| Canale | Pin |
|---|---|
| 0 | D9 |
| 1 | D10 |
Imposta il duty cycle PWM.
<ch>:0..1<val>:0..255
Esempio:
SOUR:PWM 0,128
Restituisce il valore PWM corrente del canale richiesto.
Se sullo stesso canale era stato precedentemente attivato un servo, il firmware esegue automaticamente il detach() prima di applicare il PWM.
| Canale | Pin |
|---|---|
| 0 | D9 |
| 1 | D10 |
Imposta la posizione del servo.
<ch>:0..1<angle>:0..180
Esempio:
SOUR:SERVO 1,90
Quando il canale non è ancora associato a un servo, il firmware esegue automaticamente attach() sul pin corrispondente.
Restituisce l'ultimo angolo impostato sul canale servo richiesto.
<ch>:0..1- valore tipico restituito:
0..180
Restituisce lo stato attuale di attach del servo:
1= servo attaccato0= servo non attaccato (detach)
Definisce la lista di canali analogici da acquisire con READ?.
Formati supportati:
- elenco esplicito:
(@0,1,2) - intervallo:
(@0:5)
Esempi:
ROUT:SCAN (@0,1,2)
ROUT:SCAN (@0:5)
Restituisce la lista canali attualmente configurata come sequenza separata da virgole.
Esempio:
0,1,2
Esegue l'acquisizione dei canali definiti in ROUT:SCAN.
- se il trigger è soddisfatto, restituisce le tensioni dei canali selezionati
- se la lista è vuota o c'è errore di esecuzione, restituisce
ERR(dettaglio conSYST:ERR?) - se il trigger va in timeout, restituisce
ERR(dettaglio-250,"Timeout error"viaSYST:ERR?)
Esempio risposta:
1.2307,0.9814,3.4487
Il firmware supporta tre modalità trigger:
IMM= trigger immediatoANA= trigger analogicoDIG= trigger digitale
Seleziona la sorgente di trigger.
Valori ammessi:
IMM
ANA
DIG
Esempi:
TRIG:SOUR IMM
TRIG:SOUR ANA
TRIG:SOUR DIG
Restituisce la modalità trigger corrente.
Imposta il fronte di trigger nella modalità scope:
POS= fronte di salitaNEG= fronte di discesa
In ANA la condizione diventa:
POS: trigger quandoV >= levelNEG: trigger quandoV <= level
Per trigger digitali (TRIG:SOUR DIG) il firmware usa trigger edge:
TRIG:SLOP POS= fronte LOW→HIGHTRIG:SLOP NEG= fronte HIGH→LOW
Restituisce POS oppure NEG.
Imposta il canale sorgente del trigger.
Il significato dipende dalla modalità corrente:
- con
TRIG:SOUR ANA,<ch>deve essere un canale analogico0..5 - con
TRIG:SOUR DIG,<ch>può essere:- un indice digitale SCPI
0..11 - un pin nel formato
D<n>
- un indice digitale SCPI
Trigger analogico
| Canale | Pin |
|---|---|
| 0 | A0 |
| 1 | A1 |
| 2 | A2 |
| 3 | A3 |
| 4 | A4 |
| 5 | A5 |
Trigger digitale
| Canale | Pin |
|---|---|
| 0 | D2 |
| 1 | D3 |
| 2 | D4 |
| 3 | D5 |
| 4 | D6 |
| 5 | D7 |
| 6 | D8 |
| 7 | D9 |
| 8 | D10 |
| 9 | D11 |
| 10 | D12 |
| 11 | D13 |
Quando si configura un trigger digitale, il pin selezionato viene messo in INPUT per permettere la lettura del segnale esterno.
Se si tenta di usare TRIG:CHAN mentre la modalità è IMM, il firmware risponde:
ERR
(dettaglio: -221,"Settings conflict" da SYST:ERR?)
Restituisce:
- il canale analogico di trigger se il modo è
ANA - il canale digitale di trigger se il modo è
DIG NONEse il modo èIMM
Imposta il livello di trigger.
- in modalità
ANA, la condizione di trigger èV >= level(oppureV <= levelseTRIG:SLOP NEGnella versione scope) - in modalità
DIG, il comando non è ammesso (Settings conflict, errore-221)
Restituisce il livello trigger corrente.
Nota: nelle revisioni più recenti il comportamento di
TRIG:LEV?è stato corretto per essere coerente con la modalità trigger attiva; se la modalità non usaTRIG:LEV, il comando può restituire errore.
Imposta il timeout del trigger in millisecondi.
- deve essere maggiore di
0 - il default dopo reset è
1000
Restituisce il timeout trigger corrente in millisecondi.
La variante scope introduce una macchina a stati di acquisizione con buffer circolare logico su array lineare:
- stati:
ACQ_IDLE,ACQ_PREFILL,ACQ_ARMED,ACQ_POST,ACQ_DONE - buffer ADC raw massimo:
MAX_TOTAL_POINTS = 300campioni totali (distribuiti su tutti i canali in scan) - pre-trigger e post-trigger al 50% dei punti richiesti
Imposta il numero di punti per acquisizione.
- ammessi:
1 .. 300 - errore su valore non valido:
ERR:VAL
Imposta il passo temporale di campionamento interno in microsecondi (variabile firmware acqTStep).
- valore ammesso:
> 0 - errore su valore non valido:
ERR:VAL
Restituisce il numero di punti configurato.
Restituisce il passo temporale in microsecondi.
Restituisce lo stato corrente della macchina acquisizione:
IDLEPREFILLARMEDPOSTDONE
Arma l'acquisizione scope.
Controlli effettuati:
- se
ROUT:SCANnon è configurato ->ERR(-200,"Execution error") - se
ACQ:POIN * numero_canali_scan > 300->ERR(-222,"Data out of range")
Se valido, entra in stato ACQ_PREFILL.
Interrompe/disarma l'acquisizione e riporta lo stato a ACQ_IDLE.
Attende il completamento dell'acquisizione e poi restituisce i dati acquisiti.
Comportamento:
- se non armato (
ACQ_IDLE) ->ERR(-200,"Execution error") - timeout interno fetch di 2 secondi ->
ERR(-250,"Timeout error") - in caso positivo, stampa
acqPointsrighe - ogni riga contiene i canali della scan corrente separati da virgola
- valori convertiti in volt con
raw * (vRef / 1024.0)
Formato output (esempio con 2 canali in scan):
1.2344,0.1025
1.2451,0.1030
...
CONF:VOLT 0
MEAS:VOLT?
MEAS:VOLT? 4
MEAS:RAW? 4
DIG:OUT D13,1
SOUR:PWM 0,200
SOUR:SERVO 1,45
ROUT:SCAN (@0,1,2)
TRIG:SOUR ANA
TRIG:CHAN 0
TRIG:LEV 2.500
TRIG:TOUT 3000
READ?
ROUT:SCAN (@0:2)
TRIG:SOUR DIG
TRIG:SLOP POS
TRIG:CHAN D2
TRIG:TOUT 5000
READ?
ROUT:SCAN (@0,1)
TRIG:SOUR ANA
TRIG:SLOP POS
TRIG:CHAN 0
TRIG:LEV 2.300
ACQ:POIN 120
ACQ:TINT 250
INIT
FETC?
- firmware pensato per Arduino UNO / ATmega328P
- tensioni calcolate usando
vRefconfigurabile viaCAL:REF/CAL:VREF(default 5V) - il trigger si applica alla lettura
READ?e, nella versione scope, anche al cicloINIT/FETC? - il firmware non implementa un parser SCPI completo, ma un sottoinsieme pratico
- nella variante
Arduino_SCOPE_SCPI.cla memoria totale dei campioni è limitata a300valori ADC complessivi
Distribuito secondo la licenza riportata nel file LICENSE.