Ok, sembra andare meglio (anche se non hai fatto il Ctrl-T per indentare correttamente tutto il codice). Però se sarà un programma a gestire la comunicazione, dovresti per prima cosa togliere di mezzo tutti i "Serial.print()" che non rispettano il formato del protocollo (es. "Serial.println("Couldn't find RTC");
" eccetera). Inoltre ti consiglio di definire come variabile globale il buffer che usi per comporre le risposte, e dimensionato per poter contenere la stringa più lunga prevista (ossia metti in testa al programma un "char outBuf[20]
" ad esempio per definire un buffer stringa di massimo 19 caratteri).
Poi hai ancora quella "Serial.write()" di un singolo byte che non ha alcun senso: se le informazioni devono andare via seriale nel formato diciamo "CV\r\n
" dove "C" è il codice del parametro e "V" il relativo valore (come stringa decimale ad esempio), devi definire quindi quali sono i codici parametri e rispettare SEMPRE quel formato. Non penso sia necessario aggiungere un separatore come il punto e virgola (e neanche lo spazio) tra comando e valore, rende più semplice l'interpretazione lato VB, ma se preferisci puoi usare un punto e virgola.
Quindi per la lettura del potenziometro ad esempio non fare:
// Manda il dato come singolo byte
Serial.write(val);
bensì qualcosa tipo:
sprintf(outBuf, "P;%d", val);
Serial.println(outBuf);
Una cosa analoga devi farlo anche per i comandi che dal programma VB devi mandare al codice, devi definire cosa possa mandare ed il relativo formato e significato. Tutto questo si chiama "definire un protocollo di comunicazione".
Poi per la lettura dalla seriale prima di tentare di leggere verifica se "Serial.available()
" restituisce un valore maggiore di zero, ed in tal caso leggi il dato. Se nel protocollo prevedi un terminatore di riga (i caratteri '\r' e '\n', che puoi impostare anche in VB) come per i dati che mandi da Arduino, dovresti accumulare in un buffer tutti i caratteri ricevuti fino a che non ricevi '\n' (nel frattempo ignorando il classico CR ossia '\r') quando potrai interpretare la stringa che hai ricevuto. Se, come in questo caso, si limita ad un solo carattere, puoi anche fare una cosa più semplice, ma se ad esempio da VB devi mandare un comando con un parametro ti serve comunque qualcosa di più strutturato, ma lo vedrai in seguito.
Poi, in generale, metti all'inizio del codice le costanti con la "configurazione" (tipicamente i pin, da definire come "const byte"), e con identificatori sempre tutti in maiuscolo (per distinguere le variabili dalle costanti).
E per finire (per ora
) sappi che non è necesasrio chiamare "sprintf()
" per ogni elemento da inviare, ad esempio per l'orario puoi fare tutto con una sola istruzione:
sprintf(outBuf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
Quindi vedi questa versione (cerca di capire cosa ho modificato) e provala, io non l'ho provata, ma fallo tu e se funziona puoi partire da questa:
#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>
// CONFIGURAZIONE
const byte P_LED = 9;
const byte P_SET = 6;
const byte P_RESET = 7;
const byte P_RELE_APRE = 10; //relè x sbloccare porta
const byte P_RELE_BLOCCA = 11; //rele x bloccare porta
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345); //identifiacativo magnetometro
LiquidCrystal_I2C lcd(0x27, 16, 2); //display lcd x la visualizzazione dell orario
RTC_DS3231 rtc;
DateTime now;
char str[3];
int stato1 = 0;
int val = 0;
int val0 = 0;
// Buffer per la composizione delle stringhe da inviare via seriale
char outBuf[20];
void setup() {
Wire.begin();
Serial.begin(9600);
lcd.backlight();
lcd.init();
//pulsanti set e reset
pinMode(P_SET, INPUT);
pinMode(P_RESET, INPUT);
pinMode(P_LED, OUTPUT);
pinMode(P_RELE_APRE, OUTPUT);
pinMode(P_RELE_BLOCCA, OUTPUT);
digitalWrite(P_RELE_APRE, HIGH);
digitalWrite(P_RELE_BLOCCA, HIGH);
if (!rtc.begin()) { //inizializzo l rtc
Serial.println("Couldn't find RTC");
while (true)
;
}
if (!rtc.lostPower()) {
//Serial.println("RTC is NOT running, let's set the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
if (!mag.begin()) //inizializzo il magnetometro
{
/* There was a problem detecting the HMC5883 ... check your connections */
Serial.println("Ooops, no HMC5883 detected ... Check your wiring!");
while (1)
;
}
}
void loop() {
MostraOra();
bussola();
if (Serial.available()) {
// Gestione comandi da VB
// Per ora leggo solo un singolo carattere per volta
char comando = Serial.read();
switch (comando) {
case 'A':
digitalWrite(P_RELE_APRE, LOW);
delay(100); // attivo o disattivo i rele in base al comando ricevuto da visual basic
digitalWrite(P_RELE_APRE, HIGH);
break;
case 'O':
digitalWrite(P_RELE_BLOCCA, LOW);
delay(100);
digitalWrite(P_RELE_BLOCCA, HIGH);
break;
default:
// Ignoro qualsiasi altro carattere
break;
}
}
int val = 0;
// Somma tre letture consecutive
for (int i = 0; i < 3; ++i)
val += analogRead(A0);
// Calcola la media
val = val / 3;
// Riporta il valore tra 0 e 100 //calcolo la media dei valori del potenziometro x il controllo del volume e li invio tramite la seriale,
val = map(val, 0, 1023, 0, 100); // visualbasic cosi regolerà il volume del player
// Se il valore è cambiato
if (val < val0 - 1 || val > val0 + 1) {
// Manda il dato ("P" = potenziometro)
sprintf(outBuf, "P;%d", val);
Serial.println(outBuf);
val0 = val;
}
delay(100);
}
void bussola() { //evento bussola per indicare i gradi del magnetometro,
sensors_event_t event;
mag.getEvent(&event);
float heading = atan2(event.magnetic.y, event.magnetic.x);
float declinationAngle = 0.06;
heading += declinationAngle;
if (heading < 0) {
heading += 2 * PI;
}
if (heading > 2 * PI) {
heading -= 2 * PI;
}
float headingDegrees = heading * 180 / M_PI;
// Manda la lettura ("B"=bussola)
char deg[8];
// Gradi: ###.## quindi 6 caraatteri totali, inclusi 2 decimali)
dtostrf(headingDegrees, 6, 2, deg);
sprintf(outBuf, "B;%s", deg);
Serial.println(outBuf);
delay(500);
}
void MostraOra() {
switch (stato1) {
case 0:
displayTime();
break;
case 1:
setHour();
break;
case 2:
setMinute();
break;
case 3:
setSecond();
break;
case 4:
setyear();
break;
case 5:
setmonth();
break;
case 6:
setday();
break;
}
}
unsigned long t1, dt1;
bool isFirst = true;
void displayTime() {
if (isFirst) {
lcd.clear();
t1 = millis();
isFirst = false;
}
dt1 = millis() - t1;
if (dt1 > 1000) {
now = rtc.now();
lcd.setCursor(4, 1);
sprintf(str, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
lcd.print(str);
lcd.setCursor(3, 0);
sprintf(str, "%02d/%02d/%02d", now.day(), now.month(), now.year());
lcd.print(str);
t1 = millis();
}
if (digitalRead(P_SET)) {
//imposta ora
stato1 = 1;
delay(300);
isFirst = true;
}
}
int seth = 0;
void setHour() {
if (isFirst) {
lcd.clear();
now = rtc.now();
seth = now.hour();
lcd.setCursor(0, 0);
lcd.print("Imposta ora");
isFirst = false;
}
lcd.setCursor(0, 1);
sprintf(str, "%02d", seth);
lcd.print(str);
if (digitalRead(P_RESET)) {
seth++;
if (seth >= 24) seth = 0;
delay(200);
}
if (digitalRead(P_SET)) {
//salva ora scelta e passa ai minuti
rtc.adjust(DateTime(now.year(), now.month(), now.day(), seth, now.minute(), now.second()));
stato1 = 2;
isFirst = true;
delay(200);
}
}
int setm;
void setMinute() {
if (isFirst) {
lcd.clear();
now = rtc.now();
setm = now.minute();
lcd.setCursor(0, 0);
lcd.print("Imposta minuti");
isFirst = false;
}
lcd.setCursor(0, 1);
sprintf(str, "%02d", setm);
lcd.print(str);
if (digitalRead(P_RESET)) {
setm++;
if (setm >= 60) setm = 0;
delay(200);
}
if (digitalRead(P_SET)) {
//salva min scelta e passa ai sec
rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), setm, now.second()));
stato1 = 3;
delay(200);
isFirst = true;
}
}
int sets = 0;
void setSecond() {
if (isFirst) {
lcd.clear();
now = rtc.now();
sets = now.second();
lcd.setCursor(0, 0);
lcd.print("Imposta sec.");
isFirst = false;
}
lcd.setCursor(0, 1);
sprintf(str, "%02d", sets);
lcd.print(str);
if (digitalRead(P_RESET)) {
sets++;
if (sets >= 60) sets = 0;
delay(200);
}
if (digitalRead(P_SET)) {
//salva sec scelta e passa ai minuti
rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), sets));
stato1 = 4;
delay(200);
isFirst = true;
}
}
int sety = 0;
void setyear() {
if (isFirst) {
lcd.clear();
now = rtc.now();
sety = now.year();
lcd.setCursor(0, 0);
lcd.print("Imposta anno");
isFirst = false;
}
lcd.setCursor(0, 1);
sprintf(str, "%02d", sety);
lcd.print(str);
if (digitalRead(P_RESET)) {
sety++;
if (sety >= 9999) sety = 0;
delay(200);
}
if (digitalRead(P_SET)) {
//salva sec scelta e passa ai minuti
rtc.adjust(DateTime(sety, now.month(), now.day(), now.hour(), now.minute(), now.second()));
stato1 = 5;
delay(200);
isFirst = true;
}
}
int setmo = 0;
void setmonth() {
if (isFirst) {
lcd.clear();
now = rtc.now();
setmo = now.month();
lcd.setCursor(0, 0);
lcd.print("Imposta mese");
isFirst = false;
}
lcd.setCursor(0, 1);
sprintf(str, "%02d", setmo);
lcd.print(str);
if (digitalRead(P_RESET)) {
setmo++;
if (setmo >= 12) setmo = 0;
delay(200);
}
if (digitalRead(P_SET)) {
//salva sec scelta e passa ai minuti
rtc.adjust(DateTime(now.year(), setmo, now.day(), now.hour(), now.minute(), now.second()));
stato1 = 6;
delay(200);
isFirst = true;
}
}
int setd = 0;
void setday() {
if (isFirst) {
lcd.clear();
now = rtc.now();
setd = now.day();
lcd.setCursor(0, 0);
lcd.print("Imposta giorno");
isFirst = false;
}
lcd.setCursor(0, 1);
sprintf(str, "%02d", setd);
lcd.print(str);
if (digitalRead(P_RESET)) {
setd++;
if (setd >= 32) setd = 0;
delay(200);
}
if (digitalRead(P_SET)) {
//salva sec scelta e passa ai minuti
rtc.adjust(DateTime(now.year(), now.month(), setd, now.hour(), now.minute(), now.second()));
stato1 = 0;
delay(200);
isFirst = true;
}
}