Skip to content
Snippets Groups Projects
Commit 1251a07b authored by Elisabetta Pianori's avatar Elisabetta Pianori
Browse files

Merge branch 'zz_addDMM6500_update_libMeter' into 'devel'

add DMM6500 multimeter and add IMeter to libMeter

See merge request !206
parents 11563a3d 1b4fcaa8
No related branches found
No related tags found
6 merge requests!308Bring main and devel back in sync,!300playing with fixing divergence between devel and main,!287Updates for Julabo Chiller,!285Julabo Chiller Added with Fixed Pipeline Compatibility,!269Merge devel into main: largest change is code formatting checker and enforcement in CI,!206add DMM6500 multimeter and add IMeter to libMeter
Pipeline #2435076 passed
......@@ -16,6 +16,11 @@ add_executable(fluke_example)
target_sources(fluke_example PRIVATE fluke_example.cpp)
target_link_libraries(fluke_example PRIVATE Utils Meter Com)
# multimeter
add_executable(multimeter_example)
target_sources(multimeter_example PRIVATE multimeter_example.cpp)
target_link_libraries(multimeter_example PRIVATE Utils Meter Com)
# scope
if ( ${libScope_FOUND} )
add_executable(scope_example)
......
#include <iostream>
#include <iomanip>
#include "Logger.h"
#include "DMM6500.h"
#include "CharDeviceCom.h"
int main(int argc, char*argv[]) {
DMM6500 meter(argv[1]);
std::shared_ptr<CharDeviceCom> com = std::make_shared<CharDeviceCom>(argv[1]);
meter.setCom(com);
meter.reset();
/* ping multimeter */
meter.ping(0);
/* ping scanner card */
meter.ping(1);
std::cout<<"=======================================scan result========================================="<<std::endl;
std::cout<<std::setw(13)<<" Ch1 [Ohm],"<<std::setw(13)<<" Ch2 [Ohm],"<<std::setw(13)<<" Ch3 [Ohm],"
<<std::setw(13)<<" Ch4 [pF],"<<std::setw(13)<<" Ch5 [pF],"<<std::setw(13)<<" Ch9 [pF],"<<std::setw(13)<<" Ch10 [pF],"<<std::endl;
std::cout<<std::setw(12)<<meter.measureRES(1, true)<<",";
std::cout<<std::setw(12)<<meter.measureRES(2, true)<<",";
std::cout<<std::setw(12)<<meter.measureRES(3, true)<<",";
std::cout<<std::setw(12)<<meter.measureCAP(4)*1e12<<",";
std::cout<<std::setw(12)<<meter.measureCAP(5)*1e12<<",";
std::cout<<std::setw(12)<<meter.measureCAP(9)*1e12<<",";
std::cout<<std::setw(12)<<meter.measureCAP(10)*1e12<<",";
std::cout<<std::endl;
std::cout<<"==========================================================================================="<<std::endl;
return 0;
}
add_library(Meter SHARED)
target_sources(Meter
PRIVATE
IMeter.cpp
Keithley2000.cpp
Fluke8842.cpp
HP3478A.cpp
PM6680.cpp
DMM6500.cpp
)
target_link_libraries(Meter PRIVATE Com Utils)
target_include_directories(Meter PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
......
#include "DMM6500.h"
#include "Logger.h"
#include "IMeter.h"
#include "ScopeLock.h"
DMM6500::DMM6500(const std::string& name) : IMeter(name, {"DMM6500"}){ }
bool DMM6500::ping(unsigned dev)
{
std::string result = "";
if(dev == 0){
logger(logDEBUG) <<"ping the multimeter.....";
result = m_com->sendreceive("*IDN?");
}
if(dev == 1){
logger(logDEBUG)<<"ping scanner card.....";
result = m_com->sendreceive(":SYSTem:CARD1:IDN?");
}
result.erase(result.size()-1);
if(result.empty())
throw std::runtime_error("Failed communication with the device");
else
logger(logDEBUG)<<result;
return !result.empty();
}
std::string DMM6500::identify()
{
std::string idn=m_com->sendreceive("*IDN?");
return idn;
}
void DMM6500::autowait() {
m_com->send("*OPC");
int ESRValue = 0;
while ( (ESRValue & 1) == 0)
{
ESRValue = std::stoi(m_com->sendreceive("*ESR?"));
std::this_thread::sleep_for(std::chrono::milliseconds(m_wait));
}
}
void DMM6500::send(const std::string& cmd) {
logger(logDEBUG) << __PRETTY_FUNCTION__ << " -> Sending: " << cmd;
m_com->send("*CLS");
m_com->send(cmd);
this->autowait();
}
std::string DMM6500::sendreceive(const std::string& cmd) {
m_com->send("*CLS");
std::string buf=m_com->sendreceive(cmd);
this->autowait();
logger(logDEBUG) << __PRETTY_FUNCTION__ << " -> Received: " << buf;
buf.erase(buf.size()-1);
return buf;
}
void DMM6500::reset() {
logger(logDEBUG) << __PRETTY_FUNCTION__ << " -> Initialising: ";
this->send("*RST");
}
void DMM6500::sendScanCommand(std::string channel){
this->send(":ROUT:SCAN:CRE (@"+channel+")");
this->send(":ROUT:SCAN:COUNT:SCAN 1");
this->send(":TRAC:CLE");
this->send("INIT");
this->send("*WAI");
}
//measure DC voltage with high precision
//take average of 10 repeatings
double DMM6500::measureDCV(unsigned channel){
std::string s_ch = "";
if(channel > 0)//use scanner card
s_ch = ", (@"+std::to_string(channel)+")";
ScopeLock lock(m_com);
this->send("*RST");
this->send(":SENS:FUNC \"VOLT:DC\""+s_ch);
this->send(":SENS:VOLT:RANG:AUTO ON"+s_ch);
this->send(":SENS:VOLT:INP AUTO"+s_ch);
this->send(":SENS:VOLT:NPLC 1"+s_ch);
this->send(":SENS:VOLT:AZER ON"+s_ch);
this->send(":SENS:VOLT:AVER:TCON REP"+s_ch);
this->send(":SENS:VOLT:AVER:COUN 10"+s_ch);
this->send(":SENS:VOLT:AVER ON"+s_ch);
if(channel > 0)//use scanner card
this->sendScanCommand(std::to_string(channel));
return std::stod(this->sendreceive(":READ?"));
}
//measure resistance (2W or 4W)
//take average of 10 repeatings
double DMM6500::measureRES(unsigned channel, bool use4w){
std::string n_func = "RES";
if(use4w)
n_func = "FRES";
std::string s_ch = "";
if(channel > 0)//use scanner card
s_ch = ", (@"+std::to_string(channel)+")";
ScopeLock lock(m_com);
this->send("*RST");
this->send(":SENS:FUNC \""+n_func+"\""+s_ch);
this->send(":SENS:"+n_func+":RANG:AUTO ON"+s_ch);
if(use4w)
this->send(":SENS:"+n_func+":OCOM ON"+s_ch);
this->send(":SENS:"+n_func+":AZER ON"+s_ch);
this->send(":SENS:"+n_func+":NPLC 1"+s_ch);
this->send(":SENS:"+n_func+":AVER:TCON REP"+s_ch);
this->send(":SENS:"+n_func+":AVER:COUN 10"+s_ch);
this->send(":SENS:"+n_func+":AVER ON"+s_ch);
if(channel > 0)//use scanner card
this->sendScanCommand(std::to_string(channel));
return std::stod(this->sendreceive(":READ?"));
}
//measure capacitance
//take average of 10 repeatings
double DMM6500::measureCAP(unsigned channel){
std::string s_ch = "";
if(channel > 0)//use scanner card
s_ch = ", (@"+std::to_string(channel)+")";
ScopeLock lock(m_com);
this->send("*RST");
this->send(":SENS:FUNC \"CAP\""+s_ch);
this->send(":SENS:CAP:RANG:AUTO ON"+s_ch);
this->send(":SENS:CAP:AVER:TCON REP"+s_ch);
this->send(":SENS:CAP:AVER:COUN 10"+s_ch);
this->send(":SENS:CAP:AVER ON"+s_ch);
if(channel > 0)//use scanner card
this->sendScanCommand(std::to_string(channel));
return std::stod(this->sendreceive(":READ?"));
}
//measure DC current with high precision
//take average of 10 repeatings
double DMM6500::measureDCI(unsigned channel){
std::string s_ch = "";
if(channel > 0)//use scanner card
s_ch = ", (@"+std::to_string(channel)+")";
ScopeLock lock(m_com);
this->send("*RST");
this->send(":SENS:FUNC \"CURR:DC\""+s_ch);
this->send(":SENS:CURR:RANG:AUTO ON"+s_ch);
this->send(":SENS:CURR:NPLC 1"+s_ch);
this->send(":SENS:CURR:AZER ON"+s_ch);
this->send(":SENS:CURR:AVER:TCON REP"+s_ch);
this->send(":SENS:CURR:AVER:COUN 10"+s_ch);
this->send(":SENS:CURR:AVER ON"+s_ch);
if(channel > 0)//use scanner card
this->sendScanCommand(std::to_string(channel));
return std::stod(this->sendreceive(":READ?"));
}
#ifndef DMM6500_H
#define DMM6500_H
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include "IMeter.h"
/*
DMM6500 multimeter
Author: Zhicai Zhang
Date: Feb 2021
Reference 1: https://www.tek.com/tektronix-and-keithley-digital-multimeter/dmm6500-manual/model-dmm6500-6-1-2-digit-multimeter-3
Reference 2: https://www.tek.com/manual/model-dmm6500-6-1-2-digit-multimeter-user-manual
2000-Scan card note: https://www.tek.com/default-accessory-series-manual/model-2000-scan-scanner-card
*/
class DMM6500 : public IMeter {
public:
DMM6500(const std::string& name);
/** ping the device
* @param dev: index of the device to ping (if there are multiple parts connected)
* dev = 0 is for the main meter
* dev > 0 is for other parts that's connected to the meter
*/
virtual bool ping(unsigned dev = 0);
virtual std::string identify();
virtual void reset();
/** measure DC voltage (unit: V)
* @param channel: channel ID to perform the measurement
* channel = 0 means without scanner card
* channel > 0 means measure with specific channel on scanner card
*/
virtual double measureDCV(unsigned channel = 0);
/** measure DC current (unit: A)
* @param channel: channel ID to perform the measurement
* channel = 0 means without scanner card
* channel > 0 means measure with specific channel on scanner card
*/
virtual double measureDCI(unsigned channel = 0);
/*
measure resistance (unit: Ohm)
* @param channel: channel ID to perform the measurement
* channel = 0 means without scanner card
* channel > 0 means measure with specific channel on scanner card
* @param use4w: whether or not use 4-wire method
*/
virtual double measureRES(unsigned channel = 0, bool use4w = false);
/*
measure capacitance (unit: F)
* @param channel: channel ID to perform the measurement
* channel = 0 means without scanner card
* channel > 0 means measure with specific channel on scanner card
*/
virtual double measureCAP(unsigned channel = 0);
private:
void send(const std::string& cmd);
void sendScanCommand(std::string channel="1");
std::string sendreceive(const std::string& cmd);
void autowait();
std::chrono::milliseconds m_wait{10};
};
#endif
#include "IMeter.h"
#include "Logger.h"
IMeter::IMeter(const std::string& name, std::vector<std::string> models) {
m_name = name;
m_models = models;
}
void IMeter::setCom(std::shared_ptr<ICom> com)
{
if(!com->is_open())
com->init();
m_com = com;
if(!ping(0))
throw std::runtime_error("Failed communication with the multimeter");
}
bool IMeter::ping(unsigned dev)
{
logger(logWARNING) << "ping() not implemented for this multimeter.";
return false;
}
void IMeter::checkCompatibilityList()
{
// get model connected to the meter
std::string idn = identify();
// get list of models
std::vector<std::string> models = IMeter::getListOfModels();
if (models.empty()){
logger(logINFO) << "No model identifier implemented for this meter. No check is performed.";
return;
}
for(const std::string& model : models)
{
if(idn.find(model) != std::string::npos)
return;
}
logger(logERROR)<< "Unknown meter: " << idn;
throw std::runtime_error("Unknown meter: " + idn);
}
std::vector<std::string> IMeter::getListOfModels()
{
return m_models;
}
double IMeter::measureDCV(unsigned channel){
logger(logWARNING) << "measureDCV() not implemented for this multimeter.";
return 0;
}
double IMeter::measureRES(unsigned channel, bool use4w){
logger(logWARNING) << "measureRES() not implemented for this multimeter.";
return 0;
}
double IMeter::measureCAP(unsigned channel){
logger(logWARNING) << "measureCAP() not implemented for this multimeter.";
return 0;
}
double IMeter::measureDCI(unsigned channel){
logger(logWARNING) << "measureDCI() not implemented for this multimeter.";
return 0;
}
#ifndef IMETER_H
#define IMETER_H
#include <iostream>
#include <string>
#include "ICom.h"
/* Generic multimeter interface
a typical workflow:
IMeter meter(name);
meter.setCom(com);
meter.reset();
meter.ping(0);
meter.measureDCV();
//....
*/
class IMeter {
public:
/** Constructor.
* @param name: name of the meter
* @param models: list of tested models (empty means no check is performed)
*/
IMeter(const std::string& name, std::vector<std::string> models={});
void setCom(std::shared_ptr<ICom> com);
/** ping the device
* @param dev: index of the device to ping (if there are multiple parts connected)
* dev = 0 is for the main meter
* dev > 0 is for other parts that's connected to the meter
*/
virtual bool ping(unsigned dev = 0);
virtual void reset() = 0;
/** Check that the device model is supported by checking that
* model identifier of the connected meter contains
* one of the supported models for that meter
* Throws exception if compatibility is not found
* If the list of model identifiers is empty, no check is performed
*/
virtual void checkCompatibilityList();
/* Return list of supported models. */
virtual std::vector<std::string> getListOfModels();
/** Returns the model of the meter connected.
* Meter classes should return an empty string if this functionality does not exist
*/
virtual std::string identify() = 0;
/** measure DC voltage (unit: V)
* @param channel: channel ID to perform the measurement
*/
virtual double measureDCV(unsigned channel = 0);
/** measure DC current (unit: A)
* @param channel: channel ID to perform the measurement
*/
virtual double measureDCI(unsigned channel = 0);
/** measure resistance (unit: Ohm)
* @param channel: channel ID to perform the measurement
* @param use4w: whether or not use 4-wire method
*/
virtual double measureRES(unsigned channel = 0, bool use4w = false);
/** measure capacitance (unit: F)
* @param channel: channel ID to perform the measurement
*/
virtual double measureCAP(unsigned channel = 0);
protected:
std::shared_ptr<ICom> m_com = nullptr;
/** Store device configuration name */
std::string m_name;
std::vector<std::string> m_models;
};
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment