|
4 | 4 |
|
5 | 5 | 
|
6 | 6 |
|
7 |
| -All'avvio vengono inizializzati i registri per la comunicazione seriale (UART), l'uso dei timer (TIMER1), i pin digitali, l'LCD (usata [libreria esterna](http://winavr.scienceprog.com/example-avr-projects/avr-gcc-4-bit-and-8-bit-lcd-library.html)), l'interfaccia ADC (definita appositamente in [adc.c](src/adc.c)) e gli external interrupt (INT0, INT1). |
| 7 | +All'avvio vengono inizializzati i registri per la comunicazione seriale (UART), i pin digitali, l'LCD (usata [libreria esterna](http://winavr.scienceprog.com/example-avr-projects/avr-gcc-4-bit-and-8-bit-lcd-library.html)), l'interfaccia ADC (definita appositamente in [adc.c](src/adc.c)) e gli external interrupt (INT0, INT1). |
8 | 8 |
|
9 | 9 | ```c
|
10 |
| -EIMSK = (1<<INT1)|(1<<INT0); //Turn ON INT0 and INT1 |
| 10 | +EIMSK = (1<<INT1)|(1<<INT0); //turn ON INT0 and INT1 |
11 | 11 | EICRA = (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);
|
12 | 12 | ```
|
13 | 13 |
|
@@ -43,50 +43,74 @@ ISR(INT0_vect){ //external interrupt service routine
|
43 | 43 | reset = 1;
|
44 | 44 | waitingForOutput = 0;
|
45 | 45 | }
|
| 46 | + else if(!waitingForOutput && !EEPROM_params_ready && DigIO_getValue(buttonLeft) == HIGH){ |
| 47 | + EEPROM_params_ready = 1; |
| 48 | + } |
46 | 49 | }
|
47 | 50 |
|
48 | 51 | ISR(INT1_vect){ //external interrupt service routine
|
49 | 52 | if(waitingForOutput && DigIO_getValue(buttonRight) == HIGH){
|
50 | 53 | reset = 0;
|
51 | 54 | waitingForOutput = 0;
|
52 | 55 | }
|
| 56 | + else if(!waitingForOutput && !EEPROM_params_ready && DigIO_getValue(buttonRight) == HIGH){ |
| 57 | + EEPROM_params_ready = 1; |
| 58 | + } |
53 | 59 | }
|
54 | 60 | ```
|
55 | 61 |
|
56 |
| -Nel primo caso (`reset = 1`) l'MCU interagisce con l'utente tramite seriale per ottenere i nuovi parametri di configurazione e salvarli in EEPROM, ognuno in blocchi da 16 byte come di seguito riportato. Sono state scritte funzioni apposite per lettura/scrittura da/su EEPROM definite in [eepromParams.c](src/eepromParams.c) |
| 62 | +Nel primo caso (`reset = 1`) l'MCU installa gli handler per i pacchetti binari e attende dall'utente l'arrivo dei ConfigPacket contenenti i nuovi parametri di configurazione (continua a flushare l'input buffer), salva i singoli valori in EEPROM, ognuno in blocchi da 16 byte come di seguito riportato. Sono state scritte funzioni apposite per lettura/scrittura da/su EEPROM definite in [eepromParams.c](src/eepromParams.c) |
| 63 | +
|
| 64 | +**N.B**: dopo aver premuto il pushbutton associato a INT0 [sendParams.c](host/sendParams.c) è il programma da eseguire su host per scegliere e inviare i nuovi settaggi. Si veda più avanti il paragrafo sulla comunicazione seriale. |
57 | 65 |
|
58 |
| - |
| 66 | + |
59 | 67 |
|
60 | 68 | * `uint16_t timer`: intervallo in ms tra due successivi controlli dei sensori
|
61 | 69 | * `uint16_t minLight`
|
62 | 70 | * `uint16_t maxLight`
|
63 | 71 | * `uint16_t minTemp`
|
64 | 72 | * `uint16_t maxTemp`
|
65 |
| -* `uint16_t maxPoll`: massimo valore della qualità dell'aria tollerato, consigliabile 150-170 |
66 |
| -* `float R1`: resistenza per il calcolo della temperatura, nel circuito 10000 |
| 73 | +* `float R1`: resistenza in Ω impiegata per il calcolo della temperatura, nel circuito 10000 |
67 | 74 | * `float C1, C2, C3`: costanti, vedere [Termistore](#Termistore)
|
| 75 | +* `uint16_t maxPoll`: massimo valore della qualità dell'aria tollerato, consigliabile 150-170 |
| 76 | +
|
| 77 | +**N.B**: [eeprom_test.c](eeprom_test.c) è un programma di debugging scritto per leggere i valori correnti in EEPROM. |
68 | 78 |
|
69 |
| -**N.B**: il programma [eeprom_test.c](eeprom_test.c) è stato scritto per leggere i valori correnti in EEPROM. |
| 79 | +Una volta che i parametri sono stati modificati, l'utente può premere un qualunque pushbutton per uscire dal loop (il flag `EEPROM_params_ready` è settato a 1) e disinstallare gli handler dei pacchetti. |
70 | 80 |
|
71 |
| -Nel secondo caso (`reset = 0`) i valori già presenti in EEPROM - quelli dell'ultimo setup - sono salvati subito nelle variabili globali. |
| 81 | +Nel secondo caso (`reset = 0`) l'MCU va subito a salvare i valori già presenti in EEPROM nelle variabili globali, cioé quelli dell'ultimo setup. |
72 | 82 |
|
73 | 83 | ```c
|
74 | 84 | timer = get_EEPROM_timer();
|
75 | 85 | minLight = get_EEPROM_minLight();
|
76 | 86 | maxLight = get_EEPROM_maxLight();
|
77 | 87 | minTemp = get_EEPROM_minTemp();
|
78 | 88 | maxTemp = get_EEPROM_maxTemp();
|
79 |
| -maxPoll = get_EEPROM_maxPoll(); |
80 | 89 | R1 = get_EEPROM_r1();
|
81 | 90 | C1 = get_EEPROM_c1();
|
82 | 91 | C2 = get_EEPROM_c2();
|
83 | 92 | C3 = get_EEPROM_c3();
|
| 93 | +maxPoll = get_EEPROM_maxPoll(); |
| 94 | +``` |
| 95 | + |
| 96 | +A questo punto: |
| 97 | + |
| 98 | +* vengono disattivati i bit dei registri per gli external interrupt perché non saranno più utilizzati |
| 99 | +* viene inizializzato il timer basato sul TIMER1 |
| 100 | + |
| 101 | +```c |
| 102 | +//disable interrupts globally to turn OFF INT0 and INT1 |
| 103 | +cli(); |
| 104 | +EIMSK = 0x00; |
| 105 | +EICRA = 0x00; |
| 106 | +Timers_init(); //initialize timer |
| 107 | +sei(); //enable interrupts globally |
84 | 108 |
|
85 | 109 | struct Timer* timerSensors = Timer_create("timer_0", timer, timerFn, NULL);
|
86 | 110 | Timer_start(timerSensors);
|
87 | 111 | ```
|
88 | 112 |
|
89 |
| -Il valore in `timer` è usato per richiamare ogni "timer" ms la funzione `timerFn()` che si occupa di effettuare il sensing dell'ambiente. |
| 113 | +Il valore memorizzato in `timer` è usato per richiamare ogni "timer" ms la funzione `timerFn()` che si occupa di effettuare il sensing dell'ambiente. |
90 | 114 |
|
91 | 115 | ```c
|
92 | 116 | void timerFn(void* args){
|
@@ -115,36 +139,72 @@ Il microcontrollore entra infine in un loop vuoto ed eseguirà la funzione `time
|
115 | 139 |
|
116 | 140 | ## Comunicazione seriale
|
117 | 141 |
|
118 |
| -Il baudrate selezionato è 115200. Il formato dei frame adottato in [uart.c](src/uart.c) prevede 1 start bit, 8 bits data (`UCSR0C = _BV(UCSZ01) | _BV(UCSZ00)`), nessun bit di parità (nel registro UCSR0C i bit UPM01=0 e UPM00=0), 1 stop bit (nel registro UCSR0C il bit USBS0=0). Il programma [sendParams.c](sendParams.c) scritto per comunicare via terminale e configurare così i parametri in EEPROM utilizza la stessa configurazione per i pacchetti. |
| 142 | +### Lato Microcontrollore |
119 | 143 |
|
120 |
| -```c |
121 |
| -speed_t baud = B115200; /* baud rate */ |
| 144 | +Nei paragrafi precedenti si è visto che si instaura una comunicazione seriale binaria a pacchetti solo per trasmettere i parametri di misurazione. Esistono 4 tipi di ConfigPacket: |
122 | 145 |
|
123 |
| -struct termios settings; |
124 |
| -tcgetattr(fd, &settings); |
| 146 | +```c |
| 147 | +typedef struct TimerConfigPacket{ |
| 148 | + PacketHeader header; |
| 149 | + uint32_t duration; |
| 150 | +} TimerConfigPacket; |
| 151 | + |
| 152 | +typedef struct LightConfigPacket{ |
| 153 | + PacketHeader header; |
| 154 | + uint16_t minLight; |
| 155 | + uint16_t maxLight; |
| 156 | +} LightConfigPacket; |
| 157 | + |
| 158 | +typedef struct TemperatureConfigPacket{ |
| 159 | + PacketHeader header; |
| 160 | + uint16_t minTemp; |
| 161 | + uint16_t maxTemp; |
| 162 | + float r1; |
| 163 | + float c1; |
| 164 | + float c2; |
| 165 | + float c3; |
| 166 | +} TemperatureConfigPacket; |
| 167 | + |
| 168 | +typedef struct PollutionConfigPacket{ |
| 169 | + PacketHeader header; |
| 170 | + uint16_t maxPoll; |
| 171 | +} PollutionConfigPacket; |
| 172 | +``` |
125 | 173 |
|
126 |
| -cfsetospeed(&settings, baud); /* baud rate */ |
127 |
| -settings.c_cflag &= ~PARENB; /* no parity */ |
128 |
| -settings.c_cflag &= ~CSTOPB; /* 1 stop bit */ |
129 |
| -settings.c_cflag &= ~CSIZE; |
130 |
| -settings.c_cflag |= CS8 | CLOCAL; /* 8 bits */ |
131 |
| -settings.c_lflag = ICANON; /* canonical mode */ |
132 |
| -settings.c_oflag &= ~OPOST; /* raw output */ |
| 174 | +Ognuno dei precedenti è dotato di una funzione "onReceive" che estrae il payload, carica in EEPROM i nuovi parametri e li mostra sull'LCD come feedback per l'utente. A titolo di esempio ecco la funzione per il PollutionConfigPacket: |
133 | 175 |
|
134 |
| -tcsetattr(fd, TCSANOW, &settings); /* apply the settings */ |
135 |
| -tcflush(fd, TCOFLUSH); |
| 176 | +```c |
| 177 | +PacketStatus PollutionConfigPacket_onReceive(PacketHeader* header, void* args __attribute__((unused))){ |
| 178 | + PollutionConfigPacket* p = (PollutionConfigPacket*) header; |
| 179 | + int maxPoll = p->maxPoll; |
| 180 | + set_EEPROM_maxPoll(maxPoll); |
| 181 | + char buffer[8]; |
| 182 | + sprintf(buffer, "%d", maxPoll); |
| 183 | + LCDclr(); |
| 184 | + printOnLCD(buffer); |
| 185 | + return Success; |
| 186 | +} |
136 | 187 | ```
|
137 |
| -Il programma riconosce la fine di un messaggio grazie a un carattere speciale (`'\0' oppure '\n'`), legge da `stdin` la stringa digitata dall'utente e la invia al microcontrollore dopo aver aggiunto il terminatore `\0`. Il ciclo è ripetuto 7 volte, cioé per ogni parametro configurabile in EEPROM. |
138 | 188 |
|
139 |
| -Dall'altro lato l'MCU salva la stringa ricevuta nella EEPROM, e.g. la variabile timer: |
| 189 | +### Lato Host |
| 190 | +
|
| 191 | +Il programma [sendParams.c](host/sendParams.c) avvia di fatto una procedura guidata per l'inserimento dei parametri. Chiede un parametro alla volta, lo legge da stdin, lo converte da char* al tipo corretto, prepara il singolo pacchetto e lo invia. Di seguito un esempio con il LightConfigPacket. |
140 | 192 |
|
141 | 193 | ```c
|
142 |
| -printString("timer in ms?\n"); |
143 |
| -readString(rx_message, BUFFER_SIZE); |
144 |
| -set_EEPROM_timer(rx_message); |
| 194 | +printf("Insert min light: "); |
| 195 | +read_from_stdin(); |
| 196 | +uint16_t minLight = atoi(inputString); |
| 197 | +
|
| 198 | +printf("Insert max light: "); |
| 199 | +read_from_stdin(); |
| 200 | +uint16_t maxLight = atoi(inputString); |
| 201 | +
|
| 202 | +LightConfigPacket p1 = { {LIGHT_CONFIG_PACKET_TYPE, LIGHT_CONFIG_PACKET_SIZE, 0}, minLight, maxLight }; |
| 203 | +PacketHandler_sendPacket(&packet_handler, (PacketHeader*) &p1); |
| 204 | +flushOutputBuffer(fd); |
145 | 205 | ```
|
146 | 206 |
|
147 |
| -**N.B**: `void readString(char* dest, int size)` è una funzione definita in [main.c](main.c) per salvare in un buffer i caratteri ricevuti. |
| 207 | +L'host non ha funzioni di ricezione "onReceive" per i pacchetti perché si occupa solo di inviare valori. Naturalmente - per come è stato progettato il [main.c](main.c) - saranno ignorati i pacchetti inviati senza aver premuto il pushbutton associato a INT0 oppure dopo che gli external interrupt sono stati disabilitati. |
148 | 208 |
|
149 | 209 | ## Sensori
|
150 | 210 |
|
@@ -188,7 +248,7 @@ void controlPoll(void){
|
188 | 248 | char msg[BUFFER_SIZE];
|
189 | 249 |
|
190 | 250 | if(air_value>maxPoll){
|
191 |
| - sprintf(msg, "Polluted air %d", air_value); |
| 251 | + sprintf(msg, "Polluted air"); |
192 | 252 | printOnLCD(msg);
|
193 | 253 | sprintf(msg, "Air: %d", air_value);
|
194 | 254 | LCDGotoXY(0,1);
|
@@ -243,4 +303,3 @@ La variabile Tc indica la temperatura attuale.
|
243 | 303 | * `Tc = T - 273.15` lo converte in °C.
|
244 | 304 |
|
245 | 305 | Se la temperatura attuale non è nell'intervallo `[minTemp,maxTemp]` viene invocata la funzione `error_blink()` e viene stampato un messaggio di errore.
|
246 |
| - |
|
0 commit comments