Měření napětí pomocí ADC

Project owner: Cyberian
Interested:
Related:
License: Uveďte původ-Zachovejte licenci CC BY-SA

Tento projekt vznikl po problémech s pojízdnou plošinou, na které sedí děti, plošina má dvě kamery a ty sledují černou izolační pásku nalepenou na zemi. Pokud díte zmačkne a drží tlačítko, plošina jede po černě vyznačené cestě, dokud se tlačítko neuvolní. Problém nástaval v momentu kdy nám obsluha jezdila i na vybité baterie i přes zvukovou signalizaci. Sice by šla nainstalovat nějaká ochrana baterií, ale proč to řešit tak jednoduše :-), jde mi o to najít člověka, který to dělá a zničil již dva bateriové packy. Napadlo mne tedy využít k měření ESP8266, které u nás v Labce někteří používají, měřit na baterii napětí a pravidelně ho posílat přes wifi spojení na server do grafany. Ideální příležitost, jak se naučit s ESP na něčem reálném. Část, kde bude řešena Grafana a nezbytné služby a protokoly bude v samostatném projektu Grafana a data z ADC

Materiál:

  • ESP8266 (Nodemcu nebo např. Wemos mini D1)
  • 5x rezistor 10K
  • OLED-091 diymore 128×32 I2C dispej
  • nepájivé kontaktní pole, případně pájitelné
  • baterii 12V, nebo ideálně zdroj napětí 15V

ESP8266 má interní 10 bitový AD převodník. Jeho vstup je na pinu A0 a dá se číst pomocí funkce analogRead(0). Vstupní napětí, které je schopen měřit je od 0 V do 3,3 V. Baterie jsou sice 2x 12 V v sérii, ale bude stačit měřit jen jednu. Pro měření napětí od 0 do 15V, což je pro mne maximální předpokládané napětí na baterii použijeme dělič napětí v poměru 10K ku 40K. Pokud by si někdo chtěl spočítat bez práce vlastní, pak může využít Webový kalkulátor (díky Ivane za link :-)).

K internímu převodníku je dobré poznamenat, že má dva módy. Jeden pro měření napětí 3,3 V přicházejícího do ESP8266, který se nastavuje zavoláním ADC_MODE(ADC_VCC); a jeden pro externí měření na pinu A0. Tento pin má někdy označení i jako TOUT. Rozsah hodnot převodníku 0 až 1024 namapujeme na rozsah napětí 0 až 15 V pomocí funkce map.

Při měření multimetrem se zjistilo, že AD převodník není přesný, jak by měl být. Byla tam odchylka cca 6%, což je hodně. Jednoduše se zvětšil interval(rozsah) hodnot ve funkci map. Funkce map je velmi šikovná, udělá spread hodnot z jednoho rozsahu hodnot na jiný rozsah. Zvláštní je, že podle různých zkušeností ostatních lidí se interní AD převodníky různých ESP8266 pletou o téměř stejnou hodnotu. Nepřesnost převoníku má být cca 1%. Viz následující kód:

int adcread=(analogRead(0));
  float napeti= (float)(map(adcread, 0, 1024, 0, 16055))/1000; //adcread je int, měřená hodnota je v mV

Za zmíňku stojí část dokumentace k ADC od Espresiffu, kde se zmiňují o 107. bytu z počátku romky, kterým by se měl AD převodník dokalibrovat. Otázkou je zda to pomůže a tohle se musí ještě ozkoušet. Na ukázku uvedu citaci z dokumentace:

esp_init_data_default.bin is provided in SDK package which contains RF initialization parameters (0 ~ 127 bytes). The name of the 107th byte in esp_init_data_default.bin is vdd33_const, which is defined as below:

  • When vdd33_const = 0xff, the power voltage of Pin3 and Pin4 will be tested by the internal self-calibration process of ESP8266EX itself. RF circuit conditions should be optimized according to the testing results.
  • When 18 =< vdd33_const =< 36, ESP8266EX RF Calibration and optimization process is implemented via (vdd33_const/10).
  • When vdd33_const < 18 or 36 < vdd33_const < 255, vdd33_const is invalid. ESP8266EX RF Calibration and optimization process is implemented via the default value 3.3V

Jen drobnou poznámku. Pull up odpory pro displej mají chybku. Oba přivádějí pull up napájení 3.3 V jen na pin D2. Přehoďte si jeden znich tak, aby přiváděl pull up napájení na pin D1, kde chybí. Správně jsou vidět na předchozím projektu se zapojením OLED displeje.

Zde je prozatimní kód, který pouze ukazuje na displeji přidělenou IP adresu a naměřené napětí, na displej i do sériové konzole. Je potřeba nastavit si SSID wifi sítě.

// ADC_MODE(ADC_VCC); <--- tento kód by se použil na přepnutí módu z externího měření na interní měření napájení, čte pak však jinou funkcí
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// sekce pro displej
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// použít PROGMEM makro je důležité proto, aby se tato proměnná zapsala do ROM a nikoliv do velmi omezené RAM
// stejně tak funguje funkce F()
static const unsigned char PROGMEM zoja [] = 
{
0x20,0x0,0x0,0x20,
0x70,0x0,0x0,0x70,
0x50,0x0,0x0,0x50,
0xd8,0x0,0x0,0xd8,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x1,0xc0,0x0,0x0,
0x3,0x60,0x0,0x0,
0x2,0x20,0x78,0x0,
0x2,0x20,0x48,0x0,
0x2,0x20,0x48,0x0,
0x3,0x60,0x48,0x0,
0x1,0xc0,0x38,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,
0x1,0x0,0x8,0x0,
0x1,0x80,0x8,0x0,
0x0,0x88,0x98,0x0,
0x0,0xc5,0x10,0x0,
0x0,0x42,0x10,0x0,
0x0,0x65,0x30,0x0,
0x0,0x28,0xa0,0x0,
0x0,0x20,0x20,0x0
};

void setup() 
{
  Serial.begin(9600);
  Serial.println(F("Nastavuji piny pro I2C sběrnici..."));
  Wire.begin();
  Serial.println(F("Inicializuji displej"));
  
   // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) 
    { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // prasecká nekonečná smyčka :-P
    }
  delay(2000);
  display.clearDisplay();

  //Wifi sekce
  WiFi.begin("nejakeSSID", "nejakeheslo");
  Serial.print(F("Verze jádra: ")); Serial.println(ESP.getCoreVersion()); // vypiš verzi ESP jádra
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
  WiFi.printDiag(Serial);
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.print(F("IP: "));display.println(WiFi.localIP());
  display.drawBitmap(98,0,zoja, 29, 32, 1); (x,y,pole,
  display.display();
  
}

void loop() 
{

  int adcread=(analogRead(0));
  float napeti= (float)(map(adcread, 0, 1024, 0, 16055))/1000; // adcread je int, hodnota je tedy v mV
  Serial.print(F("ADC A0: "));Serial.print(adcread);Serial.print(F(" DEC, "));
  Serial.print(F("Napětí: "));Serial.print(napeti);Serial.println(F(" V"));
  display.setTextSize(1);
  display.setCursor(0,10);
  display.setTextColor(WHITE,BLACK); // pokud by bylo pouze WHITE, tak by se nepřepisovalo pozadí. Pozor Toto nefunguje u user fontů
  display.print(F("Napeti: "));display.print(napeti);display.println(F(" V"));
  display.display(); // vypis obsah bufferu na displej. Pokud není posláno, obraz se neaktualizuje
  delay(1000);
 
}

  • project/esp8266_adc.txt
  • Last modified: 2019/03/13 14:58
  • by cyberian