Skocz do zawartości

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


rziomber

Pomocna odpowiedź

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
Link do komentarza
Share on other sites

Podoba Ci się ten projekt? Zostaw pozytywny komentarz i daj znać autorowi, że zbudował coś fajnego!

Masz uwagi? Napisz kulturalnie co warto zmienić. Doceń pracę autora nad konstrukcją oraz opisem.

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.