Ho fatto solo qualche scorrimento di testo.
// Sketch for Arduino magnetometer
// Measures strength of magnetic field with SS49E hall sensor
// #define LCD /* Display LCD 1602, altrimenti OLED SSD1306 */
// E' adatto anche per display OLED con le 16 righe superiori di colore diverso (p. es. gialle), perché lì scrive nome
// e versione, mentre tutto il resto va nella parte inferiore blu.
const char *percorso=__FILE__; // Dalla macro __FILE__ prende il percorso del file in uso. Questa parte di programma,
char ver[10]; // però, si trova nel file/cartella dell'IDE c_setup, in cui non è scritta la versione
// del programma. La versione è scritta nel file principale, che ha lo stesso nome della
// cartella che contiene tutti i file del programma. Questa riga, quindi, non può stare
// nel setup.
#include <EEPROM.h>
#ifdef LCD
#include <PCF8574_HD44780_I2C.h>
// LCD 16x2 con indirizzo I2C 0x27:
PCF8574_HD44780_I2C lcd(0x27,16,2);
#else // OLED
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h> // v2.5.7 Ok
#include <Adafruit_GFX.h> // v1.0.6 Ok
Adafruit_SSD1306 display(128,64,&Wire,-1);
char txtDC_old[10]=" "; // Testo DC precedente per cancellarlo. E' inizializzata con 9 spazi.
char txtAC_old[10]=" "; // Testo AC precedente per cancellarlo. E' inizializzata con 9 spazi.
#endif
#define nmeas 2000 // stay below 2048 to avoid overflow
uint16_t nmeas_div_2 = nmeas/2;
#define cal_int 0.349*0.582 // calibration constant in mT per ADC count. nominal (5.0/1024)/0.014=0.349:
#define cal_est 0.349*0.582
float cal=cal_int;
#define per_let_bat 10000 // Periodo di lettura della tensione della batteria in ms: 10 secondi.
bool puls_prec=HIGH;
uint32_t t_press=0; // millis() alla pressione del pulsante.
float zero = 511.0; // nominal 511: halfway 0 and 1023
float temp;
bool zero_fatto=LOW;
bool G_mT=LOW; // HIGH=Gauss; LOW=mT.
bool sonda_int_est=LOW; // HIGH=sonda interna; LOW=sonda esterna.
bool sonda_int_est_prec=HIGH; // HIGH=sonda interna; LOW=sonda esterna.
uint32_t t_int_est=0; // Per la verfica della presenza della sonda esterna.
uint16_t vbat; // Tensione della batteria: lettura di A3: 1023=10V.
uint32_t t_bat=per_let_bat; // Per la lettura periodica della tensione della batteria, impostato per una prima lettura immediata.
uint32_t t_interm_bat; // Per l'intermittenza della batteria scarica.
bool corpo_bat=true; // Corpo della batteria visibile/non visibile per l'intermittenza.
void Bip() {tone(5,2000,100);}
void Biip() {tone(5,2000,400);}
void batteria()
{
analogReference(INTERNAL);
analogRead(A3); delay(10); vbat=analogRead(A3); // Serve un delay di almeno 7ms.
if(vbat>=860) display.fillRect(111,2,3,7,WHITE); // Barretta 4.
else display.fillRect(111,2,3,7,BLACK);
if(vbat>=800) display.fillRect(115,2,3,7,WHITE); // Barretta 3.
else display.fillRect(115,2,3,7,BLACK);
if(vbat>=740) display.fillRect(119,2,3,7,WHITE); // Barretta 2.
else display.fillRect(119,2,3,7,BLACK);
if(vbat>=680) display.fillRect(123,2,3,7,WHITE); // Barretta 1.
else display.fillRect(123,2,3,7,BLACK);
// display.display(); // Anche qui è inutile!...
analogReference(DEFAULT);
analogRead(A3); delay(10);
}
void test_puls()
{
if(digitalRead(6)==LOW) // Se è premuto:
{
if(puls_prec==HIGH) // Se è stato premuto adesso:
{
Bip();
puls_prec=LOW;
G_mT=!G_mT;
mask_H_Gauss_L_mT();
}
}
else t_press=millis();
}
void mask_H_Gauss_L_mT()
{
#ifdef LCD
lcd.setCursor(11,0); if(G_mT) lcd.print("G "); else lcd.print("mT");
lcd.setCursor(11,1); if(G_mT) lcd.print("G "); else lcd.print("mT");
#else // OLED
display.setTextSize(1);
display.setCursor(0,29); // DC.
if(G_mT) // DC - G.
{
display.setTextColor(BLACK); display.print("mT");// Cancella.
display.setCursor(0,29);
display.setTextColor(WHITE); display.print('G'); // Scrive.
}
else // DC - mT.
{
display.setTextColor(BLACK); display.print('G'); // Cancella.
display.setCursor(0,29);
display.setTextColor(WHITE); display.print("mT");// Scrive.
}
display.setCursor(0,56); // AC.
if(G_mT) // AC - G.
{
display.setTextColor(BLACK); display.print("mT");// Cancella.
display.setCursor(0,56);
display.setTextColor(WHITE); display.print('G'); // Scrive.
}
else // AC - mT.
{
display.setTextColor(BLACK); display.print('G'); // Cancella.
display.setCursor(0,56);
display.setTextColor(WHITE); display.print("mT");// Scrive.
}
#endif
}
void setup()
{
char *ver_ext=strrchr(percorso,'v'); // Va a cercare l'ultima 'v' nel percorso.
byte n_car=strlen(ver_ext)-4; // Calcola la lunghezza escludendo .ino.
strncpy(ver, ver_ext, n_car); // Copia i primi n_car caratteri da ver_ext a ver.
ver[n_car]='\0'; // Mette il terminatore in fondo.
pinMode(A0,INPUT); // Segnale del sensore Hall interno.
pinMode(A1,INPUT); // Segnale del sensore Hall esterno.
pinMode(5, OUTPUT); // Uscita per cicalino passivo.
pinMode(6,INPUT_PULLUP); // Pulsante a GND G/mT e azzeramento.
pinMode(7,INPUT_PULLUP); // Ingresso del consenso a GND della sonda esterna.
pinMode(8, OUTPUT); // Alimentazione per sonda esterna.
analogReference(DEFAULT);
#ifdef LCD
lcd.init();
lcd.backlight(); // Backlight ON
lcd.setCursor(2,0); lcd.print("MAGNETOMETRO");
lcd.setCursor((16-strlen(ver))/2, 1); lcd.print(ver);
delay(1500);
lcd.clear();
lcd.setCursor(1,0); lcd.print("DC");
lcd.setCursor(1,1); lcd.print("AC");
if(digitalRead(7))
{
EEPROM.get(0, temp); // float: 0,1,2,3. Legge lo zero della sonda interna.
if(temp>-1000 && temp<1000) zero=temp;
}
else
{
EEPROM.get(4, temp); // float: 4,5,6,7. Legge lo zero della sonda esterna.
if(temp>-200 && temp<200) zero=temp;
}
G_mT=EEPROM.read(8); // HIGH=Gauss.
mask_H_Gauss_L_mT();
#else // OLED
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 0x3C: Indirizzo I2C.
// display.clearDisplay(); // Cancella immediatamente il logo automatico Adafruit :)
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(28,0); display.print("MAGNETOMETRO");
display.setCursor((106-15-6*strlen(ver))/2 +20, 8); display.print(ver);
display.setCursor(0,16); display.print("Press.breve: G/mT RMS");
display.setCursor(80,28); display.print(">>");
display.setCursor(0,40); display.print("Press.lunga: Zero DC");
display.display();
display.startscrollright(3,4);
delay(2500);
display.stopscroll();
display.setTextColor(BLACK);
display.setCursor(80,28); display.print(">>"); // Cancella >> che, non so perché, riappare
display.setTextColor(WHITE); // nella posizione iniziale dello scroll!
for(uint8_t x=0; x<17; x+=4) {display.fillRect(x,16,4,48,BLACK); display.display();}
if(digitalRead(7))
{
display.setCursor(0,0); display.print("Int"); sonda_int_est_prec=LOW;
}
else
{
display.setCursor(0,8); display.print("Est"); sonda_int_est_prec=HIGH;
}
display.setCursor(0,16); display.print("DC");
display.setCursor(0,43); display.print("AC");
if(digitalRead(7))
{
EEPROM.get(0, temp); // float: 0,1,2,3. Legge lo zero della sonda interna.
if(temp>-1000 && temp<1000) zero=temp;
}
else
{
EEPROM.get(4, temp); // float: 4,5,6,7. Legge lo zero della sonda esterna.
if(temp>-200 && temp<200) zero=temp;
}
G_mT=EEPROM.read(8); // HIGH=Gauss.
mask_H_Gauss_L_mT();
for(uint8_t x=17; x<125; x+=4) {display.fillRect(x,16,4,48,BLACK); display.display();}
display.drawRect(106,3,3,5,WHITE); // Contatto +.
display.drawRect(109,0,19,11,WHITE); // Corpo.
display.display();
#endif
}
void loop()
{
if(millis()/1000==0 || millis()-t_bat>per_let_bat)
{
t_bat=millis();
batteria();
}
if(vbat<680)
{
if(millis()-t_interm_bat>500)
{
t_interm_bat=millis();
if(corpo_bat)
{
display.drawRect(109,0,19,11,BLACK); // Cancella il corpo.
display.drawRect(106,3,3,5,BLACK); // Cancella il contatto +.
}
else
{
display.drawRect(109,0,19,11,WHITE); // Disegna il corpo.
display.drawRect(106,3,3,5,WHITE); // Disegna il contatto +.
}
corpo_bat=!corpo_bat;
}
}
if(millis()-t_int_est>=500) // Ogni mezzo secondo controlla se è stata inserita la sonda esterna.
{
t_int_est=millis();
sonda_int_est=digitalRead(7);
if(sonda_int_est!=sonda_int_est_prec)
{
display.setTextSize(1);
if(sonda_int_est) // Sonda interna.
{
digitalWrite(8, HIGH); // Alimenta la sonda interna.
EEPROM.get(0, temp); // float: 0,1,2,3. Legge lo zero della sonda interna.
if(temp>-1000 && temp<1000) zero=temp;
cal=cal_int; // Carica la calibrazione della sonda interna.
display.setCursor(0,8); display.setTextColor(BLACK); display.print("Est"); // Cancella.
display.setCursor(0,0); display.setTextColor(WHITE); display.print("Int"); // Scrive.
}
else // Sonda esterna.
{
digitalWrite(8, LOW); // Toglie tensione alla sonda interna per risparmiare energia.
EEPROM.get(4, temp); // float: 4,5,6,7. Legge lo zero della sonda esterna.
if(temp>-1000 && temp<1000) zero=temp;
cal=cal_est; // Carica la calibrazione della sonda esterna.
display.setCursor(0,0); display.setTextColor(BLACK); display.print("Int"); // Cancella.
display.setCursor(0,8); display.setTextColor(WHITE); display.print("Est"); // Scrive.
}
delay(200);
}
sonda_int_est_prec=sonda_int_est;
}
uint32_t sum=0;
uint32_t sumsq=0;
for(uint16_t n=0; n<nmeas; n++) // Impiega 224ms (112us a lettura), pari a 11 cicli a 50Hz.
{
uint32_t val;
if(sonda_int_est) val=analogRead(A0); // Sonda interna.
else val=analogRead(A1); // Sonda esterna.
sum+=val;
sumsq+=val*val;
if(n==nmeas_div_2) test_puls(); // Il controllo della pressione del pulsante ogni 224ms
} // era troppo lento: a volte la pressione non era rilevata,
test_puls(); // perciò lo faccio anche a metà misura.
if(digitalRead(6)==HIGH) // Se il pulsante non è premuto
{
if(puls_prec==LOW) EEPROM.update(8,G_mT); // Se è stato appena lasciato, memorizza G/mT.
puls_prec=HIGH;
zero_fatto=LOW;
}
if(millis()-t_press>1000 && !zero_fatto)
{
zero_fatto=HIGH;
G_mT=!G_mT; // Ripristina la visualizzazione precedente alla pressione lunga.
mask_H_Gauss_L_mT();
zero=(float)sum/nmeas;
if(sonda_int_est) EEPROM.put(0, zero); // Memorizza lo zero della sonda interna.
else EEPROM.put(4, zero); // Memorizza lo zero della sonda esterna.
Biip();
}
// Calculate DC and AC field strength. AC corresponds to RMS of the fluctuations
float B_DC = ((float)sum/nmeas - zero)*cal;
float B_ACsq = ((float)sumsq/nmeas - pow((float)sum/nmeas, 2))*pow(cal, 2);
float B_AC = 0.0;
if (B_ACsq>0.000025) B_AC=pow(B_ACsq, 0.5);
B_AC=pow(B_ACsq, 0.5);
char txt[10]; // Text buffer needed to print formatted float
#ifdef LCD
lcd.setCursor( 3, 0);
#else
display.setTextSize(3);
#endif
if(!G_mT) // DC in mT.
{
dtostrf(B_DC,7,2,txt);
}
else // DC in G.
{
dtostrf(B_DC*10,7,1,txt);
}
#ifdef LCD
lcd.print(txt);
#else // OLED
display.setCursor(0,16);
display.setTextColor(BLACK); display.print(txtDC_old); // Cancella.
display.setCursor(0,16);
display.setTextColor(WHITE); display.print(txt); // Scrive.
#endif
#ifdef LCD
lcd.setCursor( 3, 1);
#else // OLED
strcpy(txtDC_old, txt);
#endif
if(!G_mT) // AC in mT.
{
dtostrf(B_AC,7,2,txt);
}
else // AC in G.
{
dtostrf(B_AC*10,7,1,txt);
}
#ifdef LCD
lcd.print(txt);
#else // OLED
display.setCursor(0,43);
display.setTextColor(BLACK); display.print(txtAC_old); // Cancella.
display.setCursor(0,43);
display.setTextColor(WHITE); display.print(txt); // Scrive.
display.display();
strcpy(txtAC_old, txt);
#endif
}
/*
Fis.I/OPorta
1 - RS
2 0 PD0
3 1 PD1
4 2 PD2
5 3 PD3
6 4 PD4 Consenso sonda esterna (a GND).
--
11 5 PD5 Uscita per cicalino passivo.
12 6 PD6 Pulsante di azzeramento DC (con INPUT_PULLUP) verso GND con 100nF in parallelo.
13 7 PD7
14 8 PB0 Alimentazione per sonda interna.
----------
15 9 PB1
16 10 PB2
17 11 PB3
18 12 PB4
19 13 PB5
--
23 14 PC0 A0 SS49E int.
24 15 PC1 A1 SS49E est.
25 16 PC2 A2
26 17 PC3 A3 Vbat/2
27 18 PC4 A4 SDA | Al display
28 19 PC5 A5 SCL | SSD1306.
29 20 A6 (solo in Arduino Nano)
Fis
9 PB6 XTAL 16MHz In : compensatore a GND (ho messo 22+10pF).
10 PB7 XTAL 16MHz Out: 22pF a GND.
21 ARef
7,20: Vcc
8,22: GND
EEPROM
0-3: float zero_int.
4-7: float zero_est.
8: bool Gauss/mT.
*/