Quasar Strumento gratuito · Web Serial

Quasar Web Console Controlla Quasar Basic o Arduino Uno dal browser, via USB o Bluetooth (HC-05)

Collega la scheda e controllala da questa pagina, senza installare nulla: accendi e spegni i pin, leggi pulsanti e sensori, imposta PWM e angolo dei servo, guarda gli ingressi analogici in un grafico dal vivo ed esportali in CSV, esegui sequenze e dai comandi con la voce. Funziona con Quasar Basic e con qualsiasi Arduino Uno, con il cavo USB o con un modulo Bluetooth HC-05.

Pin digitali

Tocca un'uscita per accenderla o spegnerla, oppure scegli Ingresso / Pull-up per leggere un pulsante o un sensore: lo stato si aggiorna da solo. D2 e D3 sono usati dall'HC-05; se è saldato un modulo nRF24L01, evita D9–D13.

PWM

Ingressi analogici

Tocca un valore per leggerlo, oppure attiva l'aggiornamento automatico.

Grafico in tempo reale

Scegli gli ingressi analogici e l'intervallo, poi premi Avvia: la scheda invia le letture e il grafico le disegna dal vivo. Esporta i dati in CSV per un foglio di calcolo o per StarlyLab. Via Bluetooth usa 200 ms o più.

Servomotore

Collega il filo del segnale del servo al pin scelto. I servo piccoli come l'SG90 si possono alimentare dal pin 5V; quelli più grandi richiedono un alimentatore esterno con il GND in comune. Mentre un servo è collegato, il PWM sui pin 9 e 10 non funziona.

90°

Sequenze

Scrivi un comando per riga e aggiungi WAIT seguito dai millisecondi per fare una pausa. Le righe che iniziano con # sono commenti. La sequenza resta salvata in questo browser.

Esempi:

Comandi vocali

Premi il microfono e pronuncia un comando: la console lo trasforma in un comando per la scheda. La stessa idea di ElectroHome, l'app Android del 2018 che comandava Arduino con la voce.

Prova a dire:

  • “accendi il pin 13”
  • “spegni il pin 13”
  • “inverti il pin 7”
  • “imposta il pin 9 al 50 per cento”
  • “servo sul pin 6 a 90 gradi”
  • “leggi analogico 0”
  • “stato”

In Chrome il riconoscimento vocale è svolto dai server di Google: l'audio del comando viene inviato a Google per essere trasformato in testo. Il collegamento con la scheda resta nel tuo browser.

Terminale

Come si usa

1

Carica lo sketch

Apri l'IDE di Arduino, scegli Arduino Uno come scheda (anche per Quasar Basic), incolla o scarica lo sketch qui sotto e caricalo via USB.

2

Scegli il collegamento

Per l'USB sei già pronto: lascia il cavo collegato. Per il Bluetooth, collega l'HC-05 come nella tabella qui sotto e associalo al computer o al telefono (PIN predefinito 1234 o 0000).

3

Apri la console

Usa Chrome o Edge su un computer, oppure Chrome su Android. Scegli la velocità (9600 baud predefiniti) e premi Connetti.

4

Scegli la porta

Nella finestra del browser seleziona la porta USB della scheda o l'HC-05 associato. Poi usa i pin, i cursori PWM e il terminale.

Collegamento dell'HC-05

HC-05Quasar / Arduino UnoNota
VCC5Vil modulo HC-05 accetta 5 V su VCC
GNDGND
TXDD2la scheda riceve (RX della SoftwareSerial)
RXDD3tramite partitore di tensione: 1 kΩ da D3, 2 kΩ verso GND

Il pin RXD dell'HC-05 lavora a 3,3 V: il partitore abbassa il segnale a 5 V della scheda. L'uscita TXD dell'HC-05 può andare direttamente su D2.

Comandi

PINGverifica la connessione, risponde PONG QUASAR
ON 13 / OFF 13accende o spegne un pin digitale da 4 a 13
TOGGLE 13inverte un pin digitale
PWM 9 128valore PWM da 0 a 255 sui pin 5, 6, 9, 10, 11
MODE 7 INmodalità del pin: OUT, IN o PULLUP; gli ingressi comunicano da soli i cambiamenti
SERVO 6 90angolo del servo da 0 a 180 (SERVO 6 OFF lo rilascia)
READ A0 / READ D7legge un ingresso analogico (0–1023) o un pin digitale
STREAM 200 A0 A1invia gli ingressi analogici scelti ogni 200 ms (20–5000); STREAM OFF lo ferma
STATUSstato di tutti i pin e degli ingressi analogici

Lo sketch

Lo sketch ascolta i comandi sia sull'USB sia sull'HC-05, a 9600 baud. Funziona su Quasar Basic e su Arduino Uno.

/*
  Quasar Console 2.0 - Starlyware
  https://www.starlyware.com/products/quasar/console

  Lets the Quasar web console control the board over USB or over a
  Bluetooth HC-05 module. Works on Quasar Basic and on Arduino Uno
  (any ATmega328P board at 16 MHz). In the Arduino IDE choose "Arduino Uno".

  HC-05 wiring:
    HC-05 VCC -> 5V
    HC-05 GND -> GND
    HC-05 TXD -> D2 (board RX for Bluetooth)
    HC-05 RXD <- D3 through a voltage divider (1 kOhm from D3, 2 kOhm to GND):
                 the HC-05 RX pin works at 3.3 V.

  Commands (one per line, upper or lower case), pins 4-13:
    PING                 -> PONG QUASAR
    HELP                 -> list of commands
    ON 13 / OFF 13       -> digital output HIGH or LOW
    TOGGLE 13            -> invert a digital output
    PWM 9 128            -> PWM 0-255 on pins 5, 6, 9, 10, 11
    MODE 7 IN            -> pin mode: OUT, IN or PULLUP
    SERVO 9 90           -> servo angle 0-180 (SERVO 9 OFF to release it)
    READ A0 / READ D7    -> read an analog input (0-1023) or a digital pin
    STREAM 50 A0 A1      -> send the analog inputs every 50 ms (20-5000)
    STREAM OFF           -> stop the stream
    STATUS               -> state of pins 4-13 and A0-A5

  Answers use KEY=VALUE pairs: D = digital output, P = PWM, I = input,
  U = input with pull-up, S = servo angle, A = analog input, T = time in ms.
  Digital inputs report their changes automatically.

  Note: while a servo is attached, the Servo library uses Timer1 and
  PWM on pins 9 and 10 stops working.

  Serial speed: 9600 baud on both USB and Bluetooth (HC-05 default).
  If your HC-05 is configured at 38400, change BT_BAUD below.
*/

#include <SoftwareSerial.h>
#include <Servo.h>

const uint8_t BT_RX_PIN = 2;   // connected to HC-05 TXD
const uint8_t BT_TX_PIN = 3;   // connected to HC-05 RXD (through the divider)
const long USB_BAUD = 9600;
const long BT_BAUD = 9600;

const uint8_t FIRST_PIN = 4;
const uint8_t LAST_PIN = 13;
const uint8_t LINE_MAX = 40;
const uint8_t MAX_ARGS = 8;

enum QMode : uint8_t { M_OUT, M_PWM, M_IN, M_PULLUP, M_SERVO };

SoftwareSerial bt(BT_RX_PIN, BT_TX_PIN);
Servo servos[LAST_PIN - FIRST_PIN + 1];   // one per pin 4-13 (10 of the 12 available)

uint8_t pinModeOf[LAST_PIN + 1];
int pinValue[LAST_PIN + 1];                // output value, PWM value, input level or servo angle
Stream *lastOut = &Serial;                 // where spontaneous messages go

uint8_t streamMask = 0;                    // bit n = stream analog input An
unsigned long streamInterval = 0;
unsigned long lastStream = 0;
unsigned long lastInputPoll = 0;

char usbLine[LINE_MAX];
uint8_t usbLen = 0;
char btLine[LINE_MAX];
uint8_t btLen = 0;

bool isPwmPin(int p) {
  return p == 5 || p == 6 || p == 9 || p == 10 || p == 11;
}

// Accepts "13" or "D13". Returns -1 if not a usable pin.
int parseDigital(const char *t) {
  if (!t) return -1;
  if (*t == 'D') t++;
  if (*t < '0' || *t > '9') return -1;
  int p = atoi(t);
  return (p >= FIRST_PIN && p <= LAST_PIN) ? p : -1;
}

// Accepts "A0".."A5". Returns -1 if not valid.
int parseAnalog(const char *t) {
  if (!t || t[0] != 'A' || t[1] < '0' || t[1] > '5' || t[2] != 0) return -1;
  return t[1] - '0';
}

char modeLetter(uint8_t m) {
  switch (m) {
    case M_PWM: return 'P';
    case M_IN: return 'I';
    case M_PULLUP: return 'U';
    case M_SERVO: return 'S';
    default: return 'D';
  }
}

void printPin(Stream &out, int p) {
  out.print(modeLetter(pinModeOf[p]));
  out.print(p);
  out.print('=');
  out.print(pinValue[p]);
}

void releaseServo(int p) {
  if (pinModeOf[p] == M_SERVO) servos[p - FIRST_PIN].detach();
}

void makeOutput(int p) {
  releaseServo(p);
  if (pinModeOf[p] == M_IN || pinModeOf[p] == M_PULLUP || pinModeOf[p] == M_SERVO) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
    pinValue[p] = 0;
  }
  pinModeOf[p] = M_OUT;
}

void printStatus(Stream &out) {
  for (int p = FIRST_PIN; p <= LAST_PIN; p++) {
    printPin(out, p);
    out.print(' ');
  }
  for (int a = 0; a <= 5; a++) {
    out.print('A'); out.print(a); out.print('='); out.print(analogRead(A0 + a));
    if (a < 5) out.print(' ');
  }
  out.println();
}

void handle(char *line, Stream &out) {
  lastOut = &out;
  for (char *c = line; *c; c++) *c = toupper(*c);
  char *arg[MAX_ARGS];
  uint8_t n = 0;
  for (char *t = strtok(line, " "); t && n < MAX_ARGS; t = strtok(NULL, " ")) arg[n++] = t;
  if (n == 0) return;
  const char *cmd = arg[0];

  if (!strcmp(cmd, "PING")) {
    out.println(F("PONG QUASAR"));

  } else if (!strcmp(cmd, "HELP")) {
    out.println(F("OK PING HELP ON OFF TOGGLE PWM MODE SERVO READ STREAM STATUS"));

  } else if (!strcmp(cmd, "STATUS")) {
    out.print(F("STATUS "));
    printStatus(out);

  } else if (!strcmp(cmd, "ON") || !strcmp(cmd, "OFF") || !strcmp(cmd, "TOGGLE")) {
    int p = parseDigital(n > 1 ? arg[1] : NULL);
    if (p < 0) { out.println(F("ERR PIN 4-13")); return; }
    bool wasOn = pinModeOf[p] == M_OUT || pinModeOf[p] == M_PWM ? pinValue[p] > 0 : false;
    makeOutput(p);
    int v = !strcmp(cmd, "ON") ? 1 : !strcmp(cmd, "OFF") ? 0 : (wasOn ? 0 : 1);
    digitalWrite(p, v ? HIGH : LOW);
    pinValue[p] = v;
    out.print(F("OK ")); printPin(out, p); out.println();

  } else if (!strcmp(cmd, "PWM")) {
    int p = parseDigital(n > 1 ? arg[1] : NULL);
    if (p < 0 || !isPwmPin(p)) { out.println(F("ERR PWM PIN 5 6 9 10 11")); return; }
    if (n < 3) { out.println(F("ERR VALUE 0-255")); return; }
    makeOutput(p);
    int v = constrain(atoi(arg[2]), 0, 255);
    analogWrite(p, v);
    pinValue[p] = v;
    pinModeOf[p] = M_PWM;
    out.print(F("OK ")); printPin(out, p); out.println();

  } else if (!strcmp(cmd, "MODE")) {
    int p = parseDigital(n > 1 ? arg[1] : NULL);
    if (p < 0 || n < 3) { out.println(F("ERR MODE PIN OUT|IN|PULLUP")); return; }
    if (!strcmp(arg[2], "OUT")) {
      makeOutput(p);
      digitalWrite(p, LOW);
      pinValue[p] = 0;
    } else if (!strcmp(arg[2], "IN") || !strcmp(arg[2], "PULLUP")) {
      releaseServo(p);
      bool pullup = !strcmp(arg[2], "PULLUP");
      pinMode(p, pullup ? INPUT_PULLUP : INPUT);
      pinModeOf[p] = pullup ? M_PULLUP : M_IN;
      pinValue[p] = digitalRead(p);
    } else {
      out.println(F("ERR MODE OUT|IN|PULLUP")); return;
    }
    out.print(F("OK ")); printPin(out, p); out.println();

  } else if (!strcmp(cmd, "SERVO")) {
    int p = parseDigital(n > 1 ? arg[1] : NULL);
    if (p < 0 || n < 3) { out.println(F("ERR SERVO PIN 0-180|OFF")); return; }
    if (!strcmp(arg[2], "OFF")) {
      makeOutput(p);
      out.print(F("OK ")); printPin(out, p); out.println();
      return;
    }
    int angle = constrain(atoi(arg[2]), 0, 180);
    if (pinModeOf[p] != M_SERVO) {
      servos[p - FIRST_PIN].attach(p);
      pinModeOf[p] = M_SERVO;
    }
    servos[p - FIRST_PIN].write(angle);
    pinValue[p] = angle;
    out.print(F("OK ")); printPin(out, p); out.println();

  } else if (!strcmp(cmd, "READ")) {
    int a = parseAnalog(n > 1 ? arg[1] : NULL);
    if (a >= 0) {
      out.print('A'); out.print(a); out.print('='); out.println(analogRead(A0 + a));
      return;
    }
    int p = parseDigital(n > 1 ? arg[1] : NULL);
    if (p < 0) { out.println(F("ERR READ A0-A5|D4-D13")); return; }
    if (pinModeOf[p] == M_IN || pinModeOf[p] == M_PULLUP) pinValue[p] = digitalRead(p);
    printPin(out, p); out.println();

  } else if (!strcmp(cmd, "STREAM")) {
    if (n > 1 && !strcmp(arg[1], "OFF")) {
      streamMask = 0;
      out.println(F("OK STREAM OFF"));
      return;
    }
    long ms = n > 1 ? atol(arg[1]) : 0;
    uint8_t mask = 0;
    for (uint8_t i = 2; i < n; i++) {
      int a = parseAnalog(arg[i]);
      if (a >= 0) mask |= (1 << a);
    }
    if (ms < 20 || ms > 5000 || mask == 0) { out.println(F("ERR STREAM 20-5000 A0..A5")); return; }
    streamInterval = ms;
    streamMask = mask;
    lastStream = 0;
    out.println(F("OK STREAM ON"));

  } else {
    out.println(F("ERR UNKNOWN COMMAND"));
  }
}

// Collects characters until a newline, then runs the command.
void readLine(Stream &in, char *buf, uint8_t &len) {
  while (in.available()) {
    char c = in.read();
    if (c == '\r') continue;
    if (c == '\n') {
      buf[len] = 0;
      if (len > 0) handle(buf, in);
      len = 0;
    } else if (len < LINE_MAX - 1) {
      buf[len++] = c;
    }
  }
}

// Reports the inputs that changed since the last check.
void pollInputs() {
  for (int p = FIRST_PIN; p <= LAST_PIN; p++) {
    if (pinModeOf[p] != M_IN && pinModeOf[p] != M_PULLUP) continue;
    int v = digitalRead(p);
    if (v != pinValue[p]) {
      pinValue[p] = v;
      printPin(*lastOut, p);
      lastOut->println();
    }
  }
}

void sendStream() {
  lastOut->print(F("STREAM T="));
  lastOut->print(millis());
  for (uint8_t a = 0; a <= 5; a++) {
    if (!(streamMask & (1 << a))) continue;
    lastOut->print(F(" A")); lastOut->print(a); lastOut->print('=');
    lastOut->print(analogRead(A0 + a));
  }
  lastOut->println();
}

void setup() {
  for (int p = FIRST_PIN; p <= LAST_PIN; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
    pinModeOf[p] = M_OUT;
    pinValue[p] = 0;
  }
  Serial.begin(USB_BAUD);
  bt.begin(BT_BAUD);
  Serial.println(F("READY QUASAR CONSOLE 2"));
  bt.println(F("READY QUASAR CONSOLE 2"));
}

void loop() {
  readLine(Serial, usbLine, usbLen);
  readLine(bt, btLine, btLen);

  unsigned long now = millis();
  if (now - lastInputPoll >= 20) {
    lastInputPoll = now;
    pollInputs();
  }
  if (streamMask && now - lastStream >= streamInterval) {
    lastStream = now;
    sendStream();
  }
}

Domande frequenti

Chrome ed Edge su Windows, macOS, Linux e ChromeOS, e Chrome 137 o successivo su Android (solo Bluetooth). Safari, iPhone, iPad e Firefox non supportano Web Serial.

Sì. Su un computer collega la scheda con il cavo USB e scegli la sua porta: lo sketch risponde anche sull'USB. Su Android è disponibile solo il collegamento Bluetooth.

Sì. Lo sketch e la console funzionano con qualsiasi Arduino Uno o scheda con ATmega328P a 16 MHz, con gli stessi collegamenti.

Non con questa pagina: l'HC-05 usa il Bluetooth classico con il profilo seriale (SPP), che è quello supportato da Web Serial. I moduli BLE funzionano in un altro modo.

No. La connessione avviene interamente nel tuo browser, tra la pagina e la tua scheda. Solo i comandi vocali usano il riconoscimento vocale di Google in Chrome, che riceve l'audio del comando.

L'HC-05 usa una seriale software: mentre la scheda trasmette non può ricevere. Via Bluetooth usa un intervallo di 200 ms o più; via USB puoi scendere fino a 50 ms.

Torna a Quasar Basic