In questa terza parte dedicata allo sketch della centralina humidity temperatura suolo analizerai le funzioni di raccolta dati, visualizzazione e salvatagglio dei log.
Dedicherò poi un articolo finale, a conclusione del progetto per descrivere come funziona la centralina e come analizzare i dati creando grafici con Excel.
Lo sketch della centralina humidity temperatura suolo
lo sketch della centralina humidity temperatura suolo è sempre lo stesso presentato nei precedenti articoli:
- centralina humidity temperatura suolo – lo sketch
- centralina humidity temperatura suolo – lo sketch – parte II
In questo articolo analizzi le ultime funzioni:
- readSensor()
- viewSensor()
- saveData()
- ctrlButton()
/* * centralina humidity temperatura suolo con Arduino * * @author: Alfieri Mauro * Tw: @mauroalfieri * Web: www.mauroalfieri.it */ #include <Wire.h> #include "RTClib.h" #include <SdFat.h> #include <dht11.h> #include <SHT1x.h> #include <Adafruit_Sensor.h> #include <Adafruit_BMP085_U.h> #include <LiquidCrystal.h> #define CS 10 #define DHT11_PIN 15 #define SHT_dataPin 2 #define SHT_clockPin 3 #define BLAKLIGHT 16 #define BUTTON A0 int setModeTime=2000; int setViewTime=2000; unsigned long time=0; unsigned long timeSet=0; int SELECT[] = {720,760}; int LEFT[] = {480,520}; int RIGTH[] = {0,20}; int UP[] = {120,160}; int DOWN[] = {300,350}; RTC_DS1307 RTC; dht11 DHT; SHT1x sht1x(SHT_dataPin, SHT_clockPin); LiquidCrystal lcd(8,9,4,5,6,7); char buffer[50]; char lcdBuffer[16]; int DHT_h; int DHT_t; char BMP_p[10]; char SHT_t[10]; char SHT_h[10]; int current; //File myFile; SdFat sd; SdFile myFile; Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085); void setup () { Serial.begin(9600); // Serial.print("Initializing SD card..."); pinMode( CS,OUTPUT ); pinMode( BUTTON,INPUT ); pinMode( BLAKLIGHT,OUTPUT ); blacklightOn(); lcd.begin(16, 2); lcd.setCursor(0,0); lcd.print("Mandorleto v1.0"); lcd.setCursor(0,1); lcd.print("mauroalfieri.it"); delay( 3000 ); lcd.clear(); lcd.setCursor(0,0); lcd.print("Init SD Card..."); lcd.setCursor(0,1); //if (!SD.begin(CS)) { if (!sd.begin(CS, SPI_HALF_SPEED)) { sd.initErrorHalt(); // Serial.println("initialization failed!"); lcd.print("... Failed "); while(1); } // Serial.println("initialization done."); lcd.print("... Ready "); delay( 2000 ); lcd.clear(); Wire.begin(); RTC.begin(); RTC.sqw(0); //0 Led off - 1 Freq 1Hz - 2 Freq 4096kHz - 3 Freq 8192kHz - 4 Freq 32768kHz lcd.setCursor(0,0); lcd.print("Init BMP085 ..."); lcd.setCursor(0,1); delay( 200 ); if(!bmp.begin()) { Serial.print("BMP085 Failed"); lcd.print("... Failed "); while(1); } lcd.print("... Ready "); delay( 2000 ); lcd.clear(); blacklightOff(); } void loop () { if ( ctrlButton( analogRead( BUTTON ) ) == 0 || ctrlButton( analogRead( BUTTON ) ) > 1 ) { time = millis(); } DateTime now = RTC.now(); if (time > 0 && setModeTime < (millis() - time) ) { blacklightOn(); now = setMode( now ); lcd.clear(); } if (( now.minute() == 00 || now.minute() == 15 || now.minute() == 30 || now.minute() == 45 ) && (now.minute() != current)) { blacklightOn(); current=now.minute(); saveData( now ); lcd.clear(); } if ( ctrlButton( analogRead( BUTTON ) ) > 1 ) { blacklightOn(); viewSensor(); lcd.clear(); } sprintf(lcdBuffer, "%02d/%02d/%04d", now.day(), now.month(), now.year() ); lcd.setCursor(0,0); lcd.print(lcdBuffer); sprintf(lcdBuffer, "%02d:%02d:%02d", now.hour(), now.minute(), now.second() ); lcd.setCursor(0,1); lcd.print(lcdBuffer); delay( 1000 ); blacklightOff(); } void blacklightOn() { digitalWrite( BLAKLIGHT,HIGH ); } void blacklightOff() { digitalWrite( BLAKLIGHT,LOW ); } DateTime setMode( DateTime now ) { boolean setModeVal = true; int setModeLevel = 0; int _day = now.day(); int _month = now.month(); int _year = now.year(); int _hour = now.hour(); int _min = now.minute(); int _sec = now.second(); lcd.clear(); lcd.setCursor(0,0); sprintf(lcdBuffer, "%s: %02d", "Giorno", _day); delay( 1000 ); timeSet = millis(); while ( setModeVal ) { if ( ctrlButton( analogRead( BUTTON ) ) >= 1 ) { timeSet = millis(); } lcd.setCursor(0,0); // Set Day if ( setModeLevel == 0 ) { if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _day < 31) { _day++; } if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _day > 1) { _day--; } sprintf(buffer, "%s: %02d", "Giorno", _day); } // Set Month if ( setModeLevel == 1 ) { if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _month < 12) { _month++; } if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _month > 1) { _month--; } sprintf(buffer, "%s: %02d", "Mese", _month); } // Set Year if ( setModeLevel == 2 ) { if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _year < 9999) { _year++; } if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _year > 1900) { _year--; } sprintf(buffer, "%s: %02d", "Anno", _year); } // Set Hour if ( setModeLevel == 3 ) { if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _hour < 24) { _hour++; } if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _hour > 1) { _hour--; } sprintf(buffer, "%s: %02d", "Ora", _hour); } // Set Minute if ( setModeLevel == 4 ) { if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _min < 60) { _min++; } if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _min > 1) { _min--; } sprintf(buffer, "%s: %02d", "Minuti", _min); } // Set Second if ( setModeLevel == 5 ) { if ( ctrlButton( analogRead( BUTTON ) ) == 3 && _sec < 60) { _sec++; } if ( ctrlButton( analogRead( BUTTON ) ) == 2 && _sec > 0) { _sec--; } sprintf(buffer, "%s: %02d", "Secondi", _sec); } lcd.print( buffer ); if ( ctrlButton( analogRead( BUTTON ) ) == 4 && setModeLevel > 0) { lcd.clear(); setModeLevel--; } if ( ctrlButton( analogRead( BUTTON ) ) == 5 && setModeLevel < 5 ) { lcd.clear(); setModeLevel++; } // if ( setModeLevel > 5 ) { setModeLevel=0; } if ((timeSet > 0 && (setModeTime*2) < (millis() - timeSet)) || ( ctrlButton( analogRead( BUTTON ) ) == 1) ) { RTC.adjust(DateTime(_year, _month, _day, _hour, _min, _sec)); setModeVal = false; } delay(200); } return RTC.now(); } void readSensor() { int chk = DHT.read(DHT11_PIN); if ( chk != DHTLIB_OK ) { lcd.clear(); lcd.setCursor(0,0); lcd.print("DHT11 (Aria)"); lcd.setCursor(0,1); switch (chk){ case DHTLIB_OK: lcd.print("SUCCESS"); break; case DHTLIB_ERROR_CHECKSUM: lcd.print("Checksum error"); break; case DHTLIB_ERROR_TIMEOUT: lcd.print("Time out error"); break; default: lcd.print("Unknown error"); break; } delay( setViewTime ); } DHT_h=DHT.humidity; DHT_t=DHT.temperature; // ----------------------------------------------------------------------- sensors_event_t event; bmp.getEvent(&event); if (event.pressure) { dtostrf(event.pressure, 5, 2, BMP_p); } // ----------------------------------------------------------------------- dtostrf(sht1x.readHumidity(), 5, 2, SHT_h); dtostrf(sht1x.readTemperatureC(), 5, 2, SHT_t); } void viewSensor() { lcd.clear(); readSensor(); lcd.clear(); lcd.setCursor(0,0); lcd.print("DHT11 (Aria)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %02d", "Humidty", DHT_h); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("DHT11 (Aria)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %02d", "Temp.", DHT_t); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("BMP085 Pressione"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %s", "Pressione", BMP_p); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("SHT (Suolo)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %s", "Humidity", SHT_h); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("SHT (Suolo)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %s", "Temp.", SHT_t); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); } void saveData( DateTime now ) { readSensor(); sprintf(buffer, "%02d/%02d/%d %02d:%02d:%02d %02d %02d %s %s %s", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), DHT_h, DHT_t, BMP_p, SHT_h, SHT_t ); lcd.clear(); lcd.setCursor(0,0); lcd.print("Salvataggio dati"); if (myFile.open("dati.log", O_RDWR | O_CREAT | O_AT_END)) { myFile.println(buffer); myFile.close(); lcd.setCursor(0,1); lcd.print("SD Write Success"); } else { sd.errorHalt("opening dati.log for write failed"); lcd.setCursor(0,1); lcd.print("SD Write Error"); } delay(1000); } int ctrlButton( int button ) { if ( SELECT[0] <= button && button <= SELECT[1] ) { return 1; } if ( LEFT[0] <= button && button <= LEFT[1] ) { return 2; } if ( RIGTH[0] <= button && button <= RIGTH[1] ) { return 3; } if ( UP[0] <= button && button <= UP[1] ) { return 4; } if ( DOWN[0] <= button && button <= DOWN[1] ) { return 5; } return 0; }
Funzione readSensor()
La funzione readSensor() della centralina humidity temperatura suolo è incaricata di interrogare i 3 sensori presenti sulla centralina e popolare 5 variabili che userai sia in fase di visualizzazione ( viewSensor ) sia in fase di salvataggio ( saveData )
void readSensor() { int chk = DHT.read(DHT11_PIN); if ( chk != DHTLIB_OK ) { lcd.clear(); lcd.setCursor(0,0); lcd.print("DHT11 (Aria)"); lcd.setCursor(0,1); switch (chk){ case DHTLIB_OK: lcd.print("SUCCESS"); break; case DHTLIB_ERROR_CHECKSUM: lcd.print("Checksum error"); break; case DHTLIB_ERROR_TIMEOUT: lcd.print("Time out error"); break; default: lcd.print("Unknown error"); break; } delay( setViewTime ); } DHT_h=DHT.humidity; DHT_t=DHT.temperature; // ----------------------------------------------------------------------- sensors_event_t event; bmp.getEvent(&event); if (event.pressure) { dtostrf(event.pressure, 5, 2, BMP_p); } // ----------------------------------------------------------------------- dtostrf(sht1x.readHumidity(), 5, 2, SHT_h); dtostrf(sht1x.readTemperatureC(), 5, 2, SHT_t); }
linea 232: interroga il sensore DHT usando il metodo read() dell’istanza DHT e salva il valore restituito nella variabile chk;
linea 233: se il valore di chk è identico a quello della costante DHTLOB_OK definita nella libreria DHT vuol dire che la la lettura del sensore DHT della centralina humidity temperatura suolo è avvenuta con successo ed hai letto i valori di temperatura ed umiità dal sensore;
linee 234-237: scrivi sulla prima linea dell’LCD la stringa “DHT11 (Aria)” e posiziona il cursore sulla seconda linea;
linee 238-251: scrive sulla seconda riga del display un meggassio relativo all’esito della lettura del sensore DHT11;
linea 252: attendi un tempo pari a quello definito in setViewTime();
linee 254-255: assegna i valori di temperatura ed umidità alle relative variabili DHT_t e DHT_h che userai per la visualizzazione;
linee 257-258: leggi il valore di pressione dal sensore BMP085;
linea 259: assegna il valore letto dal BMP085 alla variabile BMP_p dopo aver convertito il valore float restituito dalla libreria BMP in un valore di tipo char formato da 5 cifre di cui 2 decimali;
linee 261-262: interroga il sensore SHT1x ed elabora i risultati come alla riga 259;
Funzione viewSensor()
la funzione viewSensor() della centralina humidity temperatura suolo ha il compito di visualizzare sul monitor LCD i dati raccolti dai sensori attraverso la funzione readSesor().
void viewSensor() { lcd.clear(); readSensor(); lcd.clear(); lcd.setCursor(0,0); lcd.print("DHT11 (Aria)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %02d", "Humidty", DHT_h); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("DHT11 (Aria)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %02d", "Temp.", DHT_t); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("BMP085 Pressione"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %s", "Pressione", BMP_p); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("SHT (Suolo)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %s", "Humidity", SHT_h); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); lcd.setCursor(0,0); lcd.print("SHT (Suolo)"); lcd.setCursor(0,1); sprintf(lcdBuffer, "%s %s", "Temp.", SHT_t); lcd.print(lcdBuffer); delay( setViewTime ); lcd.clear(); }
la linea 266: pulisci il display LCD e richiama la funzione readSensor();
linee 268-273: scrivi sul display LCD la prima riga “DHT11 (Aria)” e sulla seconda riga il valore di umidità in % rilevato dallo stesso DHT11;
linea 275: attendi il tempo specificato nella variabile setViewTime prima di procedere oltre;
linee 277-282: pulisci il display e scrivi sempre sulla prima riga il tipo di sensore letto e il mezzo in cui lo hai letto, in questo caso ancora Aria per distinguerlo dal Suolo che visualizzerai in seguito. Sulla seconda riga scrivi il valore di temperatura rilvata;
linea 283: identica alla linea 275;
linee 286-291: Scrivi sul display il sensore che stai leggendo “BMP085 Pressione” ed il valore rilevato per la pressione;
linea 293: identica alla 275;
linee 295-311: compie le medesime operazioni delle linee precedenti per il sensore SHT1x;
linea 312: pulisci il display LCD;
Funzione saveData()
la saveData() è la funzione che si occupa del vero e proprio salvataggio dei dati sulla scheda SD.
Scopo della centralina humidity temperatura suolo è rilevare i dati di temperatura e umidità dell’aria e del suolo e salvarli come datalog su una scheda SD da 2Gb.
void saveData( DateTime now ) { readSensor(); sprintf(buffer, "%02d/%02d/%d %02d:%02d:%02d %02d %02d %s %s %s", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), DHT_h, DHT_t, BMP_p, SHT_h, SHT_t ); lcd.clear(); lcd.setCursor(0,0); lcd.print("Salvataggio dati"); if (myFile.open("dati.log", O_RDWR | O_CREAT | O_AT_END)) { myFile.println(buffer); myFile.close(); lcd.setCursor(0,1); lcd.print("SD Write Success"); } else { sd.errorHalt("opening dati.log for write failed"); lcd.setCursor(0,1); lcd.print("SD Write Error"); } delay(1000); }
linea 316: richiami la funzione readSensor() per aggiornare i valori dei sensori da scrivere sulla SD Card;
linee 317-319: prepari la linea da scrivere nel file di log, la sequenza di scrittura dei dati è:
dd/mm/aaa hh:mm:ss temp_aria umidità_aria pressione temp_suolo umidità_suolo
tutti i valori sono separati da spazio e questa informazione ti servirà in fase di importazione dati su excel;
linee 321-323: pulisci il display da precedenti messaggi e scrivi sulla prima linea il messaggio “Salvataggio dati”;
linee 324-329: se riesci ad aprire il dile DATI.LOG in scrittura aggiungi una nuova linea con i dati predisposti alle linee 317-319, chiudi il file e scrivi sulla seconda linea “SD Write Success”;
linee 319-333: scrivi sul display il messaggio “SD Write Error” sulla seconda riga del display;
linea 334: aspetta un secondo prima di uscire dalla funzione, questo tempo è necessario a leggere il messaggio di Success o Error verificatosi durante la scrittura su SD.
Cosa leggi sul display della centralina datalogger
Ho realizzato qualche foto durante la visualizzazione dei valori rilevati dalla centralina humidity temperatura suolo dopo il montaggio:
premendo un pulsante visualizzi data ed ora con la retroilluminazione dell’LCD
premendo il pulsante DOWN iniziano a scorrere in automatico i valori rilevati dai sensori:
temperatura dell’aria:
pressione atmosferica:
umidità del suolo o terreno in cui hai inserito la sonda SHT1x:
temperatura del suolo attraverso la sonda SHT1x:
Nel prossimo articolo vedrai come organizzare i dati raccolti in Excel e come creare dei grafici.
Buona rilevazione della temperatura ed umidità con la tua centralina arduino.
13 commenti
Vai al modulo dei commenti
Ciao Mauro, prima della domanda colgo l’occasione per ringraziarti per tutto quello che hai messo online! Una vera e propria enciclopedia di Arduino.
Vengo alla domanda: ho problemi con la libreria RTClib, l’ho scaricata dal sito ufficiale (il solito al quale rimandano i tanti risultati trovati su google ricercando RTClib). Niente da fare, non la riconosce…
Ho avuto diversi messaggi di errore, l’ho rinominata RTClib e messa nella cartella libraries come sempre, ma niente da fare. È la prima volta che ho un problema di questo tipo, non so proprio che fare. Potresti eventualmente, quando hai tempo, provare a inviarmi per mail la tua copia funzionante? In questo modo dovrei risolvere il problema al 99%….
Ti saluto Mauro, a presto
Autore
Ciao Francesco,
ti ho inviato la mia libreria, considera che è stata modificata per funzionare anche con shield sperimentali e potrebbe presentare degli errori di funzionamento.
Ciao Mauro, grazie, abbiamo risolto il problema (nel frattempo ne ho avuto un altro al pc, ho dovuto aprire la batteria e sostituire le celle al litio, ho fatto una roba da vergognarsi a raccontarlo….). Grazie di nuovo Mauro, alla prossima!
ciao; mi unisco ai complimenti; grazie per questa miniera di informazioni! anche io ho problemi con le librerie originali scaricate ed installate; non le riconosce; sono forse state modificate dal produttore e non più compatibili con lo sketch pubblicato? mi riferisco alle librerie della shield datalogging.
Alex
Autore
Ciao Alex,
che errore ti restituisce? Sei certo di averle installate in modo corretto? Trovi dei tutorial su come fare sul web e nei miei articoli.
Ho provato a compilare lo sketch:”centralina humidity temperatura suolo con Arduino.” ne sito https://www.mauroalfieri.it/elettronica/centralina-humidity-temperatura-suolo-lo-sketch-parte-iii.html
Spero di aver installato correttamente tutte le librerie, per inciso in un lavoro così ben fatto perché non sono incluse, però alla fine saltano fuori i seguenti errori
centralinaMeteo1.ino: In function ‘void setup()’:
centralinaMeteo1.ino:82:10: error: ‘sd’ was not declared in this scope
centralinaMeteo1.ino:96:9: error: ‘class RTC_DS1307’ has no member named ‘sqw’
centralinaMeteo1.ino: In function ‘void saveData(DateTime)’:
centralinaMeteo1.ino:310:52: error: ‘O_AT_END’ was not declared in this scope
centralinaMeteo1.ino:316:7: error: ‘sd’ was not declared in this scope
Errore durante la compilazione
Che fare?
Grazie
Renzo
Autore
Ciao Renzo,
non è necessario inserire un link ad un mio articolo in un commento allo stesso articolo 🙂
Hai dei problemi con le librerie ma non sembrano dipendere dalla cattiva inclusione, piuttosto il primo dalla mancata dichiarazione alla linea 053-054-055 e la seconda si riferisce ad una libreria RTC standard che non ha la funzione “sqw” puoi commentare quella riga e risolvere il problema.
salve Mauro,
Ho corretto come suggerito, ho cambiato anche la formattazione per farla corrispondere al tuo listato ma gli errori sono sempre:
centralinaMeteoX.ino:53:1: error: ‘SdFat’ does not name a type
centralinaMeteoX.ino: In function ‘void setup()’:
centralinaMeteoX.ino:80:10: error: ‘sd’ was not declared in this scope
centralinaMeteoX.ino: In function ‘void saveData(DateTime)’:
centralinaMeteoX.ino:324:52: error: ‘O_AT_END’ was not declared in this scope
centralinaMeteoX.ino:330:7: error: ‘sd’ was not declared in this scope
Errore durante la compilazione
ed io non sono in grado di correggere errori del tipo
Salve
Renzo
Autore
Ciao Renzo,
avrai già notato che l’errore sulla funzione sqw è sparito.
Ora puoi concentrarti sulla libreria SD che probabilmente non è corretta o non è installata nel tuo IDE.
Salve, ti ringrazio per la tua attenzione e per le tue risposte sempre pronte, purtroppo per mia ignoranza non ho risolto.
E’ mia intenzione mettere dei sensori meteo all’esterno, con dei dati tipo i tuoi, non mi serve l’umidità del suolo ma è solo questione di sostituzione di sensori , e trasmettere i dati all’interno per registrarli su SD o sul computer.
La parte WiFi l’ho risolta in parte con il modulo nRF24L01, mi imbatto in istruzioni del tipo:
Mirf.getData((byte *) &time); o
sprintf(lcdBuffer, “%02d/%02d/%04d”, now.day(), now.month(), now.year() );
per la rilevazione o trasformazioni di dati.
Cosa significano e dove vado a studiarmi le espressioni senza leggere un intero corso in C?
Grazie
Autore
Ciao Renzo,
la prima linea sembra un metodo di una istanza richiamata tramite una libreria, tuttavia non saperi dirti di cosa si tratta, non la conosco.
La seconda linea la utilizzo spesso nei miei sketch e puoi leggere in qualche mio articolo come funziona.
Ciao Mauro! Quanto vorrei essere un tuo studente… Complimenti per gli articoli, devo dire che sono sempre bene fatti.
Ho provato a replicare la centralina di temperatura-umidità aggiungendo un relè(collegato ad un’elettrovalvola) e un sensore di umidità analogico per il terreno.
Seguendo più o meno il tuo schema tutto funziona tranne che il salvataggio del valore del sensore analogico. Sul display visualizzo correttamente tutti i valori dei sensori (digitali e non), ma quando vado a leggere il file di testo dal pc, al posto dei valori dell’umidità del terreno mi risultano tanti simboli strani.
Hai qualche idea?
Grazie
Autore
Ciao Alessandro,
i miei corsi sono aperti a tutti, si tratta di corsi privati a cui ti puoi iscrivere e partecipare.
Il problema dei simboli visualizzati nel file potrebbe essere un problema di codifica, assicurati che il valore letto sia un char come si aspetta la linea 317, in alternativa se usi un altro tipo di valore devi adattare la linea alla corretta codifica.