C: buona prassi per lo scambio di dati tra i moduli

Ciao a tutti
Di C per microcontroller ne ho scritto parecchio, ma non sono un programmatore vero.
Una cosa è sapere l'italiano, un'altra è scrivere come il Manzoni.
Con l'esperienza si migliora (si spera), ma nascono anche piú dubbi, dovuti al fatto che si diventa piú esigenti verso sè stessi.
Uno di questi dubbi è come gestire lo scambio di informazioni all'interno di un programma per microcontroller scritto in C senza orientazione agli oggetti.
Ci sono diverse possibilità e mi piacerebbe sentire il vostro parere su quale sia quella da preferire. Magari ne scaturisce una discussione interessante
Faccio un esempio di programma per illustrare la situazione.
Questo diagramma non rappresenta necessariamente un'architettura, è solo per capire cosa abbiamo.
Immaginiamo di avere un modulino che misura la temperatura e la mette a disposizione su una linea seriale.
Lo scheduler (usando per esempio un timer) richiede una volta al secondo una conversione all'ADC.
Questo la esegue e genera un interrupt. In seguito all'interrupt i dati estratti dall'ADC e messi in memoria come rawData. A questo punto il modulo di calcolo li prende e li converte in una temperatura, usando dei dati di calibrazione del sensore che sono presenti in memoria. Chiamiamoli gain e offset. Questi dati vengono configurati via UART, così come via UART avviene la lettura della temperatura.
L'esempio si può espandere a piacere (scelta dell'unità tra °C e K, modifica dell'intervallo di misura, impostazione di un moving average,...)
La necessità è la stessa: ci sono delle variabili in memoria che devono essere accessibili a piú moduli, per esempio UART e modulo di calcolo.
Come risolvere il problema?
1) Variabili globali
Questa opzione la metto per completezza, ma è un approccio antiquato che non andrebbe usato in un moderno programma ben strutturato. Funzionerebbe, perché lo scheduler assicura che non possa esserci una comunicazione che modifica i dati di calibrazione mentre questi vengono usati dal modulo di calcolo. Ma come detto, vogliamo qualcosa di ben fatto
2) Modulo DATA
Questa possibilità rispecchia in un certo senso il diagramma qui sopra. In un file si definiscono delle variabili statiche, ma dallo scope limitato a quel file. Si lavora poi con dei "getter" e "setter". È la soluzione che uso di solito, ma sinceramente non ne sono pienamente soddisfatto. Per diversi motivi:
- è vero che posso mettere dei controlli nei setter e che le variabili sono incapsulate in un file, ma la differenza mi sembra piú filosofica che altro: tutti i cani e porci che includono data.h hanno accesso in qualsiasi momento alle variabili
- la leggibilità del codice ne risente
3) Variabili dove vengono usate
È una soluzione simile alla seconda, ma invece di mettere tutto in un file dedicato, metto rawData in driverADC.c, gain e offset li metto nel modulo di calcolo e così via.
In questo modo limito un po' l'accesso, ma anche no. Per esempio UART.c avrà inclusi tutti gli header files di tutti i moduli in cui c'è una variabile configurabile. E quindi ottengo un'architettura a spaghetti, dove tutti comunicano con tutti. Anche questa non è una bella soluzione.
Voi come fate?
Saluti Boiler
Di C per microcontroller ne ho scritto parecchio, ma non sono un programmatore vero.
Una cosa è sapere l'italiano, un'altra è scrivere come il Manzoni.
Con l'esperienza si migliora (si spera), ma nascono anche piú dubbi, dovuti al fatto che si diventa piú esigenti verso sè stessi.
Uno di questi dubbi è come gestire lo scambio di informazioni all'interno di un programma per microcontroller scritto in C senza orientazione agli oggetti.
Ci sono diverse possibilità e mi piacerebbe sentire il vostro parere su quale sia quella da preferire. Magari ne scaturisce una discussione interessante

Faccio un esempio di programma per illustrare la situazione.
Questo diagramma non rappresenta necessariamente un'architettura, è solo per capire cosa abbiamo.
Immaginiamo di avere un modulino che misura la temperatura e la mette a disposizione su una linea seriale.
Lo scheduler (usando per esempio un timer) richiede una volta al secondo una conversione all'ADC.
Questo la esegue e genera un interrupt. In seguito all'interrupt i dati estratti dall'ADC e messi in memoria come rawData. A questo punto il modulo di calcolo li prende e li converte in una temperatura, usando dei dati di calibrazione del sensore che sono presenti in memoria. Chiamiamoli gain e offset. Questi dati vengono configurati via UART, così come via UART avviene la lettura della temperatura.
L'esempio si può espandere a piacere (scelta dell'unità tra °C e K, modifica dell'intervallo di misura, impostazione di un moving average,...)
La necessità è la stessa: ci sono delle variabili in memoria che devono essere accessibili a piú moduli, per esempio UART e modulo di calcolo.
Come risolvere il problema?
1) Variabili globali
Questa opzione la metto per completezza, ma è un approccio antiquato che non andrebbe usato in un moderno programma ben strutturato. Funzionerebbe, perché lo scheduler assicura che non possa esserci una comunicazione che modifica i dati di calibrazione mentre questi vengono usati dal modulo di calcolo. Ma come detto, vogliamo qualcosa di ben fatto

2) Modulo DATA
Questa possibilità rispecchia in un certo senso il diagramma qui sopra. In un file si definiscono delle variabili statiche, ma dallo scope limitato a quel file. Si lavora poi con dei "getter" e "setter". È la soluzione che uso di solito, ma sinceramente non ne sono pienamente soddisfatto. Per diversi motivi:
- è vero che posso mettere dei controlli nei setter e che le variabili sono incapsulate in un file, ma la differenza mi sembra piú filosofica che altro: tutti i cani e porci che includono data.h hanno accesso in qualsiasi momento alle variabili
- la leggibilità del codice ne risente
3) Variabili dove vengono usate
È una soluzione simile alla seconda, ma invece di mettere tutto in un file dedicato, metto rawData in driverADC.c, gain e offset li metto nel modulo di calcolo e così via.
In questo modo limito un po' l'accesso, ma anche no. Per esempio UART.c avrà inclusi tutti gli header files di tutti i moduli in cui c'è una variabile configurabile. E quindi ottengo un'architettura a spaghetti, dove tutti comunicano con tutti. Anche questa non è una bella soluzione.
Voi come fate?
Saluti Boiler