Go Down

Topic: Campionamento segnale analogico Arduino (Read 686 times) previous topic - next topic

docdoc

#45
May 21, 2019, 03:25 pm Last Edit: May 21, 2019, 03:27 pm by docdoc
Buon divertimento ... postaci il risultato :)
Perché? Non l'ho ancora fatto, ma parliamo di classi C++, aggiungere una readInt() ad una classe che deriva dalla HardwareSerial dovrebbe essere una cosa del genere:

Code: [Select]
class MyHardwareSerial: public HardwareSerial
{
   public:
     MyHardwareSerial();
     int readInt();
};


e quindi implementare il costruttore (non so se serva, ma richiamerebbe a sua volta quello HardwareSerial) e la "int readInt();" utilizzando due read().
Che problema ci vedi?
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

gpb01

#46
May 21, 2019, 03:36 pm Last Edit: May 21, 2019, 03:36 pm by gpb01
Che problema ci vedi?
Nessuno, il mio "buon divertimento" non era una battuta, era un invito a divertirsi a farlo ... io purtroppo NON ho il tempo, ma se tu lo trovi, poi facci sapere il risultato :)

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

Maurotec

Quote
Buon divertimento ... postaci il risultato :)
Se la è cercata lui. :)

Del resto per quanto mi riguarda è l'unico a poterlo fare.

Quote
Perché? Non l'ho ancora fatto, ma parliamo di classi C++, aggiungere una readInt() ad una classe che deriva dalla HardwareSerial dovrebbe essere una cosa del genere:
Troppo semplice no. Se però  dentro la int readInt(); ci metti dentro due read() non vale. Che poi a quanto mi risulta la read originale restituisce un int.

Code: [Select]

int read(void)
        {
        // if the head isn't ahead of the tail, we don't have any characters
        if (_head == _tail)
            return -1;
        else
            {
            byte c = _buffer[_tail];
            _tail = (_tail + 1) % rx_buffer_size;
            return c;
            }
}


Purtroppo _head e _tail sono private.

Code: [Select]

private:
    unsigned char _buffer[rx_buffer_size];
    volatile byte _head;
    volatile byte _tail;


Ciao.

Standardoil

#48
May 21, 2019, 03:51 pm Last Edit: May 21, 2019, 03:52 pm by Standardoil
Quindi serve restituire un long, con un codice di errore 'esterno' all'intervallo possibile per lo int normalmente restituito
E fin qui è facile, a similia della read normale che restituisce un byte espresso come int oppure un codice di errore che non appartiene all'intervallo possibile per un byte
Adesso viene il difficile:
Essendo gli indici non accessibili serve di fare un'available(), se rende 1 o 0 restituire il valore di errore.
Altrimenti eseguire le due read e restituire il valore giusto.
Giusto? Avrei i miei dubbi, dato che potrebbe anche essere che la trasmissione abbia saltato un passo, e i singoli byte siano ora sfalsati...
Prima legge di Nelson (che sono io): Non scambiare il fine con il mezzo: ricorda "cosa" devi fare, non "come" devi farlo

Non bado a studenti, che copino altrove

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

docdoc

#49
May 21, 2019, 04:07 pm Last Edit: May 21, 2019, 04:08 pm by docdoc
Che poi a quanto mi risulta la read originale restituisce un int.
Io dentro a HardwareSerial.cpp (di ArduinoCore-avr intendo) anche se è pur vero che la read restituisce int, il valore che restituisce lo vedo un unsigned char:

Code: [Select]
int HardwareSerial::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
  } else {
    unsigned char c = _rx_buffer[_rx_buffer_tail];
    _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
    return c;
  }
}

(non so tu da dove abbia preso quel codice)

Quote
Purtroppo _head e _tail sono private
Sono "protected":

Code: [Select]
class HardwareSerial : public Stream
{
  protected:
    volatile uint8_t * const _ubrrh;
...
    volatile rx_buffer_index_t _rx_buffer_head;
    volatile rx_buffer_index_t _rx_buffer_tail;
    volatile tx_buffer_index_t _tx_buffer_head;
    volatile tx_buffer_index_t _tx_buffer_tail;
...

Ma non vado mica a guardare quello, io invocherei solo due read(), ricomponendo i due byte in un int, che restituirei.

Appena ho un attimo a casa ci provo, anche perché con Arduino non ho mai esteso classi. :)
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

Maurotec

#50
May 21, 2019, 04:18 pm Last Edit: May 21, 2019, 04:25 pm by Maurotec
Quote
Essendo gli indici non accessibili serve di fare un'available(), se rende 1 o 0 restituire il valore di errore.
Altrimenti eseguire le due read e restituire il valore giusto.
Si deve decidere se accontentarsi della read attuale o no, se non ci si accontenta si deve mettere mano alla libreria e allora dovrebbe essere semplice restituire un signed long su cui salvare due byte.

Però noto una cosa; la read è interrompibile e non è protetta da questa possibilità, però funziona.

Leggendo il codice di LUFA : https://github.com/abcminiuser/lufa
noto come per sicurezza fa un cli() prima di aggiornare i puntatori e poi un restore sreg.

Allora penso che la read lavora correttamente solo perché la seguente porzione di codice,
Code: [Select]

byte c = _buffer[_tail];
_tail = (_tail + 1) % rx_buffer_size;

impiega meno cicli CPU di quanto ce ne vogliono da quando viene sollevato un IRQ a quando avviene il jump alla ISR. Tradotto quel codice impiega meno tempo di quello necessario per onorare un IRQ.

Ora se ingrassiamo la nuova read potrebbe non funzionare più e come fa LUFA per sicurezza:
Code: [Select]
salvo SREG
cli()
byte c = _buffer[_tail];   // ma ora 'c' dovrà essere un uint16_t
_tail = (_tail + 1) % rx_buffer_size;
restore SREG


Quote
(non so tu da dove abbia preso quel codice)
Vero l'ho preso dal posto sbagliato. questo link è corretto?
https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.h   


Ciao.

docdoc

Si deve decidere se accontentarsi della read attuale o no, se non ci si accontenta si deve mettere mano alla libreria e allora dovrebbe essere semplice restituire un signed long su cui salvare due byte.
Perché un signed long? 2 byte sono un int (se poi sia signed o meno diciamo che per ora possiamo ignorarlo).

Quote
Ora se ingrassiamo la nuova read potrebbe non funzionare più e come fa LUFA per sicurezza:
Si, ma come dicevo, io non "ingrasso" la read, la richiamo 2 volte dentro la readInt() (ovviamente solo se available >=2 ma solo per evitare di restituire dati "sporchi", questo è un controllo che delego all'utilizzatore/chiamante).

Quote
Vero l'ho preso dal posto sbagliato. questo link è corretto?
Eh si, te l'avevo indicato anche io nel mio precedente post... ;)

Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

Maurotec

#52
May 21, 2019, 04:48 pm Last Edit: May 21, 2019, 09:57 pm by Maurotec Reason: modificata uint16_t c = *(uint16_t*)&(_rx_buffer[_rx_buffer_tail]);
Quote
Si, ma come dicevo, io non "ingrasso" la read, la richiamo 2 volte dentro la readInt() (ovviamente solo se available >=2 ma solo per evitare di restituire dati "sporchi", questo è un controllo che delego all'utilizzatore/chiamante).
ahhh ok, si, però scomodare l'ereditarietà solo per questo.. non è meglio un funzione generica.

Comunque se poi vuoi provare visto che ci sei o modificato la read.

Code: [Select]

int32_t HardwareSerial::read(void)
    {
      // if the head isn't ahead of the tail, we don't have any characters
      if (_rx_buffer_head == _rx_buffer_tail) {
        return -1;
      } else {
         uint16_t c = *(uint16_t*)&(_rx_buffer[_rx_buffer_tail]); // funzionerà ???
        _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 2) % SERIAL_RX_BUFFER_SIZE;
        return c;
      }
    }




docdoc

Forse si, è da provare.

Ma generalmente tendo a non modificare le librerie, perché al primo aggiornamento mi perdo le personalizzazioni ;)
Alex "docdoc" - ** se ti sono stato d'aiuto, un punto karma sarà gradito, clicca su "add" qui a sinistra, vicino al mio nome ;) **

Go Up