Pic Micro, Arduino, Atmel, Microchip, Freescale, Texas Instrument, ecc. Strumenti di sviluppo, firmware e progetti.
#5482
E te pareva, anche questa libreria non funziona in simulazione, scrive sulla seriale ma non legge i dati, il buffer risulta sempre vuoto e la funzione available() restituisce lunghezza ZERO...

Il problema è che questa libreria non fa uso di INTERRUPT, in pratica si usano i pin digitali come INPUT e OUTPUT interrogando l'ingresso ad intervalli regolari, questo non permette di avere un evento in tempo reale consentendo al buffer di riempirsi...

Anche qui ho tentato vari espedienti per aggiustare la libreria senza ottenere dei veri benefici, in rete tutti danno la colpa ad una inizializzazione dei pin errata e prematura, infatti ora Arduino ne adotta una nuova e corretta dagli stessi utenti e pare che funzioni meglio nella realtà, con il simulatore invece non sortisce alcunché...

Intanto bisogna innanzitutto far presente che tutti gli Arduino hanno la seriale nativa, ma cosa fare se quella è già impegnata a fare altro e c'è la necessità di comunicare tra i vari dispositivi connessi???

Qui bisogna necessariamente utilizzare la libreria SOFTWARESERIAL che aggiunge una funzionalità simile ma impostabile solo sui pin digitali del dispositivo, per la scrittura non ci sono problemi, ma la lettura deve essere fatta quando l'evento si manifesta, altrimenti il buffer viene regolarmente svuotato anche se con la funzione peek() si può ottenere l'ultimo carattere memorizzato, però in simulazione questo non accade visto che la seriale non è mai disponibile in lettura...

L'idea di testare questa libreria mi è venuta da una strana richiesta di un utente che avendo 5 schede Arduino NANO, voleva creare una OR digitale dei primi 4 che segnalasse all'ultimo che c'era un problema, il quinto doveva ricevere questo avviso per poi decidere in base al suo stato cosa fare, si raccomandava di usare meno componenti esterni possibili, quindi cosa c'è di meglio che non mettere proprio nulla???

Le seriali native sono state utilizzate per visualizzare con precisione gli RPM di un motore con sensori vari e per comunicare col PC, quindi non utilizzabili per fare altro a meno di non essere dei "grandi programmatori", perciò mi è balenata l'idea di semplificare il circuito creando una seriale virtuale mettendo in serie i vari Arduino NANO, in pratica da qualunque delle prime schede partisse l'Allarme, le altre fungono da ripetitore fino alla quinta scheda e creando così uno PSEUDO 1 WIRE OR...

COLLEGAMENTI:

1a Scheda - USCITA TX verso la 2a
2a scheda - INGRESSO RX dalla 1a e USCITA TX verso la 3a
3a scheda - INGRESSO RX dalla 2a e USCITA TX verso la 4a
4a scheda - INGRESSO RX dalla 3a e USCITA TX verso la 5a


(Volendo si può collegare la TX della 5a verso RX della 1a per comunicare ulteriori comandi lungo la catena ma non era richiesto)

Ogni scheda invia un carattere solamente che descrive il suo ID + ID del ripetitore, questo fa si da escludere eventuali falsi positivi lungo la catena, ogni scheda risponde solo a due eventi, il resto viene scartato:

1) Se deve segnalare un suo problema
2) Se deve fare solo da ripetitore per le schede precedenti

ESEMPIO PROBLEMA SCHEDA 1:

Invio il carattere (char)11 ovvero, ID(problema) = 1, ID(ripetitore) = 1

la seconda scheda lo legge come byte, se vale 11 allora lo ritrasmette al terzo dopo aver modificato l'ID ripetitore che diventa (char)12, questo significa che la scheda 1 ha un problema ed il messaggio viene ripetuto dalla seconda scheda...

In seguito sulla terza scheda si legge il byte che arriva e si verifica che sia valido, qui possono arrivare solo 2 tipi di segnalazione, (char)12 o (char)22, quindi un problema alla prima scheda o un problema alla seconda scheda...

Via così per tutta la serie delle schede fino all'ultima che verificherà se il messaggio è valido e potrà capire da chi è partito intervenendo a proposito...

Gli era stato consigliato di mettere una OR esterna per semplificare, così però non si riesce più a discriminare da dove proviene l'Allarme se non ricorrendo ad ulteriori collegamenti esterni che l'utente non voleva assolutamente fare, infatti ha pure rifiutato la soluzione dei 4 diodi ed una resistenza, de gustibus non disputandum est ...

Bene, visto che si intende più di programmazione che di Elettronica, ho pensato bene di suggerirgli questa soluzione che richiedeva poche righe di codice da aggiungere ad ogni programma, ma non ha forse capito cosa si poteva ottenere e quindi non l'ha presa neanche in considerazione, perciò la pubblico qui per eventuali interessati...

Torniamo prima a noi e al problema della simulazione in PROTEUS, gira e rigira alla fine ho trovato una libreria seria che ha funzionato al primo colpo senza esitazioni, qui il link alla stessa da scaricare e installare nelle cartella Documenti/Aruino/libraries/ copiandola semplicemente e rinominandola in AltSoftSerial...


Vediamo in dettaglio cosa fa questa libreria che è stata ottimizzata per funzionare bene anche a basse velocità che è quello che vogliamo per non inficiare sulla nativa e sulle prestazioni:

1) Impostazione automatica dei pin RX e TX in base al modello di processore
2) Usa l'INTERRUPT del TIMER1
3) Precisone degli eventi anche stand-alone

L'inizializzazione della seriale virtuale è stata automatizzata sapendo dal compilatore che scheda state usando e che processore monta, quindi imposta il suo funzionamento e ottimizzazione su pin specici, per esempio su Arduino NANO che monta un ATMEGA328P, i pin preposti sono il numero 8 per RX ed il numero 9 per TX, inoltre la libreria specifica anche quali funzioni non si possono usare quando si crea questa seriale basandosi sempre sul processore in questione, in questo caso facendo uso del TIMER1, non si potrà avere il PWM sul pin 10 (poco male, a noi non serve per ora), in fase di progettazione bisognerà però tenerne conto di questo, fortunatamente il frequenzimetro opera col TIMER2 e non disturba l'aggiunta dell'ultimo momento quando le schede sono state tutte già cablate...

LISTA PIN PER MODELLO:

Codice: Seleziona tuttoAltSoftSerial usa sempre questi pin:

Board                 TX        RX     NO PWM PINS
-----              --------  -------   -----------
Teensy 3.0 & 3.1      21        20         22
Teensy 2.0             9        10       (none)
Teensy++ 2.0          25         4       26, 27
Arduino Uno            9         8         10
Arduino Leonardo       5        13       (none)
Arduino Mega          46        48       44, 45
Wiring-S               5         6          4
Sanguino              13        14         12



Chiaro che bisogna sperare che i pin che ci servano siano liberi, difatti sono all'inizio di una PORT per rendere le cose ancora più semplici in caso di modifica e non guardate solo il nome della scheda, se monta lo stesso processore allora è compatibile con quelli, infatti la NANO è come la UNO...



SCHEMA SOTTO TEST:


5ArduinoChainRX_TX.png
Aggiungi descrizione



CODICE 1a SCHEDA:

Codice: Seleziona tutto// PRIMA SERIALE
#include <AltSoftSerial.h>


#define PROBLEM
//#undef PROBLEM

    AltSoftSerial mySerial; // 8 - RX, 9 - TX (PIN USATI CON ATMEGA328P, 10 - IL PWM NON FUNZIONA, LA LIBRERIA USA IL TIMER1)
   
void setup() {
    mySerial.begin(1200); // Stiamo bassi per non consumare risorse
}

void loop() {
#ifdef PROBLEM // Simula il problema da segnalare
    delay(3000);
    mySerial.print((char)11); // ID = 1, TX = 1, Problema riscontrato dal primo e trasmesso dal primo
#endif
}


CODICE 2a SCHEDA:

Codice: Seleziona tutto// SECONDA SERIALE
#include <AltSoftSerial.h>


#define PROBLEM
#undef PROBLEM

    AltSoftSerial mySerial; // 8 - RX, 9 - TX (PIN USATI CON ATMEGA328P, 10 - IL PWM NON FUNZIONA, LA LIBRERIA USA IL TIMER1)
   
void setup() {
    mySerial.begin(1200); // Stiamo bassi per non consumare risorse
}

void loop() {
#ifdef PROBLEM // Simula il problema da segnalare
    delay(3000);
    mySerial.print((char)22); // ID = 2, TX = 2, Problema riscontrato dal secondo e trasmesso dal secondo
#else
    if (mySerial.available() > 0) {
        byte rcv = mySerial.read();
        if (rcv == 11) { // controlla se il dato è valido
            mySerial.print((char)12); // ID = 1, TX = 2, Problema riscontrato dal primo e trasmesso dal secondo
        }
    }
#endif
}



CODICE 3a SCHEDA:

Codice: Seleziona tutto// TERZA SERIALE
#include <AltSoftSerial.h>


#define PROBLEM
#undef PROBLEM

    AltSoftSerial mySerial; // 8 - RX, 9 - TX (PIN USATI CON ATMEGA328P, 10 - IL PWM NON FUNZIONA, LA LIBRERIA USA IL TIMER1)
   
void setup() {
    mySerial.begin(1200); // Stiamo bassi per non consumare risorse
}

void loop() {
#ifdef PROBLEM // Simula il problema da segnalare
    delay(3000);
    mySerial.println((char)33); // ID = 3, TX = 3, Problema riscontrato dal terzo e trasmesso dal terzo
#else
    if (mySerial.available() > 0) {
        byte rcv = mySerial.read();
        byte trx = 0;
        switch (rcv) { // controlla se il dato è valido
            case 12: case 22:
                trx = (rcv - (rcv % 10)) + 3; // Modifica il TX del ripetitore
                mySerial.print((char)trx); // ID = X, TX = 3, Problema riscontrato dal X e trasmesso dal terzo
                break;
            default:
                // NOTHING TO DO
                break;
        }
    }   
#endif
}



CODICE 4a SCHEDA:

Codice: Seleziona tutto// QUARTA SERIALE
#include <AltSoftSerial.h>


#define PROBLEM
#undef PROBLEM

    AltSoftSerial mySerial; // 8 - RX, 9 - TX (PIN USATI CON ATMEGA328P, 10 - IL PWM NON FUNZIONA, LA LIBRERIA USA IL TIMER1)
   
void setup() {
    mySerial.begin(1200); // Stiamo bassi per non consumare risorse
}

void loop() {
#ifdef PROBLEM // Simula il problema da segnalare
    delay(3000);
    mySerial.write((char)44); // ID = 4, TX = 4, Problema riscontrato dal quarto e trasmesso dal quarto
#else
    if (mySerial.available() > 0) {
        byte rcv = mySerial.read();
        byte trx = 0;
        switch (rcv) { // controlla se il dato è valido
            case 13: case 23: case 33:
                trx = (rcv - (rcv % 10)) + 4; // Modifica il TX del ripetitore
                mySerial.print((char)trx); // ID = X, TX = 4, Problema riscontrato dal X e trasmesso dal quarto
                break;
            default:
                // NOTHING TO DO
                break;
        }
    }   
#endif
}



CODICE 5a SCHEDA:

Codice: Seleziona tutto// QUINTA SERIALE
#include <AltSoftSerial.h>

#define LED 13

    AltSoftSerial mySerial; // 8 - RX, 9 - TX (PIN USATI CON ATMEGA328P, 10 - IL PWM NON FUNZIONA, LA LIBRERIA USA IL TIMER1)
   
void setup() {
    mySerial.begin(1200); // Stiamo bassi per non consumare risorse
    pinMode(LED, OUTPUT);
}

void loop() {
    if (mySerial.available() > 0) {
        byte rcv = mySerial.read();
        byte IDx = (rcv - (rcv % 10)) / 10; // ID di chi ha lanciato l'Allarme
        switch (rcv) { // controlla se il dato è valido
            case 14: case 24: case 34: case 44:
                digitalWrite(LED, HIGH); // Esempio di segnalazione Allarme con LED sul pin 13
                delay(500);
                digitalWrite(LED, LOW);
                break;
            default:
                // NOTHING TO DO
                break;
        }
    }   
}



P.S. Non metto in dubbio che poteva starci tutto in una sola scheda o al massimo due, l'utente voleva una risposta rapida agli eventi con la massima precisione possibile, quindi per non complicarsi l'esistenza ha preferito optare su 1 sola operazione per scheda (in totale sono 14), il resto è stato solamente frutto della mia creatività per sopperire all'impossibilità di rifare tutto il cablaggio e la poca fantasia di dovergli riscrivere di nuovo il programma, un classico progetto UCAS dal quale non prendere spunto anche se pur ricco di idee...
Bios ringraziano
#5490
Ciao Giò, bel lavoro, giusto qualche osservazione :

Ogni scheda invia un carattere solamente che descrive il suo ID + ID del ripetitore, questo fa si da escludere eventuali falsi positivi lungo la catena, ogni scheda risponde solo a due eventi, il resto viene scartato:


Perchè dovrebbero esserci "falsi positivi"? Non sarebbe più semplice usare un byte di cui i primi 4 bit sono lo stato del rispettivo arduino, la sequenza diventa tipo (uguale per tutti)

#DEFINE WHOAMI 0 //il bit di identità 0,1,2 o 3

- ricevo il byte
- ho un problema? setto il bit WHOAMI
- trasmetto il byte

Così si potrebbe identificare anche problemi multipli, cosa che nel tuo esempio non mi pare avvenga.
Per il caso specifico poi, siccome non mi pare si fosse mai accennato al sapere nello specifico chi segnalasse l'allarme, potevano anche bastare 2 semplici pin IN e OUT tra i 4 arduino e dall'ultimo al quinto, da settare in caso di necessità.

Ciao, Ale.
GioRock, Bios ringraziano
#5495
Certo Ale,

il mio voleva essere solo un ulteriore esempio (anche per non sprecare il tempo per nulla), poi ognuno imposta il suo protocollo personale per comunicare, infatti se leggi l'ultima riga ho specificato che ci sono molte altre strade per non complicarsi la vita!!!

Ogni idea è comunque ben accetta e sono a conoscenza della tua passione per la Programmazione, quindi sei libero di pubblicare anche le tue varianti se ritieni che sia il caso...

P.S. Se invii un byte per la seriale, questa ti restituisce un numero anche di 3 byte e non solo un carattere da un byte, qui parte solo un carattere e basta... :shock:
Dimmer su aspirazione

Ciao a tutti ho una ventola di aspirazione in came[…]

Visita il nostro canale telegram