Go Down

Topic: [Algoritmo] Mutua esclusione multipla. Non ci riesco... (Read 6392 times) previous topic - next topic

Maurotec

#30
Apr 24, 2014, 05:05 pm Last Edit: Apr 24, 2014, 08:11 pm by leo72 Reason: 1
Ho la tentazione di infierire, anzi infierisco proprio.
Ma insomma le vogliamo imparare ad usare ste struct e ste funzioni.

Certo tempo permettendo, ma è cosa di mezza giornata, perché già il concetto di sezione ti è familiare, se disegni
una centralina che ha 7 led di segnalazione tu non li spargi per il disegno ma li metti tutti in fila, nomini ogni terminale e fai lo stesso lato MCU. Con il codice si procede allo stesso modo, ma capisco che non è facile.

Comunque tu quindi
Code: [Select]
if(code == 11)  lo hai ripetuto n volte quanti sono i contatti?
Terribile, lungo, noioso.
Come procederei io:

Proprio dove leggi i dati, cioè dove c'è il read di I2c collezionerei tutti i dati inerenti i contatti in una variabile struct.
Es di struct
Code: [Select]
typedef struct {
   uint8_t id;                    // il numero del contatto, cioè quello che arriva
   uint8_t alarmCode;    // Il tipo di alarm, da 0 255
   uint8_t section;          // a quale gruppo o sezione di macchine
} IDContact;

IDContatct *idContatctList[N_MAX_CONTATCT ];


mmm.. mi mancano altre info per continuare.

La versione semplice:

Serve una variabile lastHighPriorityCode dichiarata da qualche parte in modo simile a:
Code: [Select]
#define N_MAX_CONTATCT  50
typedef uint8_t PriorityCode;
PriorityCode lastHighPriority = N_MAX_CONTACT

if (code < lastHighPriority)
   lastHighPriority = code;

prima di stampare
Code: [Select]

if (oldPriorityCode != lastHighPriority)
   show();

dopo aver stampato
Code: [Select]
oldPriorityCode = lastHighPriority;

Prova a vedere se è sufficiente.

Ciao.

BaBBuino

Si, l'ho riputo millemila volte per il nr dei contatti.
In effetti mi ero ripromesso di fare una sola funzione ripetuta 100 volte, ma oramai avevo fatto il copia incolla per 100 volte e l'ho lasciato così anche perchè ogni contatto deve avere abbinata una stringa diversa che avrei cmq dovuto scrivere con un #define.

Che info ancora ti mancano?

PaoloP


BaBBuino

Nulla è più definitivo di ciò che parte come prova-prototipo.

Maurotec

Fammi vedere la parte iniziale del loop e la parte dove inizi a leggere i dati in arrivo da i2c, come pure
quando assegni a code un valore, da dove proviene.

Ciao.

BaBBuino

Scusate l'assenza ma ero in una micro-vacanza. Tra l'altro la sera delle prove, in realtà, non ho potuto provare granchè perchè il macchinario era impegnato in manutenzione.

C'è una novità, mi è venuto in mente che ci può essere un problema di natura Hardware-Software.

Il ciclo dello SLAVE che legge i dati in arrivo dalla I2C, NON lo fa in polling, ma con questa funzione:

Wire.onReceive(receiveEvent);

Che mi pare funzioni su un Interrupt lanciato dalla periferica interna I2C dell'ATmega328.

Ho il forte sospetto che quando c'è un'interruzione multipla, di 7-8 contati, il sistema MASTER spedisce continuamente i dati che pesca in Polling dalle seriali, verso lo SLAVE in I2C, però quest'ultimo non riesce mai a portare a termine la funzione Highlander() perchè continua ad essere interrotta dall'Interrupt dell I2C.

E' plausibile questo?

Nel caso ho ipotizzato qualcosa del genere:

Se_ArrivaDatoI2C()     {     //////sto dando dei nomi a caso per rendere l'idea
cli();   ////disabilito gli Interrupt, così non mi danno fastidio durante la ricerca
Highlander();  //// Funzione che mi tira fuori il primo contatto della serie
sli(); riattivo gli interrupt
} //esco dalla funzione di recupero del dato

Può andare?


BaBBuino

Questa è la funzione che acchiappa i dati I2C spediti dal MASTER:

Code: [Select]
void receiveEvent(int data)
{
//questo evento viene generato quando sul bus
//è presente un dato da leggere
  if ((Wire.available() > 0) && (Wire.available() < 2)) {   /// Funzione che mi conferma (199) il funzionamento del Bus I2C
  unsigned char okey = Wire.read();                                   ///  e mi stampa la stringa "I2C OK " in un angoletto dello schermo
     if(okey == 199){
       myGLCD.setFont(BigFont);
       myGLCD.setColor(VGA_BLUE);
       myGLCD.print("I2C OK", 70, 0);
      }
  }
 
unsigned char alarm = 0;
unsigned char code = 0;

if (Wire.available() >=2) {  /// dati dei contatti inallarme in arrivo
   for(int i = 0 ; i < 2; i++)
            buff[i] = Wire.read();
//eseguo la lettura
  code = buff[0];    /// Codice-numero del contatto
  alarm = buff[1];   ///  tipo di allarme, se Rosso o Giallo

////////////////////////////////////////////////////////  1
if(code == 11) { ////   qua inizia la routine di mutua esclusione

lestofante

#37
Apr 29, 2014, 09:07 pm Last Edit: Apr 29, 2014, 09:17 pm by lesto Reason: 1
no, nonpuò andarte perchè disattivando gli interrupt disabiliti anchela seriale, e quindi perdi i dati. In oltre normalmente dentro un iterrup, gli interrupt sono già disattivati: ed ecco il possibile problema! mentre elabori un dati perdi gli altri. Insomma, il tuo interrupt è troopo lungo! smettila di usare receiveEvent e sposta il codice nel loop(), così non hai più problemi. Al massimo in receiveEvent() "risvegli" il chip se necessario


immagino che leggi dati invalidi ogni tanto... o se non succede è solo perchp usi un bad abbastanza veloce o un ciclo abbstanza lento.

inoltre se nella primalettura NON leggi 199, comunque se ci sono 2 byte disponibili li leggi (e quindi immagino leggi cacca)

io farei:

Code: [Select]

void loop(){
 while ((Wire.available() > 2) { // finchè ci sono almeno 3 byte da leggere
   unsigned char okey = Wire.read();
   if(okey == 199){// il valore è valido, prosegui la la lettura
     myGLCD.setFont(BigFont);
     myGLCD.setColor(VGA_BLUE);
     myGLCD.print("I2C OK", 70, 0);
     code = Wire.read();    /// Codice-numero del contatto
     alarm = Wire.read();   ///  tipo di allarme, se Rosso o Giallo
     checkIfCodeIsBiggerThanActualAlarm(code, alarm);
   }else{
     //not ok, non leggere nulla, il while ricomincia e se ci sono ancora almeno 3 byte disponibili, rifarà il controllo del primo, e via andare finchè non trova come primo byte letto 199 (ed effettua una lettura) o ci sono meno di 3 byte. Sarebbe da segnalare l'errore, se si accumulano c'è troppo disturbo in linea, oppure un chip impazzito/rotto.
   }
 }
}


comunque io ti chiedo gentilemnte uno schema elettrico delle connessioni tra contatti e da contatti e master/slave, chenon ci sto più a capire una bega.

io mi immagino come soluzione efficiace:

UN master, che va in polling sugli slave, a partire da quello che ha priorità 1 fino al 100 (o fino al primo errore: in tal caso segnala l'errore e ricomincia il ciclo, inutile andare oltre. quando finalmente continua il ciclo è perchè l'errore a monte è stato risolto, quindi gli errori successivo è da segnalare. Niente tasto reset!)
il polling va bene tanto il master fa solo quello.

oppure se il master fosse un pc o deve fare altro, o vuoi fare le cose fighette, va bene l'idea che il master riceve l'interrupt, ma essi devono essere di:
ALLARME TIPO x ON SUL PIN y
ALLARME TIPO x ON SUL PIN y FINITO

a questo punto però il master DEVE avere abbastanza ram per contenere una struttura per ogni pin (e con un atmega328 NON ce la fai, un array di 100 int è già rischioso da fare), e alla fine dei conti anzichè fare il ciclo da 1 a errore sugli slavelo fai sull'array, e il tuo loop() che leggerela seriale semplicemente aggiorna l'array; quindi ricevi "l'intterrupt", che DEVE essere veloce, e 1 quindi semplicemente copi il byteletto su un buffer. (in oltre non puoi modificare l'array mentre lo stai eseguendo, crei un disallineamento dei dati che si risolve usando un database e/o query/codice atomico).
Quindi ogni loop leggi tutti i byte arriavi a 3 a 3 e aggiorni l'array di stati, poi scorri l'array stati e segnali il primo allarme che trovi e ricominci. Magari ti salvi il numero dell'ultimo allarme, così se è diverso segnali all'operatore che sì ha riparato un guasto, ma ce ne è già un altro in cascata.
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

Maurotec

Meno male che ti ho chiesto di mostrarmi l'inizio della routine che intercetta i dati.
Il problema è dovuto al fatto che la routine impegna per troppo tempo il micro che diventa sordo ad altre richieste di interrupt come ad esempio quelle in ricezione sulla seriale, cioè di perdi dati.

Se vuoi usare ancora la funzione attuale la devi ridurre a:
Ricevi dato, metti in buffer e fine.
Il buffer poi lo consumi nel loop.
Puoi usare un ring buffer con start buffer e end buffer dinamici, cioè entra un nuovo dato messo in coda e endBuffer++, consumi un dato è startBuffer++;

Ciao.

BaBBuino

Mauro non perdo dati, perchè la scheda che raccoglie i dati dalle seriali è un'altra scheda (una DUE) la quale li passa (solo se sono valori sotto soglia, quindi errori) in I2C ad una seconda scheda che fa l'analisi di questi dati, tirando fuori l'Highlander.

Sembra che ho risolto con questo sistema, ma era l'una di notte e l'Elettromeccanico dove fare le sue cose e mi guardava male, quindi ho dovuto concludere in fretta senza fare troppe prove (leggi: un numero sufficiente di simulazioni di allarme per verificare che l'Highlander lo sia effettivamente in tutti  i rami della macchina)

Quindi:

------------------------------------
Faccio partire un Timer ( millis())

Raccolgo dati per circa 30 secondi
infilo i dati ricevuti in un array[ ]  (la board è una MEGA2560, non un 328!)
Se un codice errore è già stato letto, lo scarto

Fermo il timer a 30 secondi.
La MCU diventa sorda
Dopo di che eseguo la ricerca in mezzo a quell'array dell'Highlander
lo stampo sulla riga 1 del Display

La MCU si rimette in ascolto
Solito timer, solito riempimento dell'array e solito stop

Se l'allarme è sempre lo stesso di prima, viene ignorato, se ce n'è uno nuovo, lo stampa sulla riga 2 del Display
-----------------------------------------------

In pratica uso il principio di una macchina fotografica di cui regolo a 30 sec il tempo di esposizione e, fatta la fotografia, analizzo i dati  all'interno di quella foto. Poi via un'altro scatto e altra analisi.

Insomma... keep simple.

Go Up