Configurazione Porta Seriale Arduino M0

Buongiorno a tutti,
come da titolo, non so come far funzionare via software la porta seriale dell'Arduino M0. Ho cercato in rete ma ho avuto qualche difficoltà.
Potete darmi una mano? :slight_smile:
Devo collegare Arduino ad un sensore provvisto di porta UART.
Come posso configurare la comunicazione?

Come da reference:

Serial: 0 (RX) and 1 (TX). Used to receive (RX) and transmit (TX) TTL serial data using the ATSAMD21G18 hardware serial capability. Note that on the M0, the SerialUSB class refers to USB (CDC) communication; for serial on pins 0 and 1, use the Serial5 class.

Guglielmo

Mi da errore:

processing.app.debug.RunnerException
	at cc.arduino.packages.uploaders.SerialUploader.uploadUsingPreferences(SerialUploader.java:160)
	at cc.arduino.UploaderUtils.upload(UploaderUtils.java:82)
	at processing.app.SketchController.upload(SketchController.java:736)
	at processing.app.SketchController.exportApplet(SketchController.java:703)
	at processing.app.Editor$DefaultExportHandler.run(Editor.java:2028)
	at java.lang.Thread.run(Thread.java:748)
Caused by: processing.app.SerialException: Errore durante l'esecuzione del comando touch sulla porta seriale '/dev/ttyACM0'
	at processing.app.Serial.touchForCDCReset(Serial.java:107)
	at cc.arduino.packages.uploaders.SerialUploader.uploadUsingPreferences(SerialUploader.java:144)
	... 5 more
Caused by: jssc.SerialPortException: Port name - /dev/ttyACM0; Method name - openPort(); Exception type - Port busy.
	at jssc.SerialPort.openPort(SerialPort.java:164)
	at processing.app.Serial.touchForCDCReset(Serial.java:101)
	... 6 more

... non mi sembra un problema Arduino, ma stai cercando di aprire sulla tua macchina una porta seriale che non c'è: /dev/ttyACM0 ::slight_smile:

Te lo da in fase di caricamento del codice ? Hai selezionato la giusta porta dall'IDE ? Da sistema operativo vedi la porta nella cartella /dev ? Su che OS sei ?

Guglielmo

Ci sono due seriali sull'M0, Serial (o SerialUSB) sulla porta USB di programmazione e Serial1 (o Serial5) sui pin 0 e 1 e sulla USB nativa.
Occhio che i segnali sui pin 0 e 1 sono a 3V3. Se vuoi collegarla ad una UART TTL ti serve un convertitore di livelli logici. Da 5V a 3V3 e viceversa. Non ricordo se l'M0 è V5 tolerant.

gpb01:
… non mi sembra un problema Arduino, ma stai cercando di aprire sulla tua macchina una porta seriale che non c’è: /dev/ttyACM0 ::slight_smile:

Te lo da in fase di caricamento del codice ? Hai selezionato la giusta porta dall’IDE ? Da sistema operativo vedi la porta nella cartella /dev ? Su che OS sei ?

Guglielmo

Ho risolto, avevo aperto troppo presto la porta seriale :cold_sweat:

PaoloP:
Ci sono due seriali sull’M0, Serial (o SerialUSB) sulla porta USB di programmazione e Serial1 (o Serial5) sui pin 0 e 1 e sulla USB nativa.
Occhio che i segnali sui pin 0 e 1 sono a 3V3. Se vuoi collegarla ad una UART TTL ti serve un convertitore di livelli logici. Da 5V a 3V3 e viceversa. Non ricordo se l’M0 è V5 tolerant.

Il sensore ha come uscite una tensione da 3.3 V, quindi non ci dovrebbero essere problemi.
Però adesso mi segna sempre 0 come valori, prima il sensore era collegato ad Arduino 1 e leggevo correttamente i valori, ora invece mi segna sempre 0. Posto di seguito il codice:

void setup()
{
  SerialUSB.begin(115200);
  delay(2500);
  if(SerialUSB)
    SerialUSB.println("Porta USB: ATTIVA");
  Serial5.begin(9600);
  delay(2500);
  if(Serial5)
    SerialUSB.println("Comunicazione Seriale: ATTIVA");
}

typedef struct pms5003data   //Dati provenienti da PMS5003: 32 byte
{
  uint16_t lunghezza_frame;
  uint16_t pm1_standard, pm25_standard, pm10_standard;
  uint16_t pm1_amb, pm25_amb, pm10_amb;
  uint16_t particelle_03um, particelle_05um, particelle_1um, particelle_25um, particelle_5um, particelle_10um;
  uint16_t unused;
  uint16_t checksum;
}dat;

dat data;

void loop() 
{
  if(readPMSdata)   //Controllo sull'effettiva ricezione dei byte
  {
    SerialUSB.println("\n----------------------------------------");
    SerialUSB.println("Concentrazione Standard");
    SerialUSB.print("PM 1.0: ");
    SerialUSB.print(data.pm1_standard);
    SerialUSB.print("\t\tPM 2.5: ");
    SerialUSB.print(data.pm25_standard);
    SerialUSB.print("\t\tPM 10: ");
    SerialUSB.println(data.pm10_standard);
    SerialUSB.println("----------------------------------------");
    SerialUSB.println("Concentrazioni Ambientali");
    SerialUSB.print("PM 1.0: ");
    SerialUSB.print(data.pm1_amb);
    SerialUSB.print("\t\tPM 2.5: ");
    SerialUSB.print(data.pm25_amb);
    SerialUSB.print("\t\tPM 10: ");
    SerialUSB.println(data.pm10_amb);
    SerialUSB.println("----------------------------------------");
    SerialUSB.print("Particelle > 0.3um/0.1L aria: ");
    SerialUSB.println(data.particelle_03um);
    SerialUSB.print("Particelle > 0.5um/0.1L aria: ");
    SerialUSB.println(data.particelle_05um);
    SerialUSB.print("Particelle > 1.0um/0.1L aria: ");
    SerialUSB.println(data.particelle_1um);
    SerialUSB.print("Particelle > 2.5um/0.1L aria: ");
    SerialUSB.println(data.particelle_25um);
    SerialUSB.print("Particelle > 5.0um/0.1L aria: ");
    SerialUSB.println(data.particelle_5um);
    SerialUSB.print("Particelle > 50um/0.1L aria: ");
    SerialUSB.println(data.particelle_10um);
    SerialUSB.println("----------------------------------------");
  }
  delay(2000);
}

boolean readPMSdata(Stream *s)    //Controllo sull' arrivo dei bytes
{
  //Check fallito
  if(! s->available())
  {
    return false;
  }
  //Leggo un byte finche non ricevo '0x42' -> byte di start
  if(s->peek() != 0x42)   //Tramite peek() verifico il byte start
  {
    s->read();
    return false;
  }
  //Leggo tutti e 32bytes
  if(s->available()<32)
  {
    return false;   //Se non ricevo tutti e 32bytes
  }
  uint8_t buffer[32];
  uint16_t sum=0;
  s->readBytes(buffer,32);
  for(uint8_t i=0; i<30; i++)
  {
    sum+=buffer[i];
  }
  //Arrivo dei dati in "endian" per possibilità di lavoro in tutte la piattaforme
  uint16_t buffer_u16[15];
  for(uint8_t i=0;i<15;i++)
  {
    buffer_u16[i]=buffer[2 + i*2 +1];
    buffer_u16[i]+=(buffer[2 + i*2] << 8);
  }
  //Copio i dati nella struct
  memcpy((void*)&data,(void*)buffer_u16,30); //(destinazine,mittente,dimenzione)

  if(sum != data.checksum)
  {
    SerialUSB.println("!ERRORE! -> Check Fallito: Errore ricezione bytes");
    return false;
  }

  return true; //Se il check dei bytes è ok 
}

Scusa ma mi sembra che richiami la funzione readPMSdata senza passargli lo stream da cui leggere … ::slight_smile:

Guglielmo

Ok, ho capito cosa vuoi dire. Come passo lo stream da cui leggere?

Questo è il nuovo sketch che ho scritto:

void setup()
{
  SerialUSB.begin(115200);
  delay(2500);
  if(SerialUSB)
    SerialUSB.println("Porta USB: ATTIVA");
  Serial5.begin(9600);
  delay(2500);
  if(Serial5)
    SerialUSB.println("Comunicazione Seriale: ATTIVA");
}

typedef struct pms5003data   //Dati provenienti da PMS5003: 32 byte
{
  uint16_t lunghezza_frame;
  uint16_t pm1_standard, pm25_standard, pm10_standard;
  uint16_t pm1_amb, pm25_amb, pm10_amb;
  uint16_t particelle_03um, particelle_05um, particelle_1um, particelle_25um, particelle_5um, particelle_10um;
  uint16_t unused;
  uint16_t checksum;
}dat;

dat data;

void loop() 
{
  if(readPMSdata())   //Controllo sull'effettiva ricezione dei byte
  {
    SerialUSB.println("\n----------------------------------------");
    SerialUSB.println("Concentrazione Standard");
    SerialUSB.print("PM 1.0: ");
    SerialUSB.print(data.pm1_standard);
    SerialUSB.print("\t\tPM 2.5: ");
    SerialUSB.print(data.pm25_standard);
    SerialUSB.print("\t\tPM 10: ");
    SerialUSB.println(data.pm10_standard);
    SerialUSB.println("----------------------------------------");
    SerialUSB.println("Concentrazioni Ambientali");
    SerialUSB.print("PM 1.0: ");
    SerialUSB.print(data.pm1_amb);
    SerialUSB.print("\t\tPM 2.5: ");
    SerialUSB.print(data.pm25_amb);
    SerialUSB.print("\t\tPM 10: ");
    SerialUSB.println(data.pm10_amb);
    SerialUSB.println("----------------------------------------");
    SerialUSB.print("Particelle > 0.3um/0.1L aria: ");
    SerialUSB.println(data.particelle_03um);
    SerialUSB.print("Particelle > 0.5um/0.1L aria: ");
    SerialUSB.println(data.particelle_05um);
    SerialUSB.print("Particelle > 1.0um/0.1L aria: ");
    SerialUSB.println(data.particelle_1um);
    SerialUSB.print("Particelle > 2.5um/0.1L aria: ");
    SerialUSB.println(data.particelle_25um);
    SerialUSB.print("Particelle > 5.0um/0.1L aria: ");
    SerialUSB.println(data.particelle_5um);
    SerialUSB.print("Particelle > 50um/0.1L aria: ");
    SerialUSB.println(data.particelle_10um);
    SerialUSB.println("----------------------------------------");
  }
  //SerialUSB.println("Errore loop");
  delay(500);
  
}

boolean readPMSdata()
{
  if(!Serial5.available())
  {
    SerialUSB.println("Seriale -> ERRORE");
    return false;
  }
  else
  {
    SerialUSB.println("Seriale -> OK");
  }
  //Leggo un byte finchè non ricevo '0x42 e 0x4d' -> bytes di start
  char ctrl=Serial5.peek();
  SerialUSB.print("Byte di Start: ");
  SerialUSB.println(ctrl,HEX);
  if(ctrl!=0x42 && ctrl!=0x4d)
  {
    Serial5.read();
    SerialUSB.println("ERRORE -> Byte di start");
    return false;
  }
  //leggo tutti e 32 bytes
  if(Serial5.available()<32)
  {
    SerialUSB.println("ERRORE -> Dimenione byte");
    return false;
  }
  SerialUSB.println("Dimensione bytes: OK");

  //Carico 32 bytes nel buffer
  uint8_t buffer[32];
  uint16_t sum=0;
  Serial5.readBytes(buffer,32);
  for(uint8_t i=0; i<30; i++)
  {
    sum+=buffer[i];
  }
  uint16_t buffer_u16[15];
  for(uint8_t i=0; i<15; i++)
  {
    buffer_u16[i]=buffer[2 + i*2 +1];
    buffer_u16[i]+=(buffer[2 + i*2] << 8);
  }

  //Copio dati nella Struct
  //Indico: Destinazione, mittente dimensione:
  memcpy((void*)&data,(void*)buffer_u16,30);


  return true; //Se bytes OK
}

Effettua una prima lettura corretta, ma dalla terza in poi le letture mi riportano valori errati. Il sensore è un PSM5003 della plantower.

Nel Monitor Seriale ritrovo i seguenti dati:

Porta USB: ATTIVA
Comunicazione Seriale: ATTIVA
Seriale -> OK
Byte di Start: 42
Dimensione bytes: OK

----------------------------------------
Concentrazione Standard
PM 1.0: 143		PM 2.5: 149		PM 10: 149
----------------------------------------
Concentrazioni Ambientali
PM 1.0: 94		PM 2.5: 98		PM 10: 107
----------------------------------------
Particelle > 0.3um/0.1L aria: 11463
Particelle > 0.5um/0.1L aria: 3658
Particelle > 1.0um/0.1L aria: 92
Particelle > 2.5um/0.1L aria: 3
Particelle > 5.0um/0.1L aria: 1
Particelle > 50um/0.1L aria: 0
----------------------------------------
Seriale -> OK
Byte di Start: 42
ERRORE -> Dimenione byte
Seriale -> OK
Byte di Start: 42
Dimensione bytes: OK

----------------------------------------
Concentrazione Standard
PM 1.0: 143		PM 2.5: 149		PM 10: 149
----------------------------------------
Concentrazioni Ambientali
PM 1.0: 94		PM 2.5: 98		PM 10: 107
----------------------------------------
Particelle > 0.3um/0.1L aria: 11463
Particelle > 0.5um/0.1L aria: 3658
Particelle > 1.0um/0.1L aria: 92
Particelle > 2.5um/0.1L aria: 3
Particelle > 5.0um/0.1L aria: 1
Particelle > 50um/0.1L aria: 0
----------------------------------------
Seriale -> OK
Byte di Start: 4D
ERRORE -> Dimenione byte
Seriale -> OK
Byte di Start: 4D
Dimensione bytes: OK

----------------------------------------
Concentrazione Standard
PM 1.0: 36352		PM 2.5: 37888		PM 10: 38144
----------------------------------------
Concentrazioni Ambientali
PM 1.0: 24064		PM 2.5: 24832		PM 10: 27436
----------------------------------------
Particelle > 0.3um/0.1L aria: 40974
Particelle > 0.5um/0.1L aria: 14592
Particelle > 1.0um/0.1L aria: 22016
Particelle > 2.5um/0.1L aria: 512
Particelle > 5.0um/0.1L aria: 256
Particelle > 50um/0.1L aria: 151
----------------------------------------

il protocollo di comunicazione prevede 32 bytes così predisposti:

- Start character 1 -> 0x42 (fixed)
- Start character 2 -> 0x4d (fixed)

- Frame lenght high 8 bits -> Frame lenght=3x13+2(data+check bytes)
- Frame lenght low 8 bits  ->    "         "                      "

- Data 1 high 8 bits  ->   Data 1 refers to PM1.0 concentration unit μ g/m3(CF=1, standard particle)
- Data 1 low 8 bits  ->         "                    "                      "                          "

- Data 2 high 8 bits ->  Data 2 refers to PM2.5 concentration unit μ g/m3(CF=1, standard particle)
- Data 2 low 8 bits ->

- Data 3 high 8 bits ->  Data 3 refers to PM10 concentration unit μ g/m3(CF=1,standard particle
- Data 3 low 8 bits ->

- Data 4 high 8 bits -> Data 4 refers to PM1.0 concentration unit *μ g/m3(under atmospheric environment
- Data 4 low 8 bits ->

- Data 5 high 8 bits ->  Data 5 refers to PM2.5 concentration unit μ g/m3(under atmospheric environment)
- Data 5 low 8 bits ->

- Data 6 high 8 bits -> Data 6 refers to concentration unit (under atmospheric environment) μ g/m3
- Data 6 low 8 bits ->

- Data 7 high 8 bits -> Data 7 indicates the number of particles with diameter beyond 0.3 um in 0.1 L of air.
- Data 7 low 8 bits ->

- Data 8 high 8 bits ->  Data 8 indicates the number of particles with diameter beyond 0.5 um in 0.1 L of air.
- Data 8 low 8 bits ->

- Data 9 high 8 bits -> Data 9 indicates the number of particles with diameter beyond 1.0 um in 0.1 L of air.
- Data 9 low 8 bits ->

- Data 10 high 8 bits -> Data 10 indicates the number of particles with diameter beyond 2.5 um in 0.1 L of air.
- Data 10 low 8 bits ->

- Data 11 high 8 bits -> Data 11 indicates the number of particles with diameter beyond 5.0 um in 0.1 L of air.
- Data 11 low 8 bits -> 

- Data 12 high 8 bits ->  Data 12 indicates the number of particles with diameter beyond 10 um in 0.1 L of air.
- Data 12 low 8 bits ->

- Data 13 high 8 bits ->  Data 13 Reserved
- Data 13 low 8 bits ->

- Data and check high 8 bits -> Check code=Start character 1+ Start character 2+........+data 13
Low 8 bits
- Data and check low 8 bits ->

Non capisco dove sbaglio.
Usando lo stesso sketch su Arduino Uno con <SoftwareSerial.h> funziona perfettamente, utilizzando Arduino M0 presenta i problemi suddetti.