Arduo Memory Reminder Medicine

In questo modo allarmi è una singola struct, non un array.

=(
Mi sono perso. Aiutoooooooo! tuxduino!!!

Non è molto semplice lavorare con le struct, quando praticamente non esistono esempi da dove prendere spunto. Io ricordo molto poco...

Qualcuno ha dei consigli ? :*

Ti faccio un esempio (spero) semplice per chiarire a livello base come si usano le struct.

struct Punto {
    int x;
    int y;
};

// inizializzazione all'atto della dichiarazione
struct Punto p = { 1, 2 };

// array di struct
const byte NUM_PUNTI = 10;
struct Punto elencoPunti[NUM_PUNTI];

// accesso ai singoli campi di una struct
// passaggio di una struct come argomento di una funzione
void stampaPunto(struct Punto p) {
    Serial.print('(');
    Serial.print(p.x, DEC);
    Serial.print(',');
    Serial.print(p.y, DEC);
    Serial.print(')');
}

// scansione di un array di struct
// passare un array di struct come argomento di una funzione
void stampaPunti(struct Punto punti[]) {
    for (byte i = 0; i < NUM_PUNTI; i++) {
        stampaPunto(punti[i]);
        Serial.println();
    }
}

void traslaPunti(struct Punto punti[], struct Punto p) {
    for (byte i = 0; i < NUM_PUNTI; i++) {
        punti[i] = sommaPunti(punti[i], p);
    }
}

// struct come valore di ritorno di una funzione
struct Punto sommaPunti(struct Punto a, struct Punto b) {
    struct Punto c;
    
    c.x = a.x + b.x;
    c.y = a.y + b.y;
    
    return c;
}

void setup() {
    Serial.begin(9600);
    
    for (byte i = 0; i < NUM_PUNTI; i++) {
        elencoPunti[i].x = 0;
        elencoPunti[i].y = 0;
    }
    
    stampaPunti(elencoPunti);
}


void loop() {
    traslaPunti(elencoPunti, p);
    stampaPunti(elencoPunti);
    delay(2000);
}

Per la cronaca, ho ricominciato a smanettare con Time.h e TimeAlarm.h (11k di codice per un semplice orologio su lcd... :fearful: ). Debbo capire come manipolare l'elenco degli allarmi e salvarlo su eeprom.

Ho messo insieme un orologio con lo shield lcd+keypad di Nuelectronics e il modulo RTC con batteria di sparkfun.
Per impostare data e ora, basta inviare tramite il serial monitor una stringa formattata così:

AAAA-MM-DD hh:mm:ss

seguita da CR e/o LF

Una volta impostate data e ora, l'orologio va avanti anche ad arduino spento, grazie alla pila al litio.
Alla successiva accensione (o reset) l'aggeggio mostra ancora l'ora esatta!

// Orologio con DS1307 su modulo RTC di Sparkfun e Nuelectronics lcd+analog keypad shield.
//
// Per impostare l'ora, inviare tramite seriale una stringa con il seguente formato:
// AAAA-MM-GG hh:mm:ss
// seguita da cr e/o lf
//

#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <LiquidCrystal.h>


LiquidCrystal lcd(8, 9, 4, 5, 6, 7);    // lcd pins for nuelectronics lcd+keypad shield
const short LCD_ROWS = 2;
const short LCD_COLS = 16;


void displayDateTime(int weekday, int d, int  m, int y, int h, int mn, int s) {
    char buf[20];
    
    lcd.clear();
    
    lcd.setCursor(0, 0);
    lcd.print(dayShortStr(weekday));
    
    sprintf(buf, "%02d-%02d-%04d", d, m, y);
    lcd.setCursor(6, 0);
    lcd.print(buf);
    
    sprintf(buf, "%02d:%02d:%02d", h, mn, s);
    lcd.setCursor(4, 1);
    lcd.print(buf);
}


void setDateTime(const char* buf) {
    int t_hr;
    int t_min;
    int t_sec;
    int t_day;
    int t_mon;
    int t_year;
    
    sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &t_year, &t_mon, &t_day, &t_hr, &t_min, &t_sec);
    setTime(t_hr, t_min, t_sec, t_day, t_mon, t_year);
    RTC.set(now());
}


const byte SERIAL_BUFLEN = 20;
char serialBuffer[SERIAL_BUFLEN] = { 0 };
byte serialCnt = 0;

void processChar(char ch) {
    if (ch == '\r' || ch == '\n') {
        serialBuffer[serialCnt] = 0;
        if (serialCnt == 19) {
            setDateTime(serialBuffer);
        }
        serialCnt = 0; 
    }
    else if (serialCnt < SERIAL_BUFLEN - 1) {
        serialBuffer[serialCnt] = ch;
        serialCnt++;
    }
}


void splashScreen() {
    lcd.clear();
    lcd.print("   LCD CLOCK");
    delay(1000);
}


void setup() {
    lcd.begin(LCD_COLS, LCD_ROWS);
    Serial.begin(9600);
    setSyncProvider(RTC.get);   // the function to get the time from the RTC
    splashScreen();
}


void loop() {
    static unsigned long prevMillis;

    // ogni secondo visualizziamo data e ora    
    if (millis() - prevMillis >= 1000) {
        prevMillis = millis();

        time_t t = now();
        displayDateTime(weekday(t), day(t), month(t), year(t), hour(t), minute(t), second(t));
    }
    
    if (Serial.available() > 0) {
        char ch = Serial.read();
        processChar(ch);
    }
}

:slight_smile: Bene, questo risolverebbe anche il problema del reset alla connessione con il PC una volta caricato in eprom i parametri.

Anche se la shield costa più di arduino!!

Dove posso trovare la shield ?

Però in questo modo si liberebbero almeno (6pinxLCD, 3pinxkey, 1xBuzzer).

Opzione per l'upgrade interessante.

Ciao.

Scusa, quale shield ?

La eeprom è dentro l'atmega328. L'interfaccia i2c è integrata (pin A4 e A5), e per l'RTC è sufficiente un oggettino tipo questo SparkFun Real Time Clock Module - BOB-12708 - SparkFun Electronics (che è quello che ho io attualmente).
I display LCD seriali si pilotano con 1 pin e la libreria NewSoftSerial (o come si chiama adesso...).

:roll_eyes:
Che tu sappia esistono shield con LCD, Keypad, Buzzer ed RTC ?

Lo shield che hai usato tu ha solo LCD+Keypad giusto? Che se non sbaglio costa circa 30$.

Più RTC con costo di circa 15$.

Calcolando il totale siamo a 25$ Arduino + 30 +15 = 70$ + iva, + 32Led + materiale per la bacheca + alimentatore

Il costo del progetto comincia a lievitare !!!

Però analizziamo i costi per un confronto:
Al momento io ho speso
25E per arduino uno
10E per la bacheca
10E per i led ad alta efficenza
2E per i pulsantini
1E per il pulsante di ACK
2E per l'altoparlante
7E per il display
5E per l'alimentatore
4E per la batteria
3E per le resistenze, diodi, transistor e condensatori
5E per connetori e cavi per i collegamenti


74E totali contro circa 110E per l'upgrade. (50% in più del prezzo base)

Solo come discussione:
"Occorre ragionarci su, se si vuole poi integrare la comunicazione ETH ed un arduino più potente il dispositivo diventa costoso".

Ciao.

Che tu sappia esistono shield con LCD, Keypad, Buzzer ed RTC ?

No. Ho anche fatto qualche ricerca, ma nada.

Per quanto riguarda l'adozione di un micro + potente, direi che mantenendo i piedi per terra si fa tutto con l'UNO. Ovvio che se uno vuole controllare la programamzione via web, con sms, avvisi sonori (tipo vocina che ti dice il nome della medicina da prendere e la quantità), ecc., allora si passa facilmente al raspberry :wink:

Cosi' recuperi anche i pin necessari alla scheda Ethernet

:roll_eyes:
Certo brunello, bisognerebbe verificare però, anche se la DUE, che lavora a 84Mhz sia più precisa nel conteggio del secondo per la libreria time, che ad occhio dovrebbe avere una precisione 5 volte maggiore e che costa circa 48E (quasi come Arduino Uno+RTC) ma con molti più pin disponibili.

Tornando a noi tuxduino, hai novità sull'utilizzo delle struct array?

La precisione nel conteggio del tempo la fornisce l'RTC. UNO o DUE non fa differenza.

Per quanto riguarda l'implementazione dell'elenco di allarmi come array di struct, ho scritto la addAlarm(), a breve ti posto qualcosa.

:wink: Ok.

Aspetto un tuo feedback. Grazie.

La cosa mi ha preso un po' la mano... :wink:

Il programma è ancora poco "pulito" e incompleto per mancanza di tempo. Descrivo brevemente le features attuali.

Impostazione dell'ora tramite seriale con comando "T". Esempio:

T2012-11-13 18:16:00

Imposta data e ora al 13 novembre 2012, ore 18 e 16 e 0 secondi.
Se si collega l'RTC ai pin opportuni e si de-commenta il #define HAS_RTC nella parte iniziale dello sketch, mantiene data e ora indefinitamente.

Inserimento degli allarmi tramite seriale con comando "A". Esempio:

A18:15P01M02

Imposta un allarme giornaliero alle 18:15, per il paziente 01 e la medicina 02.
Sul display vengono mostrati il nome del paziente e il nome della medicina.
Questi nomi attualmente sono fissati nel codice. In futuro dovranno essere gestibili in modo dinamico come gli allarmi (impostabili da seriale) e memorizzabili su eeprom.
Premendo il puslante di ack l'allarme sparisce dal display.

Elenco degli allarmi: L
Cancellazione degli allarmi: C
Caricamento degli allarmi da eeprom: R (non necessario comunque perché li ricarica ad ogni avvio o reset)
Salvataggio degli allarmi su eeprom: S
Elenco degli allarmi in formato "macchina", per una futura lettura su PC: D

Quindi ricapitolando per memorizzare una serie di allarmi su eeprom si fa così:

  1. inserire uno ad uno gli allarmi desiderati con il comando A descritto prima
  2. una volta terminato, mandare il comando S per salvarli in eeprom.
  3. Fatto: d'ora in poi gli allarmi verranno letti da eeprom.

Si possono memorizzare più allarmi con gli stessi valori ora:minuto.

Note hardware:
il mio "pulsante" è un tastierino analogico, quindi per me la condizione di "premuto" significa che leggendo il canale A0 leggo un valore al di sotto di una certa soglia. Nel caso di un pulsante digitale bisogna modificare la funzione ackButtonPressed() in modo che legga lo stato alto o basso di un pin digitale (se si usa una resistenza di pullup lo stato premuto è LOW).

La segnalazione di un allarme avviene per ora soltanto tramite una scritta sul display. Ovviamente in futuro bisognerà copiare il codice del programma originale che interagisce con i led e i buzzer...

Note software:
l'allarme è una struct, l'elenco degli allarmi è un array di struct, intorno al quale però ho costruito una classe per rendere il codice più maneggevole. L'ho scritto un po' di fretta, quindi se avrò più tempo nei prossimi giorni cercherò di migliorarlo.
Ho cercato di abbondare con i commenti per rendere il tutto più comprensibile.

LCDDailyAlarmClock.ino (14.3 KB)

Alarm.h (548 Bytes)

Alarms.h (2.51 KB)

Alarms.cpp (4.99 KB)

:astonished: wow! da paura!

Dalle descrizioni che dai, hai dedicato un bel pò di tempo al progetto! Bravo!
Darò un'occhiata e se riesco provvedo all'inserimento del codice su A.M.R. R05d con l'implementazione del comando dei led.

Ciao.

Preso dall'entusiasmo, temo di essere entrato un po' troppo "a gamba tesa" :stuck_out_tongue:
Il fatto è che avevo scritto qualcosa di simile l'anno scorso, per cui oltre a qualche idea nuova ho riciclato anche qualche "pensata" vecchia ma implementata in modo nuovo...

Credo che potrei essere maggiormente d'aiuto, almeno ora, con piccole migliorie mirate al tuo codice, e/o rispondendo a tue domande specifiche...

(ho comunque intenzione di portare avanti il codice che ho appena postato :slight_smile: )

(ho comunque intenzione di portare avanti il codice che ho appena postato smiley )

Ciao tuxduino. :grin:

Intanto ottimo lavoro scrupoloso che determina interesse al progetto ArduoMemoryReminder. Grazie!

La "gamba tesa" spesso è fonte di miglioramento, come credo in questo caso.

Osservando il tuo post, ed in particolare il codice fornito, occorre chiarire e determinare lacuni aspetti del progetto.

  1. La programmabilità del device, che dovrà essere di semplice intuizione, possibilmente senza PC (il PC si userà solo per verifiche e/o programmazione)
  2. La funzionalita e la comprensione del device che verrà utilizzato da persone con problemi di varia natura
  3. Lo spazio disponibile per il codice hex da caricare su arduino Uno.

Premessa:
Comincio con il chiederti se hai postato tutto correttamente o se manca qualcosa, perchè caricandolo sull'IDE 1.0.1, compreso le librerie "Alarms" e "Alarm" mi dà errore su:

// Oggetto che gesetisce l'elenco degli allarmi.
Alarms alarms;

Segnalando:
LCDDailyAlarmClock:446: error: 'alarms' was not declared in this scope

"Ricorda che non sono esperto nell'utilizzo di librerie ed IDE"

In riferimento al Punto 1:
"Poco rilevante al momento, il codice non prevede ancora una cfg dei parametri"

In riferimento al Punto 2:
"Tenere presente che una volta funzionante, il dispositivo sarà utilizzato da persone diversamente abili o con problemi di memoria, quindi il paziente non dovrà preoccuparsi di fare nulla al di fuori della pressione del pulsante ACK per consentire al device di memorizzare l'assunzione del medicinale."

In riferimento al Punto 3:
"Con la gestione delle variabili char, sei sicuro che la UNO supporti almeno 64 di queste da 10-15 caratteri ciascuna + codice + eventuali implementazioni?"

Una volta definita la modalità di gestione di questi tre punti, si può procedere con l'upgrade al codice.

Sono sicuro che saprai già come gestire eventualmente il tutto.

Intanto ancora grazie per il lavoro svolto. E' bello vedere che esiste ancora qualcuno disponibile a partecipare a qualcosa di creativo ed utilie a tutti, specialmente a chi ne ha veramente bisogno.

PS.: Sei d'accordo se inserisco il tuo nickname nel progetto postato al FABLAB come (main software developer), questo invoglierebbe altri a partecipare al progetto ed a uno scambio di opinioni credo interessanti anche di un certo livello?

Giuseppe G.

Ho dato una scorsa al progetto.
Bravi ad entrambi :stuck_out_tongue:

Volevo suggerire solo una risposta al problema del reset dell'Arduino.
Esso avviene sempre, a meno che:

  1. non interrompi la pista RES-EN, però poi devi resettare la scheda a mano ogni qual volta la devi riprogrammare
  2. non riflashi l'Atmega8U2: http://arduino.cc/forum/index.php/topic,130621.0.html

Intanto ottimo lavoro scrupoloso che determina interesse al progetto ArduoMemoryReminder. Grazie!

Grazie a te per l'apprezzamento :slight_smile:

Intanto ancora grazie per il lavoro svolto. E' bello vedere che esiste ancora qualcuno disponibile a partecipare a qualcosa di creativo ed utilie a tutti, specialmente a chi ne ha veramente bisogno.

Non vorrei sembrarti cinico ma confesso -per onestà- che programmare mi diverte un sacco :stuck_out_tongue:

Veniamo ora ai contenuti...

Comincio con il chiederti se hai postato tutto correttamente o se manca qualcosa.

A casa l'ho pure caricato sulla scheda per provarlo... probabilmente ho fatto qualche errore nel caricamento dell'allegato... Controllerò meglio.

"Ricorda che non sono esperto nell'utilizzo di librerie ed IDE"

Lo diventerai 8)

  1. La programmabilità del device, che dovrà essere di semplice intuizione, possibilmente senza PC (il PC si userà solo per verifiche e/o programmazione)

Poco rilevante al momento, il codice non prevede ancora una cfg dei parametri.

Come ti dicevo ho buttato giù lo sketch in fretta, per cui risultava più semplice implementare la programmazione via seriale che gestire tasti e display.
Ho comunque già qualche idea in merito...

Il mio keypad è analogico (5 tasti che provocano letture diverse su A0 quando premuti), non so che tastiera usi tu (appena ho tempo lo guardo sul sito). Considero questa differenza di hw un incentivo a mantenere il codice "bello pulito" e modulare in modo che cambiando una semplice #define sia possibile utilizzare diverse "tastiere" (o per meglio dire "pulsantiere").

Comunque la programmazione senza PC mi pare di capire che al momento è poco prioritaria. Anche perché non è affatto banale da implementare...

  1. La funzionalità e la comprensione del device che verrà utilizzato da persone con problemi di varia natura

Tenere presente che una volta funzionante, il dispositivo sarà utilizzato da persone diversamente abili o con problemi di memoria, quindi il paziente non dovrà preoccuparsi di fare nulla al di fuori della pressione del pulsante ACK per consentire al device di memorizzare l'assunzione del medicinale.

L'ultima parola ovviamente spetta a te, in particolare su questo punto, per valutare se un certo modo di operare del device sia idoneo o meno a quello che tu immagini essere l'utente finale tipico.

Il fatto che ci sia solo un grosso pulsante di conferma comunque semplifica non poco la situazione.

  1. Lo spazio disponibile per il codice hex da caricare su arduino Uno.

Con la gestione delle variabili char, sei sicuro che la UNO supporti almeno 64 di queste da 10-15 caratteri ciascuna + codice + eventuali implementazioni?

Per il mio sketch occupa metà flash rom. Confido si possa ottimizzare, soprattutto perché nella Time.h ci sono molte stringhe...
Comunque no, non sono sicuro ci stia tutto. Ma la "premature optimization" è Male(TM), quindi chi vivrà vedrà... :slight_smile:

PS.: Sei d'accordo se inserisco il tuo nickname nel progetto postato al FABLAB come (main software developer)

Ne sarei onorato... Ma così mi tocca poi finire il lavoro! :smiley:

LCDDailyAlarmClock:446: error: 'alarms' was not declared in this scope

Posta l'errore completo.

Sospetto che ci sia un baco in Time.cpp: prova ad inserire queste righe prima di #include "Time.h":

#if ARDUINO >= 100
#include <Arduino.h> 
#else
#include <WProgram.h> 
#endif

:wink: Ok!

Sospetto che ci sia un baco in Time.cpp: prova ad inserire queste righe prima di #include "Time.h":

Code:

#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

Ma perchè accade questo ?
PS: Mi piacerebbe capire perchè. C' e un link dove viene spiegato ? O è un problema della libreria non aggiornata?

:slight_smile: Ciao Leo72,

Ho dato una scorsa al progetto.
Bravi ad entrambi smiley-razz

Volevo suggerire solo una risposta al problema del reset dell'Arduino.
Esso avviene sempre, a meno che:

  1. non interrompi la pista RES-EN, però poi devi resettare la scheda a mano ogni qual volta la devi riprogrammare
  2. non riflashi l'Atmega8U2: http://arduino.cc/forum/index.php/topic,130621.0.html

Grazie per l'info utile per poter implementare l'eventuale SW per gestire la visone/programmazione dei parametri.

Scusa per la domanda banale, ma basta il ponticello HD o bisogna inserire anche le parti del SW ?