CAN-bus R4 Minima

Ciao a tutti!
Sto lavorando ad un progetto con 3 (anche se saranno probabilmente di più alla fine) UNO R4 Minima collegati insieme attraverso la rete CAN (pilotata dal chip dell'Arduino e collegata ad un transceiver SN65HVD230). Sto attendendo che mi arrivino tutti i componenti ma stavo intanto pensando al funzionamento.

Allora, io vorrei che due Arduino leggessero dei dati dai sensori ad essi collegati e li inviassero sulla rete CAN in continuazione, sempre mantenendo lo stesso ID su ogni pacchetto (per identificarne la provenienza). L'Arduino "main" dovrebbe occuparsi di scrivere i dati in arrivo su di una SD, ciclando tra i vari messaggi in arrivo e prendendo soltanto quelli provenienti dal sensore desiderato.

Dal momento che nella documentazione della libreria non mi pare di aver visto che si possa passare l'ID alla funzione .read() come posso riuscire a filtrare i dati in arrivo? E ci sarebbe un conflitto tra dati se questi viaggiano contemporaneamente sulla linea? (non credo dato che il CAN è usato nelle automobili dove viaggiano molti pacchetti diversi allo stesso tempo).

EDIT: Per comunicare tra le varie schede, secondo voi, è meglio il CAN o l'I2C?

Grazie in anticipo a tutti e buona serata!
Lucio

Non c'è paragone! Il CAN

Non puoi paragonarli. I2C è pensato per dialogo tra dispositivi elettronici mooooolto vicini, di solito MCU con sensori. Ma sempre molto vicini. Infatti esistono dei chip I2C extender.

Grazie ad entrambi, ora sono sicuramente più certo della mia scelta.

Per l'altra domanda più tecnica avete qualche idea?

Lucio

Non ho provato CAN bus ma dalle librerie vedo che ci sono comandi tipo CAN.getCanId() e CAN.sendMsgBuf(id,...
Perciò presumo nei msg ci siamo gli id

"comunicazione CAN"

Comunque anche non ci fosse un id, puoi sempre stabilirlo tu. Esempio il primo char che spedisci stabilisci è sempre id del sensore.

Mi potresti linkare le librerie? Perché da quello che ho cercato io non ho trovato granché...

Lucio

Quali librerie? ... la UNO R4 vuole la SUA libreria ... è quella che occorre includere ed è quella dove occorre cercare gli esempi.

Guglielmo

Esatto, è quello che ho visto anche io. Dato che @nid69ita citava un'altra libreria volevo rendermi conto di cosa fosse ma, come avevo già constatato, la R4 vuole la sua.
Quello che non sono riuscito a capire dalla libreria nativa è se la funzione .read() accetti un valore ID per filtrare i messaggi...sai consigliarmi qualcosa @gpb01 ?

Ovviamente grazie ad entrambi!
Lucio

Comunque anche non ci fosse un id, puoi sempre stabilirlo tu. Esempio il primo char che spedisci stabilisci è sempre id del sensore.

Allora, in fase di scrittura, come hai visto nell'esempio CANWrite.ino, il CAN Id va specificato nella creazione del messaggio:

CanMsg const msg(CanStandardId(CAN_ID), sizeof(msg_data), msg_data); , riga 47

Negli esempi che fanno di lettura NON lo vedo mai usato ed il metodo read() non lo prevede, però, leggendo i sorgenti, trovo questi due commenti (mi sembrano un po' poco chiari):

, _can_mailbox_mask
{
  CAN_DEFAULT_MASK,
  CAN_DEFAULT_MASK,
  CAN_DEFAULT_MASK,
  CAN_DEFAULT_MASK,
  0,                /* Use no id filtering -> a CAN frame with any ID will be stored in receive mailbox group #0. */
  CAN_DEFAULT_MASK,
  0,                /* Use no id filtering -> a CAN frame with any ID will be stored in receive mailbox group #2. */
  CAN_DEFAULT_MASK
}

... e poi trovo due metodi:

void R7FA4M1_CAN::setFilterId_Standard(size_t const mailbox, uint32_t const id)
{
  if (mailbox > CAN_MAX_NO_STANDARD_MAILBOXES)
    return;

  size_t const mailbox_idx = CAN_MAX_STANDARD_MAILBOX_OFFSET + mailbox;
  _can_mailbox[mailbox_idx].mailbox_id = id;
}

void R7FA4M1_CAN::setFilterId_Extended(size_t const mailbox, uint32_t const id)
{
  if (mailbox > CAN_MAX_NO_EXTENDED_MAILBOXES)
    return;

  size_t const mailbox_idx = CAN_MAX_EXTENDED_MAILBOX_OFFSET + mailbox;
  _can_mailbox[mailbox_idx].mailbox_id = id;
}

... che sembrerebbero servire ad impostare dei filtri sull'Id .. ma non so come vadano utilizzati.

Il reference purtroppo NON specifica nulla sull'utilizzo del Id.

Ho idea che dovrai fare un po' di prove e studiarti bene i sorgenti della libreria :roll_eyes:

Guglielmo

Ci sono anche altri due metodi interessanti:

void R7FA4M1_CAN::setFilterMask_Standard(uint32_t const mask)
{
  _can_mailbox_mask[6] = mask;
  _can_mailbox_mask[7] = mask;
}

void R7FA4M1_CAN::setFilterMask_Extended(uint32_t const mask)
{
  _can_mailbox_mask[4] = mask;
  _can_mailbox_mask[5] = mask;
}

... che permettono di impostare un "mask" ... :roll_eyes:

Ribadisco, tocca fare delle prove ... se scopri l'arcano, riporta qui che aiuti anche altri eventuali utilizzatori :slight_smile:

Guglielmo

P.S.: Note che è chiaramente indicato: "Arduino_CAN support both 11-Bit (standard) and 29-Bit (extended) IDs."

Ma hai visto l'esempio CANReadFilter? Mi sembra che usi i suddetti filtri ... :roll_eyes:

Nei commenti:

Receive and read CAN Bus messages
Read ID 0x100 EXTENDED and ID 0x10 STANDARD

... quindi filtra le read().

Guglielmo

Si avevo notato quei due metodi nella libreria, idem l'esempio, ma come hai notato tu non è molto chiaro.

Comunque aspetterò che venerdì mi arrivino i componenti ed inizierò facendo qualche prova...vi aggiorno!!

Buona serata e grazie ancora,
Lucio

Beh, no, l'esempio CANReadFilter è piuttosto chiaro, fa vedere esattamente come filtra i due ID di demo, sia quello standard (usa il valore 0x10) che quello extended (usa il valore 0x100).

Guglielmo

Secondo me il trucco è nell'oggetto CanMsg. L'id gli viene messo dentro come nell'esempio CANwrite.ino

Poi nella CANRead.ino dovrebbero specificarlo meglio, credo si usa getStandardId() oppure getExtendedId() (non so quale usare):

uint32_t const CAN_ID = 0x20;
void loop()
{
  if (CAN.available())
  {
    CanMsg const msg = CAN.read();
    if( msg.getStandardId() == CAN_ID )   // filtro il 0x20
    {  Serial.println(msg);
    }
  }
}

@gpb01 si quella parte si, confonde un po' l'inizio dove parla di "mailbox"

@nid69ita potresti avere ragione...non vedo l'ora di riuscire a fare qualche esperimento

Lucio

Ciao a tutti,
ho montato i componenti e gli esempi funzionano alla grande.
Ora, prima di filtrare i messaggi, dovrei capire come mandare sulla linea CAN testi e valori float...avete idee?

Lucio

Ni.
Occhio che i messaggi CANbus sono al massimo di 8 byte !! MAX_DATA_LENGTH = 8
quando crei o ricevi la variabile msg, essa è un oggetto che contiene:

  • id (intero senza segno a 32 bit)
  • data_length (lunghezza messaggio max 8)
  • data (gli 8 byte del mesaggio)

CanMsg const msg(CanStandardId(CAN_ID), sizeof(msg_data), msg_data);

msg.data[0] primo byte
msg.data[1] secondo byte
etc. fino a msg.data[7]
ancora meglio da 0 a msg.data_length

Allora forse ci sono...
uint8_t const msg_data[] = {0,0,0,0,0,0,0,0}; con questo alloco la memoria con un array di 8 byte che se stampo mi ritornerà una stringa di 8 zeri.

Ora quello che sono riuscito a fare è spedire una stringa dichiarandola come uint8_t const msg_data[] = "ciao"; e passandola direttamente a CanMsg. Ora quello che non mi torna è: a cosa mi serve la dichiarazione di prima? (direi a nulla).
In ogni caso l'output che ottengo è sempre hex...come lo ritrasformo in dato leggibile? usando string()?

Se usi la Serial.print del msg, l'oggetto CanMsg stampa i singoli byte che compongono il messaggio
Al link del mio post #19 hai il codice della classe CanMsg e guarda la printTo() che è quella incaricata di stampare in generale un CanMsg con un print
Ad un certo punto stampa i singoli byte in esa con snprintf(buf, sizeof(buf), "%02X", data[d])

Prova a fare Serial.println(msg.data); essendo data un array di byte (unsigned 8 bit) dovrebbe stamparlo come una stringa classica del C

string() credo sia un metodo della classe String, evitale su queste piccole MCU. Dobbiamo parlare di stringhe classiche del C ovvero array di unsigned char o array di byte terminati da null (valore 0)

uint8_t msg_data[] = "ciao"; è una stringa classica del C di 5 elementi, ovvero hai un array di byte con dentro i valori ascii dei caratteri esempio 'c' è 99 (in esadecimale 0x63)
msg_data[0] = 99
msg_data[1] = 105
msg_data[2] = 97
msg_data[3] = 111
msg_data[4] = 0