Go Down

Topic: Arduino Library for M9803R Mastech Multimeter data logging (Read 4855 times) previous topic - next topic

gremlinc5

Hi, all.

This is my first post and my first library.

M9803R Library permit to collect data from a M9803R Mastech Multimeter, if you want it follow:

https://github.com/gremlinc5/Arduino-M9803R-Library

If you find some bug add an issue on github.

robtillaart

uint16_t _u16BaudRate;                                      ///< baud rate (300..115200) initialized in begin()


115200 does not fit in an uint16_t
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

gremlinc5

Hi

thank you for your interest, M9803R Multimeter works only at 9600 baudrate so that is not so important :)

I will remove that and don't let user to select a baudrate.

Cheers.

robtillaart

and adjust the comments accordingly :)

will have another look (I don't have such a MM so my remarks will be on code only)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Code: [Select]
void M9803RMaster::RefreshM9803R(void)
{
int8_t index_of_crlf = 0;
// Read data if available
while (M9803RSerial.available())
{
_u8ResponseBuffer[_u8ResponseBufferIndex] = M9803RSerial.read();
_u8ResponseBufferIndex++;
}

index_of_crlf = getEndOfPacket();
if (index_of_crlf != -1)
{
_u8M9803RStatus = M9803RCore(index_of_crlf);
}
}


should have a test on the array size.

Code: [Select]
void M9803RMaster::RefreshM9803R(void)
{
// Read data if available
while ( (M9803RSerial.available() > 0 ) && (_u8ResponseBufferIndex < ku8MaxBufferSize) )
{
_u8ResponseBuffer[_u8ResponseBufferIndex] = M9803RSerial.read();
_u8ResponseBufferIndex++;
}

int8_t index_of_crlf = getEndOfPacket();
if (index_of_crlf != -1)
{
_u8M9803RStatus = M9803RCore(index_of_crlf);
}
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Code: [Select]
void M9803RMaster::InitResponseBuffer(void)
{
for (uint8_t i = 0; i < ku8MaxBufferSize; i++){
_u8ResponseBuffer[i] = 0;
}
_u8ResponseBufferIndex = 0;
}


could be slightly faster

Code: [Select]
void M9803RMaster::InitResponseBuffer(void)
{
while( _u8ResponseBufferIndex > 0 )
        {
_u8ResponseBuffer[--_u8ResponseBufferIndex] = 0;
}
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Code: [Select]
uint8_t M9803RMaster::getEndOfPacket(void)
{
if (_u8ResponseBufferIndex >= 2)
{
for (uint8_t i = 0; i < (_u8ResponseBufferIndex - 1); i++){
if (_u8ResponseBuffer[i] == 0x0D)
{
if (_u8ResponseBuffer[i + 1] == 0x0A)
{
return i;
}
}
}
}
return -1;
}


has a bug.
return type is uint8_t so it cannot return a -1;
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

+ removed unreachable code from switches

+ used e notation for some floats (better do them all) - less typos
1e-4 == 1 * pow(10, -4) = 0.0001
1e3 == 1 * pow(10,3) = 1000

+ added missing return at the end

Code: [Select]

float M9803RMaster::ku8M9803RFloatConvertion(uint8_t unit, uint8_t range)
{
    switch (unit)
    {
    case 0:
    case 1: // ??
        switch (range)
        {
        case 0: return 1e-4;
        case 1: return 1e-3;
        case 2: return 1e-2;
        case 3: return 1e-1;
        case 4: return 1e0;
        default: return 0.0;
        }
    case 2:
    case 3: // ??
        switch (range)
        {
        case 0: return 1e-6;
        case 1: return 1e-5;
        case 2: return 1e-4;
        case 3:
        case 4: return 1e-3;
        default: return 0.0;
        }
    case 4:
    case 5: // ??
        switch (range)
        {
        case 0: return 1e-1;
        case 1: return 1e0;
        case 2: return 1e1;
        case 3: return 1e2;
        case 4: return 1e3;
        case 5: return 1e4;
        default: return 0.0;
        }
        break;
    case 6: // DIODE
        switch (range)
        {
        case 0:
        case 1: return 1e-3;
        default: return 0.0;
        }
        break;
    case 7: // ADP
    case 10: // Hz
        switch (range)
        {
        case 0: return 10.0;
        case 1: return 100.0;
        case 2: return 1000.0;
        case 5: return 0.1;
        case 6: return 1.0;
        default: return 0.0;
        }
        break;
    case 8:
    case 9: // ??
        switch (range)
        {
        case 0:
        case 2: return 0.01;
        default: return 0.0;
        }
        break;
    case 11:
        return 0.0;
    case 12:
        switch (range)
        {
        case 0: return 1e-12;
        case 1: return 1e-11;
        case 2: return 1e-10;
        case 3: return 1e-9;
        case 4: return 1e-8;
        default: return 0.0;
        }
    default:
        return 0.0;
    }
    return 0.0
}

give it a try
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

merging compacting,

Code: [Select]
M9803RMaster::ConvertUnitToChar(uint8_t unit)
{
if (unit > 12)
{
return ' ';
}
return "VVAAOODHAAH F"[unit];
}



ku8M9803RUnit can be removed;
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Refactored
Code: [Select]

uint8_t M9803RMaster::M9803RCore(int8_t index_crlf)
{
    uint8_t u8Status = ku8M9803RSuccess;
    uint8_t u8_unit;
    uint8_t u8_range;

    if (index_crlf < 9)
    {
        u8Status = ku8M9803RFrameMalformed;
    }
    else
    {
        // Store data
        _M9803RData.status = _u8ResponseBuffer[index_crlf - 9];
        if (_M9803RData.status & 0x01) // OL Over Range
        {
            u8Status = ku8M9803ROverRange;
        }
        else
        {
            _M9803RData.d0 = _u8ResponseBuffer[index_crlf - 8] - '0'; // char '7' != 7
            _M9803RData.d1 = _u8ResponseBuffer[index_crlf - 7] - '0';
            _M9803RData.d2 = _u8ResponseBuffer[index_crlf - 6] - '0';
            _M9803RData.d3 = _u8ResponseBuffer[index_crlf - 5] - '0';
           
            _M9803RData.unit = _u8ResponseBuffer[index_crlf - 4];
            _M9803RData.range = _u8ResponseBuffer[index_crlf - 3];
            // not used
            // _M9803RData.special_1 = _u8ResponseBuffer[index_crlf - 2];
            // _M9803RData.special_2 = _u8ResponseBuffer[index_crlf - 1];

            u8_unit = _M9803RData.unit & 127;
            u8_range = _M9803RData.range & 127;
           
            m9803r_absolute_value_unit = ConvertUnitToChar(u8_unit);
            uint16_t temp = _M9803RData.d0 + _M9803RData.d1 * 10 + _M9803RData.d2 * 100 + _M9803RData.d3 * 1000; // can be integer math.
            m9803r_absolute_value = temp * ku8M9803RFloatConvertion(u8_unit, u8_range);

            if (_M9803RData.status & 0x08) // if this bit is set sign is negative
            {
                m9803r_absolute_value *= -1.0;
            }
        }
    }
   
    InitResponseBuffer();
    return u8Status;
}


should also add

#define M9803R_LIB_VERSION "0.1.00"


sofar my remarks
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

gremlinc5

Refactored
Code: [Select]

uint8_t M9803RMaster::M9803RCore(int8_t index_crlf)
{
    uint8_t u8Status = ku8M9803RSuccess;
    uint8_t u8_unit;
    uint8_t u8_range;

    if (index_crlf < 9)
    {
        u8Status = ku8M9803RFrameMalformed;
    }
    else
    {
        // Store data
        _M9803RData.status = _u8ResponseBuffer[index_crlf - 9];
        if (_M9803RData.status & 0x01) // OL Over Range
        {
            u8Status = ku8M9803ROverRange;
        }
        else
        {
            _M9803RData.d0 = _u8ResponseBuffer[index_crlf - 8] - '0'; // char '7' != 7
            _M9803RData.d1 = _u8ResponseBuffer[index_crlf - 7] - '0';
            _M9803RData.d2 = _u8ResponseBuffer[index_crlf - 6] - '0';
            _M9803RData.d3 = _u8ResponseBuffer[index_crlf - 5] - '0';
           
            _M9803RData.unit = _u8ResponseBuffer[index_crlf - 4];
            _M9803RData.range = _u8ResponseBuffer[index_crlf - 3];
            // not used
            // _M9803RData.special_1 = _u8ResponseBuffer[index_crlf - 2];
            // _M9803RData.special_2 = _u8ResponseBuffer[index_crlf - 1];

            u8_unit = _M9803RData.unit & 127;
            u8_range = _M9803RData.range & 127;
           
            m9803r_absolute_value_unit = ConvertUnitToChar(u8_unit);
            uint16_t temp = _M9803RData.d0 + _M9803RData.d1 * 10 + _M9803RData.d2 * 100 + _M9803RData.d3 * 1000; // can be integer math.
            m9803r_absolute_value = temp * ku8M9803RFloatConvertion(u8_unit, u8_range);

            if (_M9803RData.status & 0x08) // if this bit is set sign is negative
            {
                m9803r_absolute_value *= -1.0;
            }
        }
    }
   
    InitResponseBuffer();
    return u8Status;
}


should also add

#define M9803R_LIB_VERSION "0.1.00"


sofar my remarks

Hi, this will not work. Data byte are sent from M9803R as raw byte not ascii chars.

I changed the code accordingly to your hints, thank you.

robtillaart

Quote
Hi, this will not work. Data byte are sent from M9803R as raw byte not ascii chars.
didn't know that, I've have an old multimeter that sent strings in ASCII.

I expect the footprint of the lib should become a bit smaller, can you confirm?
 
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

gremlinc5

Yes the footprint could be smaller but I want to make a Library with all function available. Special1 and Special2 needs to be coded.

If you want to debug example code use https://github.com/gremlinc5/VirtualInstrumentsM9803R
In the Publish folder there is a setup to install a M9803R Virtual Instrument. With that you will be able to send to your arduino M9803R packets with a simple USB to TTL converter.

Your PC with Virtual M9803R sends packets to your arduino.
Remeber to set RS232C CheckBox in the program or you will not get packets.

With the example code you will get the led set high if the value of the packet is greater than 10.0 (absolute value, not the four digits value that are relative to the range in use).

Go Up