Skocz do zawartości
rziomber

Multimetr DC oparty na Arduino z logowaniem danych na komputerze poprzez Bluetooth

Pomocna odpowiedź

Napisano (edytowany)

Multimetry logujące dane na komputerze są drogie. Nie mówiąc już o miernikach monitorujących równocześnie napięcie, natężenie i moc oraz rezystancję odbiornika. Może więc warto zrobić coś takiego samemu?

Projekt służy jedynie do pomiaru w obwodach prądu stałego przy NIEWIELKICH napięciach (nominalnie do 26V) i ograniczonym natężeniu (sprawdź specyfikację zastosowanego modułu). Absolutnie nie należy go stosować przy napięciu sieciowym, czy też wysokowydajnych źródłach prądu (np akumulator samochodowy pomimo bezpiecznego napiącia 13V w razie zwarcia może dostarczyć KILKASET AMPERÓW, co również może okazać się groźne)!

Arduino_Bluetooth_Multimeter.thumb.jpg.e5ffc1a18457ade27af1898ce9e89e55.jpglog.thumb.png.59efab5b9550c8ecdfc9f4e13ab2ab52.png

Składniki:

schemat.thumb.png.ed13600d84a49deb274e1c24799b176e.png

Bluetooth HC-05 oraz 06 obsługują poziom logiczny napięć 3.3V. Gotowe moduły posiadają jednak na ogół stabilizator pozwalający zasilić je bezpośrednio z 5V. Nadal pozostaje jednak problem 5V "logicznych" z wyjścia UART (czyli pinu TX) w Arduino. Najlepiej zastosować tu dzielnik napięcia lub konwerter poziomów logicznych. Ja wstawiłem szeregowo rezystor by w razie czego ograniczyć natężenie prądu. To jeszcze nie "zabiło" HC-06, ale też nie jest rozwiązaniem "podręcznikowym" i zalecanym. Port nadawczy (TX) w Bluetooth możemy za to bez obaw podłączyć bezpośrednio z odbiorczym (RX) w Arduino.

Kod źródłowy w tym wypadku był prawdę mówiąc banalny do napisania, gdyż wymagał jedynie drobnych zmian przykładu dla stosowanej biblioteki.

#include <Wire.h>
#include <Adafruit_INA219.h> //https://github.com/adafruit/Adafruit_INA219
#include <LiquidCrystal_I2C.h> //https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <Narcoleptic.h> //https://github.com/rcook/narcoleptic
#define DiodeVoltageDrop 0.42

LiquidCrystal_I2C lcd(0x27, 16, 2);
Adafruit_INA219 ina219;

void setup(void)
{
  Serial.begin(9600);
  while (!Serial) {
    // will pause Zero, Leonardo, etc until serial console opens
    delay(1);
  }
  Narcoleptic.disableTimer1();
  Narcoleptic.disableTimer2();
  Narcoleptic.disableADC();
  Narcoleptic.disableSPI();

  uint32_t currentFrequency;

  // Initialize the INA219.
  // By default the initialization will use the largest range (32V, 2A).  However
  // you can call a setCalibration function to change this range (see comments).
  ina219.begin();
  // To use a slightly lower 32V, 1A range (higher precision on amps):
  //ina219.setCalibration_32V_1A();
  // Or to use a lower 16V, 400mA range (higher precision on volts and amps):
  //ina219.setCalibration_16V_400mA();

  lcd.begin();
  lcd.backlight();
}

void loop(void)
{
  //  float shuntvoltage = 0;
  float busvoltage = 0;
  float current_mA = 0;
  //  float loadvoltage = 0;
  float power_mW = 0;

  //  shuntvoltage = ina219.getShuntVoltage_mV();
  busvoltage = ina219.getBusVoltage_V() + DiodeVoltageDrop;
  current_mA = 1086.5 / 1104.0 * (ina219.getCurrent_mA() - 1.4);
  power_mW = abs(busvoltage * current_mA);
  float impedance = abs(busvoltage / current_mA * 1000.0);
  //  power_mW = ina219.getPower_mW();
  //  loadvoltage = busvoltage + (shuntvoltage / 1000);

  Serial.print(busvoltage); Serial.print("V ");
  Serial.print(current_mA, 1); Serial.print("mA ");
  Serial.print(power_mW, 0); Serial.print("mW ");
  Serial.print(impedance, 1); Serial.println((char)244);

  lcd.clear();
  lcd.print(busvoltage);
  lcd.print("V ");
  lcd.print(current_mA, 1);
  lcd.print("mA");
  lcd.setCursor(0, 1);
  lcd.print(power_mW, 0);
  lcd.print("mW ");
  lcd.print(impedance, 1);
  lcd.print((char)244);
  Narcoleptic.delay(500);
}

Do pomiaru napięcia przez układ INA219 wymagane jest połączenie GND zasilania elektroniki z GND mierzonego obwodu. Z tego też względu nie zalecam zasilać urządzenia z gniazda USB w komputerze.  W razie pomyłki możemy uszkodzić komputer! Dlatego do "kablowania" danych użyłem Bluetooth. INA219 niestety nie toleruje również odwrotnej polaryzacji - potencjał po stronie mierzonego prądu nie może być niższy względem GND. Może to doprowadzić do uszkodzenia układu. Nie jest to więc urządzenie odpowiednie do "ręcznego" pomiaru napięcia zwykłymi sondami z multimetru - niezmiernie łatwo tu o odwrotną polaryzację! Dla bezpieczeństwa wstawiłem diodę pomiędzy masą miernika a mierzonego układu. Nieco przekłamuje to pomiar napięcia (spadek napięcia na diodzie nie jest dokładnie stały, jak skorygowałem w szkicu). Za to sama konstrukcja powinna zapewnić wygodną obsługę.

Z boku znajdziemy gniazdo DC do podłączenia zasilacza dla mierzonego układu oraz gniazda bananowe dla kabli "wyjściowych".

gniazda.thumb.jpg.de8e158f1c7add51aa6f1e44f0a9a3a4.jpg

Do zestawu oczywiście NIE dołączono uniwersalnego zestawu kabli pomiarowych. Musiałem więc zrobić je sobie sam 😉

Kable.thumb.jpg.6dd3588233b6c222b78e07392179aa35.jpg

Przewody z wtykiem bananowym 4 mm na wejściu są zakończone:

  • wtykiem DC 5.5/2.1 mm (wtedy multimetr jest po prostu "przedłużaczem" zwykłego zasilacza)
  • ponownie wtykiem bananowym, co umożliwia zastosowanie np "krokodylków" jako nakładki czy podłączenie "normalnego" multimetru celem kalibracji
  • zaciskiem typu "hak" do bezpośredniego wpinania się w goldpiny

Łatwo więc podłączymy nasze urządzenie pomiędzy zasilacz a odbiornik.

zasilacz.thumb.jpg.b73d2e702756fa754225b5b7a6cc9a9d.jpg

Po podłączeniu komputera z modułem Bluetooth - UART utworzony jest wirtualny port szeregowy. Np dla Linuksa powstanie plik urządzenia /dev/rfcomm*. Uzyskane pomiary możemy zapisać w postaci logu np za pomocą putty czy też terminalowych narzędzi dla Linuksa.

Napisałem też własny program w C++, który zapisze dane otrzymane z portu szeregowego do pliku. Skompilujemy go poprzez

g++ serial2log.cpp serialib/serialib.cpp -o serial2log -std=c++17

Wcześniej należy jednak umieścić Serialib ::: Simple Serial Library w folderze serialib. Jako parametry wywoływanego programu podajemy adres portu szeregowego, baud rate oraz nazwę pliku tekstowego z logiem.

Np: ./serial2log /dev/ttyUSB0 9600 log.txt

Pracę kończymy w bardzo "brutalny" sposób: Ctrl + C.

//g++ serial2log.cpp serialib/serialib.cpp -o serial2log -std=c++17
#include <iostream>
#include <chrono>
#include <thread>
#include <fstream>
#include <ctime>
#include "serialib/serialib.h" //http://serialib.free.fr

int main(int argc, char *argv[])
{
    if (argc != 4)
    {
        std::cout << "Usage: ./serial2log serial_port baud_rate log_file\n";
        return 0;
    }
    serialib LS;                                                            // Object of the serialib class
    int Ret;                                                                // Used for return values
    char Buffer[128];
    
    // Open serial port
    
    Ret=LS.Open(argv[1],atoi(argv[2]));                                        // Open serial link
    if (Ret!=1) {                                                           // If an error occured...
        std::cout << "Error while opening port. Permission problem?\n";        // ... display a message ...
        return Ret;                                                         // ... quit the application
    }
    std::cout << "Serial port opened successfully!\n";
    
    std::ofstream logfile;
    logfile.open(argv[3], std::ios::out | std::ios::app);
    
    /*
    Ret=LS.WriteString("AT\n");                                             // Send the command on the serial port
    if (Ret!=1) {                                                           // If the writting operation failed ...
    std::cout << "Error while writing data\n";                              // ... display a message ...
    return Ret;                                                         // ... quit the application.
    }
    std::cout << "Write operation is successful \n";
    */
    
    while(1){
    	Ret=LS.ReadString(Buffer,'\n',128,5000);                                // Read a maximum of 128 characters with a timeout of 5 seconds
    	// The final character of the string must be a line feed ('\n')
    	if (Ret>0){ 
    		std::time_t currentTime = std::time(nullptr);
    		std::cout << currentTime << " >> " << Buffer;  // If a string has been read from, print the string
    		logfile << currentTime << " >> " << Buffer << std::flush;
    	}
    	else
    		std::cout << "TimeOut reached. No data received !\n";                   // If not, print a message.
    	
    	std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    
    // Close the connection with the device
    LS.Close();
    logfile.close();
    return 0;
}

Zastosowanie: całkowanie numeryczne poboru prądu po czasie. Mamy urządzenie, którego "łakomstwo" zmienia się w czasie, a my chcemy oszacować czas jego pracy na akumulatorze. Musimy więc jakoś uśrednić jego pobór prądu. Np montaż paralaktyczny teleskopu pobiera inne natężenie prądu w trakcie podążania za ruchem dobowym nieba, a inne w trybie pozycjonowania na zadany obiekt (GoTo). Po testach będziemy mogli więc oszacować, jak długo będzie on pracował zasilany z akumulatora żelowego.

EQ-6_SIRUI_K40X.thumb.jpg.77525d846a4ad6ef9db9d2e8b1dbb5b7.jpg

Edytowano przez rziomber
  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Właśnie zaakceptowałem Twój opis, możesz go teraz zgłosić do akcji rabatowej umieszczając link w temacie zbiorczym. Dziękuję za przedstawienie ciekawego projektu, zachęcam do prezentowania kolejnych DIY oraz aktywności na naszym forum 🙂

Udostępnij ten post


Link to post
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »

×