Skip to content




Other »

Enable the RS232 communication on a Digital Multimeter

Some Digital Multimeters use an IC which has RS232 ouput but that feature is not enabled in the hardware design. However, it is easy to add some hardware componemts to fully export the RS232 port, mostly with an opto and some resistors.

Last update: 2022-07-30


FS9922 DMM Decoder

DMM with log function#

We usually do not see a DMM can send data to computer, but they actually has some models doing that. You can refer to the list from sigrok - an opensource signal analysis software, so you can find some popular names:

  • Agilent DMM with RS232
  • Brymen with RS232/ USB
  • Fluke with RS232
  • Metrawatt wth RS232/ USB
  • UNI-T with RS232/ USB/ BLE

My DMM is Twintex TM287 (3 ⅚ digit True RMS multimeter, 6000 counts with Analog bar), which uses FS9922-DMM4 IC from Fortune Semiconductor Corp., This IC is also used in the DMM UNI-T UT61D. The DMM UNI-T UT61D comes with RS232 function, with a PC applicatiion to show and log mesurated values; however, Twintex doesn’t support it.

FS9922-DMM4 IC

RS232 feature#

Checking the FS9922-DMM4 datasheet, there actually is pin for RS232 ouput named TXD.

RS232 output pin TXD


And the instruction to enable RS232 mode by long pressing the REL button.

Enable RS232 output


Finally, it shows a schematic which connects RS232 TXD to a LED for isolated optical communication method.

RS232 TXD ouput component


The ioslated optical method can be done by using an opto PS2701 as below:

Use opto for RS232 TX


And on the DB9 header, the current flows from pin 2 (RX - Receive Data) to pin 4 (DTR - Data Terminal Ready)

RS232 DB9 pinout

Modify the hardware#


Firsly, wire TXD pin and VDD pin from the IC. VDD wire can be connected to any VDD point.

Wire TXD pin


Then, wire an opto PS2701 with 1K resister between VDD and TXD pins.

After that, wire DTR and RX pin from an USB-to-TTL converter:

Add Opto to RS232 TXD line


Here is the USB-to-TTL converter:

Connect to USB-TTL converter


Now, you can read RS232 messages in text mode:

RS232 output

Decode data packet#

The RS232 data packet is defined in 14-buyte messages.

RS232 data message

The sign and digits are sent as ASCII characters. Other details, such as AC/DC, unit, mode can be decoded from the RS232 data bytes. Check the FS9922-DMM4 datasheet for message details.

You can find a simple python decoder and draw a graph like this:

Decode RS232 message and draw a graph


Decode RS232 messages:

fs9922_dmm4.py
import serial

##########
def parse(data):
    try:
        # print(data.hex(' '), end=' >> ')

        sign = 1 if data[0]==0x2b else -1

        digit1 = data[1]-0x30
        digit2 = data[2]-0x30
        digit3 = data[3]-0x30
        digit4 = data[4]-0x30

        decimal = 1
        match data[6]:
            case 0x30:
                decimal = 1
            case 0x31:
                decimal = 1000
            case 0x32:
                decimal = 100
            case 0x34:
                decimal = 10

        if data[1] == 0x3f:
            if sign == 1:
                value = float('inf')
            else:
                value = float('-inf')
        else:
            value = sign * (digit1*1000 + digit2*100 + digit3*10 + digit4) / decimal

        range = 'auto'  if data[7] & (1 << 5) else 'man'
        dc    = 'DC'    if data[7] & (1 << 4) else ''
        ac    = 'AC'    if data[7] & (1 << 3) else ''
        rel   = 'REL'   if data[7] & (1 << 2) else ''
        hold  = 'HOLD'  if data[7] & (1 << 1) else ''
        bpn   = 'BPN'   if data[7] & (1 << 0) else ''

        u     = 'u'     if data[9] & (1 << 7) else ''
        m     = 'm'     if data[9] & (1 << 6) else ''
        k     = 'k'     if data[9] & (1 << 5) else ''
        M     = 'M'     if data[9] & (1 << 4) else ''
        diode = 'D'     if data[9] & (1 << 2) else ''
        duty  = '%'     if data[9] & (1 << 1) else ''

        vol   = 'V'     if data[10] & (1 << 7) else ''
        amp   = 'A'     if data[10] & (1 << 6) else ''
        ohm   = 'Ω'     if data[10] & (1 << 5) else ''
        hz    = 'Hz'    if data[10] & (1 << 3) else ''
        far   = 'F'     if data[10] & (1 << 2) else ''
        tC    = '°C'    if data[10] & (1 << 1) else ''
        tF    = '°F'    if data[10] & (1 << 0) else ''

    except:
        value = float('inf')

    else:
        print(f'{range} {dc}{ac} {value:+} {u}{m}{k}{M}{vol}{amp}{ohm}{far}{hz}{duty}{tC}{tF}')
        return value


##########
if __name__ == '__main__':
    # open and read
    with serial.Serial('COM5', 2400) as dmm:
        while True:
            try:
                line = dmm.readline()
                print(parse(line))
            except KeyboardInterrupt:
                break

Show data in a graph using Animation in the MatPlotLib package:

showdata.py
import io
import time
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.animation
import serial

from fs9922_dmm4 import parse

PLOT_LIMIT = 60
y_min = -1
y_max =  1

fig, ax = plt.subplots(1, 1, figsize=(10,8))
ax.set_title("Digital Multimeter")
ax.set_xlabel("second")
ax.set_ylabel("value")
ax.set_ylim([y_min, y_max])


##########
def static_vars(**kwargs):
    def decorate(func):
        for k in kwargs:
            setattr(func, k, kwargs[k])
        return func
    return decorate


##########
def get_data(line):
    return parse(line)


##########
@static_vars(counter=0)
def animate(i, xs, ys, serial, limit=PLOT_LIMIT):
    global y_min
    global y_max

    # grab the data
    try:
        # next second
        animate.counter += 1
        line = serial.readline()
        data = get_data(line)

        if data < y_min:
            y_min = data - 0.5
        if data > y_max:
            y_max = data + 0.5

        # Add x and y to lists
        xs.append(animate.counter)
        ys.append(data)

        # Trim xs, ys
        xs = xs[-limit:]
        ys = ys[-limit:]

    except ValueError:
        print(f"W: {time.time()} :: EXCEPTION!")

    else:
        # Draw x and y lists
        ax.clear()
        ax.set_ylim([y_min, y_max])
        ax.plot(xs, ys)

##########
if __name__ == '__main__':
    # open and read
    with serial.Serial('COM5', 2400) as dmm:
        anim = mpl.animation.FuncAnimation(fig, animate, fargs=([None], [None], dmm))
        plt.show()
        plt.close()

Comments