Go Down

Topic: Comandare ventola PWM con LIN BUS (Read 3249 times) previous topic - next topic

PM68

Certo!
La mia esigenza è di comandare due ventole PWM  ricevendo i comandi da rete LinBus.
La rete Lin Bus esiste già.
Ho un codice in grado di leggere il traffico sulla rete che mi restituisce una "sbrodolata" di byte (un esempio lo puoi vedere sopra).
Analizzando il traffico sulla rete ho identificato i gruppi di byte che corrispondono ai comandi di funzionamento per le ventole che sono:

0 60 FE 0 = ventola SX alle velocità 3
0 66 FE 0 = ventola SX alle velocità 2
0 78 FE 0 = ventola SX alle velocità 1
0 F8 0 = ventola DX alle velocità 3
0 F8 FE 0 = ventola DX alle velocità 2
0 78 0 0 0 0 F8 FE 0 = ventola DX alle velocità 1

Quello che non so fare ora è impostare due variabili di stato che cambiano ogni qualvolta passa sulla rete una delle sequenze di comando indicate sopra.
Dallo stato di queste variabili farei dipendere il comando PWM alle ventole.

Grazie per il tuo interessamento
 

Standardoil

Stasera, dopo il lavoro, vedi di mettere insieme qualcosa
Se mi dai due dritte tu sullo hardware, perché la cosa interssa anche me
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

gpb01

#17
Jun 20, 2018, 11:28 am Last Edit: Jun 20, 2018, 11:57 am by gpb01
>PM68: ... come ti dicevo devi identificare i vari stati ... leggi da seriale, sei in stato 0, ogni volta che leggi uno ZERO te lo segni e verifichi se il successivo è ancora ZERO. Se si, rimani in tale stato, se NO, verifichi che sia 60, oppure 66, oppure 78, oppure F8 ... questo ti porta a 4 differenti stati, in ognuno di questi verifichi se il carattere successivamente ricevuto è quello giusto, es. sei nello stato in cui hai ricevuto 66, se ricevi FE è un carattere valido e passi allo stato successivo (ventola SX alle velocità 2), altrimenti NON è valido e torni allo stato ZERO.

E' lungo, ma con qualche trucchetto (es. uso di array per memorizzare le giuste sequenze), NON è difficile da realizzare.

In pratica è un "parser" che cerca determinate sequenze e lo fa in tempo reale.

Guglielmo
Search is Your friend ... or I am Your enemy !

Standardoil

Alcune cose però non tornano
Linbus non lavora proprio così...
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

Standardoil

Comunque, stasera ci guardo e tento di darti due dritte
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

gpb01

#20
Jun 20, 2018, 12:01 pm Last Edit: Jun 20, 2018, 12:01 pm by gpb01
... LIN Protocol and Physical Layer Requirements ... con tutte le specifiche e la spiegazione del protocollo.

Ho idea che il problema va proprio affrontato in modo diverso ... ::)

Guglielmo
Search is Your friend ... or I am Your enemy !

PM68

Stasera, dopo il lavoro, vedi di mettere insieme qualcosa
Se mi dai due dritte tu sullo hardware, perché la cosa interssa anche me
L'hardware è semplicissimo:  Arduino DUE con LIN Transceiver MCP2004A.


PM68

>PM68: ... come ti dicevo devi identificare i vari stati ... leggi da seriale, sei in stato 0, ogni volta che leggi uno ZERO te lo segni e verifichi se il successivo è ancora ZERO. Se si, rimani in tale stato, se NO, verifichi che sia 60, oppure 66, oppure 78, oppure F8 ... questo ti porta a 4 differenti stati, in ognuno di questi verifichi se il carattere successivamente ricevuto è quello giusto, es. sei nello stato in cui hai ricevuto 66, se ricevi FE è un carattere valido e passi allo stato successivo (ventola SX alle velocità 2), altrimenti NON è valido e torni allo stato ZERO.

E' lungo, ma con qualche trucchetto (es. uso di array per memorizzare le giuste sequenze), NON è difficile da realizzare.

In pratica è un "parser" che cerca determinate sequenze e lo fa in tempo reale.

Guglielmo
Grazie Guglielmo, ho capito come intendi gli stati. Questa sera inizio a lavorarci.

Standardoil

mah, ho dei dubbi, e te li esprimo subito
primo) il protocollo prevede una trasmissione che inizia con 0x55 (che poi sarebbe solo una sequenza di 01 alternati) e non li vedo nei tuoi dati, questo probabilemte significa solo che il trasnceiver "strippa" quasto byte, che in effetti serve solo per dare il sincronismo e l'isocronia tra i dispositivi
secondo) il protocollo prevede che il master trasmetta UN solo byte che contiene, se ho letto bene, sia indirizzo dello slave che comando, con 2 bit di parità, e questo è ben strano da fare con arduino.
io questo lo interpreto che l'indirizzo è il primo byte nelle tue sequenze, ma dovrebbe essere uguale per i tre comandi della ventola di destra, e nel tuo flusso non è così
terzo) lo slave (o il master se il comando richiede argomenti) trasmette subito dopo da 0 a 8 byte (0 se non è prevista risposta, ovviamente) con un checksum di un byte (opzionale, per modo di dire, sembra che nulla nel protocollo sia lasciato libero, il progettista del sistema deve decidere utti i dettagli, quindi il checksum potrebbe non esserci, ma se c'è non è opzionale)
e qui, io mi aspetto che per comandi omologhi (che vuol dire simili tra due dispositivi simili) la lunghezza del messaggio sia la stessa, e nei tuoi dati non è così
quarto) se ci fai caso la sequenza "0 78 0 0 0 0 F8 FE 0 = ventola DX alle velocità 1" contiene al suo interno la sequenza "0 F8 0 = ventola DX alle velocità 3", che mi fa pensare a qualcosa di strano
comunque, il tuo problema adesso è riconoscere sequenze, e guardacaso anche il mio (in un'altro contesto) quindi sono ben lieto di condividere con te, lasciami solo il tempo di "dare forma" alle mie idee
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

Standardoil

#24
Jun 20, 2018, 06:25 pm Last Edit: Jun 20, 2018, 09:58 pm by Standardoil
Ok, fatto al volo
NON lo ho fatto per te, ma perchè mi serviva per altro, ma comunque sarai il primo a provarlo, io non ho una DUE per provare, non posso nemeno compilare, dato che non ho le librerie
per prima cosa la loop()
Code: [Select]

void loop(void)
{
    byte comando = 0;
    if (Serial1.available())
      {
        // un byte disponibile
        // passo a trattarlo
        comando = parserizza((byte)Serial1.read());
        // tutto il lavoro lo fa la parserizza
        // che restituisce un valore numerico
        // 0 per non trovato
        // 1 per trovato primo comando
        // 2 per trovato.......
    }

    switch (comando)
    {
        case 0:
            // nessun comando da eseguire
            break;

        case 1:
            // qui eseguo il primo comando
            break;

        case 2:
            // qui eseguo il secondo comando
            break;

        // e via così....
        default:
            // comando non trovato
    }
}

come vedi ho semplicemente passato il lavoro sporco ad una funzione apposita, che riceve un byte per volta dalla loop, solo se la seriale è available
e restituisce 0 se non ha ancora trovato un comando valido
il numero del comando se lo ha trovato
e poi una switch case esegue il comando, abbastanza banale
per seconda cosa la funzione di parser
Code: [Select]

byte parserizza(byte in)
{
    // riceve byte a byte un comando e lo usa per riconoscere il comando complessivo
    // dichiaro una matrice di matrici di byte
    // il problema è che le sequenza non hanno lunghezza uguale tra loro
    // quindi devo anche dichiarare un array di lunghezze
    // potessi usare le stringhe, sarebbe comodo ma esistono degli 00 nel flusso
    // quindi una matrice bidimensionale di byte (larga quanto il più lungo comando)
    // con una matrice monodimensionale di lunghezze
    byte comandi[6][9];// 6 comandi per nove byte massimi
    byte lunghez[6]; // 6 lunghezze
    // inizializzo
    comandi[1] = {0x00, 0x60, 0xFE, 0x00};
    lunghez[1] = 4;
    // e qui si prosegue per gli altri 5 comandi possibili
    // siccome leggo il comando byte a byte devo tenere traccia di quanto lungo ho letto
    // e siccome devo confrontarlo con 6 possibili comandi devo avere sei indici, uno per possibile comando
    // statico per non perdere l'informazione da un ingresso al successivo
    static byte trovato[6] = {0, 0, 0, 0, 0, 0}; // variabili locali vanno inizializzate

    // adesso conosco un byte e vedo se corrisponde con la posizione raggiunta in ognuno dei possibili comandi
    for (byte i = 0; i < 6; i++)
    {
        // per ogni comando
        if (comandi[i][trovato[i]] != in)
        {
            // se il byte 'in' non corrisponde al byte in posizione [trovato[i]]
            // non e' il carattere giusto
            trovato[i] = 0; // riporto indietro il contatore
        }
        else
        {
            // è il carattere giusto
            // delle due l'una
            // o siamo alla fine del comando oppure no
            if (trovato[i] == lunghez[i])
            {
                // comando finito, ho trovato tutti i byte
                // riporto a zero l'indice, per ripartire bene la prossima volta
                trovato[i] = 0;
                // me ne esco da questa funzione restituendo il numero del comando trovato
                // più uno perchè zero indica comando non trovato
                return i + 1;
            }
            else
            {
                // comando non ancora finito, devo aspettare altri byte per sepere se è il giusto
                // aggiorno l'indice per controllare il prossimo byte
                trovato[i]++;
            }
        }
    }

    // se sono arrivato fin qui vuol dire che non ho trovato nessun comando
    // restituisco 0 -> comando non trovato
    return 0;
}

Tieni presente che ho appena finito di scriverla, e non so se compila, casomai vedi che problemi ti da
fondamentalmnte una matrice bidimensionale di byte, che contengono le sequenze possibili di byte in ricezione
letta "riga a riga" si può interpretare come una matrice di sequenze
quindi, in una for, sequenza per sequenza, controlla se il byte appena arrivato corrisponde al punto che ha già raggiunto, se corrisponde e ha finito la sequenza restiruisce il numero della sequenza riconosciuta
se corrisponde e non ha finito la sequenza "avanza di uno" nella lettura della sequenza
se non corrisponde riporta a zero l'indice di lettura
se non corrisponde per nessuna sequenza restituisce 0 per dire che non ha ancora trovato nulla
Personalmente credo che non andrà, per i dubbi che ti avevo esposto prima, ma tentar onn nuoce
a comunque NON accenderà mai la ventola DX a velocità 1, dato che con quella sequenza comunque interpreta ventola DX velocità 3
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

PM68

Grazie Standardoil!
Io sono un principiante di Arduino e non ho basi di informatica. Ho letto il tuo codice e qualcosa ho capito ma ora mi concentro e lo studio bene.
Ti faccio sapere appena lo provo.

Concordo con te sui dubbi che mi hai espresso riguardo la "sbrodolata" di byte che non rispetta il protocollo LinBus. Ho cercato una tabulazione che desse una logica uguale a tutti i frame ma non l'ho trovata.
Può esserci qualcosa che sbaglio nella lettura?
All'inizio avevo sbagliato la velocità, avevo messo 9600 mentre la LinBus trasmette a 19200 e leggevo altri dati e molti codici 7F che è il codice di errore.
Ho provato anche a variare la uint8_t rxByte[8] e l'ho portata a 16 e 32 ma non è cambiato niente.
Se hai qualche suggerimento posso modificare e provare.

Io ho supposto fosse una LinBus perchè ho visto sulla scheda elettronica che comanda queste ventole che c'è un integrato TJA1020 che è un LIN transceiver. Però la macchina è Giapponese, forse loro hanno protocolli diversi. Inoltre la Toyota non è tra i costruttori che hanno promosso lo sviluppo del protocollo LinBus.

Standardoil

Purtroppo qui non posso aiutarti, non conosco il protocollo LIN, tutto quello che so lo ho letto oggi nei documenti postati da Guglielmo, e lo ho scritto qui...
attento che ho fatto una piccola modifica al mio post precedente, avevo dichiarato la variabile comando in un blocco 'if', andava dichiarata subito prima, ho spostato la riga
continuo a non poter compilare, quindi non posso garantire nulla, ma a occhio sembra poter andare
in effetti somiglia molto ad una macchina a stati, in realtà ad un array di 6 macchine a stati, che aggiorna 6 stati per ogni byte ricevuto
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

PM68

Ma "parserizza" necessita di una libreria? Mi dice 'parserizza' was not declared in this scope.

Standardoil

no' è tutto buon 'C' in sorgente
dubbio: oltra alla loop() hai copiato anche la parserizza(), vero?
anno' forse ho capito
se bob compila la parserizza ti da una vagonata di errori
vedo se ci ho lasciato dentro qualche castroneria.......
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

Standardoil

ho sbagliato a inizializzare gli array
così adesso a me compila, ma natiralmente mi manca tutto il resto
Code: [Select]

// di Nelson "StandardOil"
// Idea da sviluppare:
void setup(void)
{
}

void loop(void)
{ byte comando = 0;
    if (Serial1.available())
       

    {
        // un byte disponibile
        // passo a trattarlo
        comando = parserizza((byte)Serial1.read());
        // tutto il lavoro lo fa la parserizza
        // che restituisce un valore numerico
        // 0 per non trovato
        // 1 per trovato primo comando
        // 2 per trovato.......
    }

    switch (comando)
    {
        case 0:
            // nessun comando da eseguire
            break;

        case 1:
            // qui eseguo il primo comando
            break;

        case 2:
            // qui eseguo il secondo comando
            break;

        // e via così....
        default:
            // comando non trovato
            break;
    }
}

byte parserizza(byte in)
{
    // riceve byte a byte un comando e lo usa per riconoscere il comando complessivo
    // dichiaro una matrice di matrici di byte
    // il problema è che le sequenza non hanno lunghezza uguale tra loro
    // quindi devo anche dichiarare un array di lunghezze
    // potessi usare le stringhe, sarebbe comodo ma esistono degli 00 nel flusso
    // quindi una matrice bidimensionale di byte (larga quanto il più lungo comando)
    // con una matrice monodimensionale di lunghezze
    byte comandi[6][9];// 6 comandi per nove byte massimi
    byte lunghez[6]; // 6 lunghezze
    // inizializzo
    comandi[1][1] = 0x00;
    comandi[1][2] = 0x60;
    comandi[1][3] = 0xFE;
    comandi[1][4] = 0x00;
    lunghez[1] = 4;
    // e qui si prosegue per gli altri 5 comandi possibili
    //siccome leggo il comando byte a byte devo tenere traccia di quanto lungo ho letto
    //e siccome devo confrontarlo con 6 possibili comandi devo avere sei indici, uno per possibile comando
    // statico per non perdere l'informazione da un ingresso al successivo
    static byte trovato[6] = {0, 0, 0, 0, 0, 0}; // variabili locali vanno inizializzate

    // adesso conosco un byte e vedo se corrisponde con la posizione raggiunta in ognuno dei possibili comandi
    for (byte i = 0; i < 6; i++)
    {
        // per ogni comando
        if (comandi[i][trovato[i]] != in)
        {
            // se il byte 'in' non corrisponde al byte in posizione [trovato[i]]
            // non e' il carattere giusto
            trovato[i] = 0; // riporto indietro il contatore
        }
        else
        {
            // è il carattere giusto
            // delle due l'una
            // o siamo alla fine del comando oppure no
            if (trovato[i] == lunghez[i])
            {
                // comando finito, ho trovato tutti i byte
                // riporto a zero l'indice, per ripartire bene la prossima volta
                trovato[i] = 0;
                // me ne esco da questa funzione restituendo il numero del comando trovato
                // più uno perchè zero indica comando non trovato
                return i + 1;
            }
            else
            {
                // comando non ancora finito, devo aspettare altri byte per sepere se è il giusto
                // aggiorno l'indice per controllare il prossimo byte
                trovato[i]++;
            }
        }
    }

    // se sono arrivato fin qui vuol dire che non ho trovato nessun comando
    // restituisco 0 -> comando non trovato
    return 0;
}

consiglio: sposta l'inizializzazione degli array prima della setup
così diventano globali e non vengono ripetuti tutte le volte
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

Go Up