Alternativa al PCF8574

Sto realizzando una serie di piccoli moduli con il PCF8574 da connettere su un bus I2C per espandere gli I/O di Arduino.

Fino a che sono usati per leggere ingressi non ho alcun problema.

Al contrario quando gli uso come uscite mi sono posto un problema di affidabilità. Volevo dotare il PCF di una sorta di WatchDog, per cui al momento che fosse interrotta l'attività sulla linea SCL per un certo periodo, fossero resettate le uscite.

Realizzazione più semplice a dirsi che a farsi, visto che il PCF non ha un pin reset. D'accordo tutto si può fare, ma volendo limitare dimensioni e complessità circuitale, speravo di trovare qualcosa che mi potesse facilitare le cose.

Navigando in rete ho potuto capire che i vari I/O expander I2C sono sprovvisti di tale terminale. Solo il MCP23S17 prevede tale pin, ma di contro complica non di poco la programmazione.

Qualcuno ha conosce un I/O expander dotato di pin di reset?

Non capisco cosa tu intenda per " problemi di affidabilità " con dei PCF8574 Non e' che hai caricato male il Bus I2C con le resistenze di PullUp ?

lelebum: Al contrario quando gli uso come uscite mi sono posto un problema di affidabilità. Volevo dotare il PCF di una sorta di WatchDog, per cui al momento che fosse interrotta l'attività sulla linea SCL per un certo periodo, fossero resettate le uscite.

Spiegati meglio, chi è che dovrebbe resettare gli expander e chi si deve accorgere che non c'è attività sulla I2C ?

Fin tanto che si usa il PCF per leggere lo stato di ingressi, piuttosto che pilotare display LCD o tastiere keypad non c'è alcun problema.

Se invece lo utilizziamo per pilotare uscite, per comandare relè o altre attuazioni, la cosa cambia.

Come noto il PCF mantiene stabile sulle uscite l'ultimo stato ricevuto e solo la mancanza di tensione può resettarlo. Esiste sempre la possibilità che un guasto al bus o allo stesso Arduino interrompa il flusso di dati sul I2C e pertanto il PCF manterebbe attive le uscite in modo indefinito.

Avevo già tentato di inserire un banale NE555 come monostabile, nel quale il gruppo RC viene scaricaricato ad ogni impulso di SCL. Se per qualsiasi motivo veniva a mancare tale sequenza di impulsi l'NE555, trascorso il tempo presatabilito toglie l'alimentazione al PCF resettando pertanto le uscite.

Purtroppo come immaginavo, togliendo alimentazione al PCF sorgevano tutta una serie di altri problemi.

Sarà che mi complico la vita, e pur consapevole che questa sorta di WatchDog non mi mette al riparo da altri problemi, mi sarebbe piaciuto dare un minimo di affidabilità al sistema.

Il PCF8574 non ha inteligenza che potrebbe riconoscere che il BUS I2C non funziona. Ciao Uwe

Capisco bene che un PCF8574 non ha intelligenza e che aggiungere un banale timer sulla linea SCL non risolva in modo certo il problema. E'evidente che sostituendo il PCF con un arduino promini si può davvero fare le cose seriamente.

Ma come ripeto l'intento era quello di aggiungere un minimo di affidabilità al sistema.

Ma c'è una combinazione definita di uscite del PCF per la quale puoi stabilire che ci sia una anomalia? Mi spiego, se per te tutte le uscite a livello logico 1 rappresentano una combinazione impossibile da realizzarsi nella norma, allora ti basta usare una logica AND multipla e ti troverai un livello H sull'unica uscita solo se tutti gli ingressi sono a 1, a quel punto un pin di Arduino sarà allertato e poi fai ciò che vuoi.

No non c'è una combinazione da cui rilevare il guasto, sono tutte uscite generiche.

Però il tuo contributo mi ha dato un'idea davvero illuminante!

Visto che la mia applicazione rinfresca le uscite ad ogni ciclo di loop o comunque con una certa frequenza, sacrifico un'uscita del PCF e programmo Arduino a farla commutare di continuo.

Tale segnale lo invio al mio circuito di WatchDog che in mancanza di variazioni di livello mi disabilita le restanti 7 uscite, magari utilizando un 74HC244. Per contenere ingombri e vista la modestissima corrente di uscita dal PCF si potrebbe optare per mettere a massa le uscite anche tramite una serie di diodi.

In questo modo qualsiasi tipo di guasto (Arduino, il bus, lo stesso PCF,ecc.) verrà intercettato da tale logica offrendo una verifica completa. Se proprio vogliamo esagerare si può anche informare Arduino che qualcosa fa cilecca.

Magari appena metto a punto il circuito, se qualcuno è interessato lo posto

Grazie dell'aiuto.

Si postalo perché potrebbe anche essere interessante come idea, anche se sinceramente non ho mai sentito parlare di problemi sul bus I2C, a meno che non fosse gestito male (errore sui valori delle pull-up o conflitti di indirizzi)

Cosa pilotano i PCF ? … degli ULN o altri transistor ?

Puoi sacrificare due uscite ? … se si, potresti implementare una doppia funzione … le due uscite di controllo invertite ad ogni ciclo fra loro sarebbero il segnale che tutto va bene … quando il circuito si blocca, mandi le uscite in alta impedenza (magari attraverso i 244) in modo che i finali di potenza si spengano (se sono ULN hanno gia il pulldown interno) ed avvisi arduino del blocco di protezione, e quando arduino le deve ripristinare, per evitare di trovarsi gli ingressi con i vecchi valori, prima li azzera, poi mandando contempoaneamente ad 1 le due uscite di “controllo” resetta la protezione …

Ovviamente questo se non vuoi usare delle altre MCU per effettuare i controlli da remoto, tipo schede rele “intelligenti”, ma fare tutto in logiche standard …

Meglio riassumere quanto detto.

A mio vedere, quando si utilizza un expander di I/O come il PCF, in linea di principio è sempre un qualcosa che sfugge al controllo diretto di una CPU, si va ad aggiungere un qualcosa che diminuisce l’affidabilità del sistema.

Soprattutto nel mio caso, quando oltre a collocare la periferica ad un discreta distanza (compatibilmente al bus I2C), vado a controllare delle uscite ‘sensibili’. In tale circostanza mi preoccupavo di avere una sorta di salvagente, un WatchDog che resetti tutto in caso di malfunzionamento del sistema.

Dai vari spunti emersi dal post, ecco fatto una soluzione ragionevole.
Nello file standar.jpg rappresento il classico circuito per utilizzare il PCF per comandare varie uscite, tipo un relè.

Nel secondo file watchdog.jpg, partendo dallo schema precedente, inserisco un circuito di watchdog utilizzando un NE555.

L’ NE555 lo uso come banale inverter. Una volta avviato il software, il treno di impulsi che verrà generato all’uscita P7 del PCF andrà a caricare C1 mandado basso il pin 2 e di conseguenza andrà alta l’uscita al pin 3, abilitando pertanto tutti i pin di uscita del PCF.
Analogamente, nel caso avvenga un guasto che interrompe la comunicazione tra Arduino e il PCF, trascorsi 2" circa (con i valori attuali di C1-R1) scaricandosi C1 va alto il pin 6 e basso il pin 3 che trammite i diodi metterà a massa le uscite del PCF.
Il pin 7 del Ne555, come opencolletor potrebbe essere usato per informare Arduino dell’anomalia.

A completare il tutto aggiungo un breve software per far funzionare tutto.
Elemento fondamentale del programma commutare ad ogni ciclo di loop il bit 7 che una volta trasferito al PCF andrà a mantenere carico il temporizzatore (R1-C1).
A solo scopo dimostrativo ho aggiunto un passaggio per trasferire lo stato del pin A0 di Arduino al pin P0 del PCF.

#include <Wire.h>

#define pinIN A0

byte AdrsPCF = 0x20; // 010 0000;
byte DataOut =0;
 
void setup()
{
  Wire.begin();
  pinMode (pinIN,INPUT_PULLUP);
}
 

void loop()
{
  DataOut ^= 0x80;                            // ad ogni ciclo di loop inverto di segno del bit 7
                                              // per mantenere attivo il wachdog
                                            
  bitClear(DataOut,0);                        // allineo il livello logico tra il bit di ingresso pinIn  
  if (digitalRead(pinIN)) bitSet(DataOut,0);  // e il bit 0 di uscita del PCF
  
  Wire.beginTransmission(AdrsPCF);
  Wire.write(DataOut);
  Wire.endTransmission();
}

Il tutto ha funzionato al primo colpo senza incertezze.
Una dovuta precisazione. All’atto dell’avvio del software, ci sarà un attimo di ritardo nell’abilitazione delle porte provocato dal tempo di prima carica di C1, stimabile in 3-4 cicli di scrittura sul bus I2C.

In merito all’idea di Etemenanki, di perdere 2 pin, ci avevo già pensato, ma non risulta percorribile.
Una volta che Arduino si accorga dell’anomalia, esiste la buona probabilità che la stessa non permetta all’eventuale comando di inibizione di arrivare a destino.

Ringraziando del contributo, resto a disposizione per dare info.

1standar.jpg

Scusate errata corrige!

Il pin "OUT" del NE555 non il n. 5 ma bensi il n. 3

In quel caso pero' il tuo circuito si "limita" (diciamo cosi) ad avvisare Arduino, ma senza intervenire in alcun modo sulle uscite, che se sono attive, rimangono attive, giusto ? ... questo non ti comporta dei problemi, se tali uscite, restando attive, creano rischi per la tua applicazione ?

In quel caso sarebbe meglio che tu usassi un driver non invertente tristate, come ad esempio un'HC244 fra il PCF e l'ULN (forzare delle uscite a massa con dei diodi non e' mai un buon sistema, rischi di strinarle), in modo che quando va in errore, le uscite vengano spente tutte quante mandando il segnale anche agli enable, o comunque portate tutte in una condizione che non causa rischi (sia aperte che chiuse, a piacere) ... questo ovviamente se, come mi pare di aver capito, il fatto che il PCF mantenga le uscite all'ultimo stato in assenza di pilotaggio ti causa problemi ...

Riguardo al secondo schema, solo un'appunto, siccome piloti la base del transistor accoppiata in AC, metti un diodo tipo 1N4148 fra base e massa (catodo sulla base), per evitare possibili picchi negativi in base (non indispensabile, ma sempre meglio prevenire ;))

EDIT: riguardo al forzare le uscite con i diodi, se proprio vuoi usare quel sistema (che mi ricorda un po i sistemi DTL :P :D), almeno metti delle resistenze sulle uscite, prima dei diodi (tipo ad esempio 680 ohm o simili), in modo da limitare la corrente in caso di forzatura ed evitare la bruciatura dei PCF ;)

In quel caso pero' il tuo circuito si "limita" (diciamo cosi) ad avvisare Arduino, ma senza intervenire in alcun modo sulle uscite, che se sono attive, rimangono attive, giusto ?

Visto che restava a disposizione una uscita open colletor al pin 7, poteva tornare utile e non indispensabile avvisare Arduino. Il circuito comunque avrebbe inibito le uscite.

questo non ti comporta dei problemi, se tali uscite, restando attive, creano rischi per la tua applicazione ?

Se escludi le classiche uscite dedicate ad un LCD piuttosto che a una keypad, tutto potrebbe essere motivo di rischio. Un esempio tipico è la domotica. A tutti piace accendere e spegnere qualsivoglia utenza, ma nessuno si preoccupa di garantire al sistema un minimo di affidabilità, non solo sotto un profilo di sicurezza, ma anche energetico. Prova immaginare gli effetti dell'accensione 24/24 di una lampadina alogena del salotto piuttosto che la pompa dell'impianto di irrigazione.

In quel caso sarebbe meglio che tu usassi un driver non invertente tristate, come ad esempio un'HC244 fra il PCF e l'ULN (forzare delle uscite a massa con dei diodi non e' mai un buon sistema, rischi di strinarle), in modo che quando va in errore, le uscite

Sono d'accordo con te che la soluzione con il HC244 sarebbe più corretta, ma nella necessità di contenere gli spazi ho preferito i diodi. Al riguardo, se qualcuno volesse optare per l'uso del HC244 c'è la necessità di apportare una banale modifica allo schema.

Riguardo al secondo schema, solo un'appunto, siccome piloti la base del transistor accoppiata in AC, metti un diodo tipo 1N4148 fra base e massa (catodo sulla base), per evitare possibili picchi negativi in base (non indispensabile, ma sempre meglio prevenire );

Il diodo collegato tra la massa e il collettore (non la base) del transistor, è lo schema tipo dei temporizzatori, garantisce che in un possibile riavvio della periferica il condensatore sia scarico, nel nostro caso C1 (forse potevo anche risparmiarmi il diodo).

EDIT: riguardo al forzare le uscite con i diodi, se proprio vuoi usare quel sistema (che mi ricorda un po i sistemi DTL :P :D), almeno metti delle resistenze sulle uscite, prima dei diodi (tipo ad esempio 680 ohm o simili), in modo da limitare la corrente in caso di forzatura ed evitare la bruciatura dei PCF ;)

La tua osservazione sarebbe corretta se riferita alle classiche uscite (Arduino, CMOS,TTL, ecc.). Nel caso del ns PCF il costruttore le dichiara 'quasi-bidirectional I/O'. A spiegarla in modo semplice, mentre allo stato LOW i pin possono assorbire sino a 20mA (si può accendere un LED) allo stato HIGH i pin sono limitati a fornire al massimo 100uA (0.1mA), utile quando si usano i pin come ingressi. Quindi i pin acettano senza alcun problema di essere messi a massa.

Magari il problema è opposto, nell'uso come uscita con soli 0,1mA si alimenta a mala pena la base di un transistor o poco più.

lelebum: ... Il diodo collegato tra la massa e il collettore ...

No, intendevo proprio di aggiungere un'altro diodo fra base e massa ... l'accoppiamento in AC potrebbe causare della tensione sulla base negativa rispetto a massa, quindi il diodo che suggerivo era per proteggere la base del transistor, non per la temporizzazione ... il rischio e' comunque minimo, ma abbondare con la sicurezza non fa mai male ;)

mentre allo stato LOW i pin possono assorbire sino a 20mA (si può accendere un LED) allo stato HIGH i pin sono limitati a fornire al massimo 100uA (0.1mA), utile quando si usano i pin come ingressi

... mi ero dimenticato il fatto del "bidirezionale" ... :roll_eyes:

Diciamo che il diodo è meglio metterlo sulla base che sul collettore.

Ma invece di usare un PCF8574 + NE555 + 74HC244 + diodi + resistenza + condensatori + transistor...

Perche' non programmi un ATMEGA8 (magari con oscillatore interno a pochi MHz) e gli fai fare il lavoro del PCF ??

Puoi farti una comunicazione bidirezionale (con feedback) !

Tu dici all' ATMEGA8 di commutare una uscota e lui ti risponde di aver comutato quella uscita. Volendo tramite un terzo PIN puoi resettare l' ATMEGA8 nel caso si bloccasse !

Inizialmente la mia scelta era caduta sul PCF per il suo consumo davvero irrisorio, poi strada facendo mi sono un po complicato la vita, anche se aggiungere un NE555 e qualche diodo ci può ancora stare.

Con ATMEGA8 intendi la serie Attiny?

In passato ho già fatto qualcosa con l'85, ma tra modifiche all'IDE, a realizzare il programmatore e con la storia dei fuse e ho sudato sette camice per farlo funzionare a dovere. Davvero comica, avevo appena terminato il lavoro quando è uscita la nuova guida di Miliani e aggiornata versione dell'IDE ....

L'idea di utizzare la serie 84 l'avevo già considerata, ma sapendo che I2C non era nativo del micro temevo di trovarmi a risolvere nuovi problemi ed allungare i tempi.

Pertanto ho preferito affrontare un percorso più rapido rimandando ad altri tempi la cosa..

Grazie comunque!

Con Atmega8 intendo Atmega8. Atmega8 e' il primo micro che si usava sui primi Arduino. Poi hanno iniziato ad usare gli Atmega168 che ha il doppio di memoria. Adesso sull' Arduino Uno si una l' Atmega328 che ha il quadruplo di memoria dell' Atmega8.

Facendola breve: per 95cent (il prezzo che io pago per un Atmega8) hai un secondo Arduino con cui dialogare. Raddoppiando i PIN a disposizione (ne perdi due per la comunicazione tra i due ... ed eventualmente un terzo, se vuoi inplementare il reset)

Programmarlo e' semplicissimo: nella IDE c'e' uno sketch di esempio (programmatore SPI) che ti permette di far funzionare il tuo attuale Arduino come programatore per programmare un Atmega8 liscio (il solo chippozzo senza scheda)

Ti ricordo che l' Atmeha8 ha un'oscillatore interno attivabile (invece del quarzo a 16MHz esterno) cosi' i consumi cadono giu' drasticamente e non hai bisogno di nessun componente esterno, nemmeno una resistenza intorno all' Atmega.

una resistenza sì, quella da 10k tra il pin 1 e 5V, per evitare falsi RESET :)