Tworzymy proste urządzenie, które będzie wyświetlać i zapisywać na karcie SD pomiary napięć dostarczanych na 4 porty.
Do tego celu wykorzystamy Arduino UNO i kilka innych elementów, poniżej lista potrzebnych gratów:
Połączenia wykonujemy według poniższego diagramu. Biblioteki Arduino których używamy w dużej części wymuszają użycie kontkretnych pinów. Z rezystorów budujemy dzielniki napięć które pozwolą nam podłączyć do Arduino bezpiecznie źródła napięć 12V (realny margines przy dzielniku 2,2kΩ + 1kΩ to 16V co pozwoli monitorować np.: ładowanie akumulatorów kwasowo-ołowiowych). Takie źródła wpinamy pomiędzy rezystory, pamiętać należy by przyłączyć masę badanych układów do masy naszego loggera.
Źródła o napięciu 5V możemy podłączyć bezpośrednio tak jak załączony na obrazku sensor natężenia prądu ACS712, który podaje napięcia 0V-2.5V dla ujemnych prądów i 2.5-5V dla dodatnich prądów.

Biblioteki który będą potrzebne:
#include <SPI.h>
#include <SD.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
Do sterownia wyświetlaczem używamy biblioteki SSD1306Ascii zamiast bardzo popularnej Adafruit ze względu na wymagania dotyczące pamięci RAM. W przypadku równoczesnego używania karty SD i wyświetlacza z biblioteką Adafruit pamięci zabraknie, mimo tego, że kompilator twierdzi, że pamięci wystarcza. Problem rodzi się w trakcie pracy - dynamicznie tworzony jest bufor ekranu i bufor do zapisu na karcie SD co całkowicie wysyca pamięć RAM. W zamian za mniejsze możliwości i migotanie przy czyszczeniu ekranu bibliotek SSD1306Ascii pozwoli na Arduino UNO używać kart SD z wyświetlaczem.
Zmienne globalne:
// zmienne używane przez bibliotekę obsługującą czytnik kart SD:
Sd2Card card;
SdVolume volume;
SdFile root;
File myFile;
// Piny do komunikacji z czytnikiem kart SD
const int chipSelect = 10; //Pin używany jako chipSelect w komunikacji SPI z czytnikiem kart
// Poniższe piny są zdefiniowane w bibliotece i tak musimy przyłączyć właściwe nóżki czytnika kart
// MOSI: 11
// MISO: 12
// SCK: 13
// Ekrany mają różne identyfikatory, najlepiej przed użyciem użyć przykładowego szkicu i2c_scanner
// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C
// Define proper RST_PIN if required.
#define RST_PIN -1
SSD1306AsciiAvrI2c oled;
// Dane dotyczące ekranu - piny do komunikacji zdefiniowane w bibliotece Wire.h
// Arduino UNO: A4(SDA), A5(SCL)
// Arduino MEGA 2560: 20(SDA), 21(SCL)
// Arduino LEONARDO: 2(SDA), 3(SCL)
//Przygotowujemy zmienne wykorzystywane bezpośrednio w naszym programie:
int a0int = 0;
int a1int = 0;
int a2int = 0;
int a3int = 0;
int analogPin0 = A0;
int analogPin1 = A1;
int analogPin2 = A2;
int analogPin3 = A3;
Funkcja setup():
void setup() {
screenInit();
cardInit();
}
Główna pętla programu:
void loop() {
a0int = analogRead(analogPin0);
a1int = analogRead(analogPin1);
a2int = analogRead(analogPin2);
a3int = analogRead(analogPin3);
drawData();
delay(1000);
writeData();
}
Ze względu na prowizoryczny charakter programu nie będziemy się bawić w żadne bardziej zaawansowane metody i do odmierzania czasu między pomiarami używamy funkcji delay().
Definicje funkcji używanych w programie:
void drawData() {
oled.clear();
oled.print("A0: "); oled.println(a0int);
oled.print("A1: "); oled.println(a1int);
oled.print("A2: "); oled.println(a2int);
oled.print("A3: "); oled.println(a3int);
}
void screenInit() {
#if RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0
// Call oled.setI2cClock(frequency) to change from the default frequency.
oled.setFont(X11fixed7x14B);
oled.clear();
oled.print("Hello");
delay(2000);
}
void writeData() {
myFile = SD.open("text.txt", FILE_WRITE);
myFile.print(a0int); myFile.print(";");
myFile.print(a1int); myFile.print(";");
myFile.print(a2int); myFile.print(";");
myFile.print(a3int); myFile.println(";");
myFile.close();
}
void cardInit() {
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
// Informujemy, że brakuje karty
oled.setFont(X11fixed7x14B);
oled.clear();
oled.print("Brak karty");
while (1);
}
oled.clear();
Serial.print("Card type: ");
switch (card.type()) {
case SD_CARD_TYPE_SD1:
oled.println("SD1");
break;
case SD_CARD_TYPE_SD2:
oled.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
oled.println("SDHC");
break;
default:
oled.println("nieznana karta");
}
// Próbujemy zaczytać kartę by sprawdzić czy jest na niej właściwy system plików
if (!volume.init(card)) {
//Jeżeli na karcie nie ma systemu plików FAT to program zapętla się w tym miejscu
oled.println("Brak FAT16/FAT32");
while (1);
}
delay(2000);
SD.begin();
}