The Tenma 72-7735 is a lower end DMM that comes with quite a few handy features including an opto-isolated serial output. This serial communication is over a cable with a male db-9 rs-232 serial connector on one end and a connector housing a photo-diode that fits into the multimeter on the other end. Here is a picture of the cable:
Software is provided by Tenma that offers a gui with that can do things like datalogging, generate graphs and show real time data. The problem is that this program only works on windows and my computer doesn’t have a serial port. Also it would be nice if it was possible to read this serial data using some kind of microcontroller based embedded system and do something cool with it.
First step was to take apart the photodiode housing:
The original idea was to cut off the db-9 connector on the other end of the cable and hook up the wires to the correct voltages to get serial data out. This turned out to be problematic due to that fact that rs232 voltages are bi-polar. See the image of the reverse engineered circuit below:
These wire were attached to the following rs232 pins:
DCD – yellow
RxD – orange
Txd – white
DTR – brown
RTS – green
This particular cable was missing several components from the internal PCB. It only seemed to have the parts needed to receive data, not send it. The TxD (white) wire is soldered to the PCB but doesn’t seem to be connected to anything. It turns out that it is possible to power very low current (roughly 10mA max) devices over rs-232, some older computer mice would have been powered this way. This is usually done using the RTS and DTR lines to generate +5V and then using the TxD line as the negative voltage. Not wanting to go messing about with negative voltages I tried to get the circuit to work with just ttl voltage levels but it didn’t work out. In the end I just de-soldered the photo-diode from the PCB and made a much simpler circuit that easily works with 5v logic levels. The quick and easy circuit looks like this:
This serial data is sent to a computer via a pl2303 based usb to serial converter.
Here is a picture of the new and improved circuit stuffed inside the housing:
Picture of the output from this circuit on an oscilloscope below. It looks a bit non-square but it didn’t seem to affect the data being read correctly:
All that is left now is to read the serial data and do cool things with it. Only problem is the serial protocol is fairly poorly documented. A protocol outline can be found here. Despite the documentation being pretty confusing, the protocol is extremely simple.The serial data sent out is the LCD table which tells us which parts of the LCD are on and which are not. This makes it slightly more difficult to decode the data on the other end than if it just sent values of voltage or current but it’s not that big of a deal. The data is sent out in 14 byte packets ( this means 14 bytes, short pause then another 14 bytes etc). The upper nibble (upper 4 bits) of each byte is the bytes location within the packet. EG the first byte in a packet will be 0001XXXX, the second one 0010XXXX etc. The XXXX’s or the lower nibble of each byte is what we are interested in. There is a table provided in the datasheet that outlines what these lower 4 bits mean.
This table is so unnecessarily confusing. What does COM 1-4 Mean? I still have no idea. The way to look at it is just ignore columns 1-4, just pay attention to the seg colummns (seg1 – seg14). There are 14 seg columns and 14 bytes in a packet. This is because each bytes lower nibble corresponds to the lcd sections in one of those columns. If for example the first byte in a packet was 00010111, the upper nibble is 0001 which means it refers to column seg1. The lower nibble is 0111, each bit of this nibble tells us if that particular symbol is currently showing on the LCD. 1 means on and 0 means off. So for example in this case 0111 means the following
0 – AC OFF
1 – Auto ON
1 – DC ON
1 – RS232 ON
This process repeats for the full 14 byte packet and by knowing which parts of the LCD are on, you can then work out what numbers are being displayed on the screen and so on. See below for a python script I wrote to do this (click to expand):
import serial import time import binascii ser = serial.Serial( port='/dev/ttyUSB0', baudrate=2400, timeout = 0.1, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS ) ser.close() ser.open() ser.flush() hex_vals =  temp_str = '' bin_vals =  dmm_data = '' lower_nibbles =  for i in range (0, 14): # make lists to store hex and binary values hex_vals.append('0') bin_vals.append(0) lower_nibbles.append(0) def get_lower_nibbles(bin_vals): # only keep the lower part of nibble for i in range(0, len(bin_vals)): temp_str = str(bin_vals[i]) lower_nibbles[i] = str(temp_str[4:8]) return(lower_nibbles) a= b= c= d= digit = 0 for h in range(8): # make a list for each digit to record which parts of seven segment are on or off a.append('0') b.append('0') c.append('0') d.append('0') def lcd_get_num(lcd_array): ## each digit corresponds to certain parts of seven segment display being on digit = 0 if lcd_array == '1010000' : digit = 1 if lcd_array =='1101101' : digit = 2 if lcd_array == '1111001' : digit = 3 if lcd_array == '0110011' : digit = 4 if lcd_array == '1011011' : digit = 5 if lcd_array == '1011111' : digit = 6 if lcd_array == '1110000' : digit = 7 if lcd_array == '1111111' : digit = 8 if lcd_array == '1111011' : digit = 9 if lcd_array == '1111110' : digit = 0 return str(digit) def decode_data(lower_nibbles): #this function works out what numbers are being displated based on for i in range(1, len(lower_nibbles)): # which parts of each seven segment digit are turned on temp_reg = lower_nibbles[i] # print temp_reg # print len(a) if (i==1): ## first digit #print temp_reg a = temp_reg a = temp_reg a = temp_reg if (i==2): a = temp_reg a = temp_reg a = temp_reg a = temp_reg if (i==3): b = temp_reg b = temp_reg b = temp_reg if (i==4): b = temp_reg b = temp_reg b = temp_reg b = temp_reg if (i==5): c = temp_reg c = temp_reg c = temp_reg if (i==6): c = temp_reg c = temp_reg c = temp_reg c = temp_reg if (i==7): d = temp_reg d = temp_reg d = temp_reg if (i==8): d = temp_reg d = temp_reg d = temp_reg d = temp_reg a.pop(0) b.pop(0) c.pop(0) d.pop(0) achar = ''.join(a) bchar = ''.join(b) cchar = ''.join(c) dchar = ''.join(d) a.append('0') b.append('0') c.append('0') # this terrible piece of code would probably make d.append('0') # Guido van Rossum cry d1 = lcd_get_num(achar) d2 = lcd_get_num(bchar) d3 = lcd_get_num(cchar) d4 = lcd_get_num(dchar) print d1+d2+d3+d4 #print numbers displayed on LCD screen return(achar, bchar, cchar, dchar) dmm_data = "" while True: dmm_data = "" ser.flush() while dmm_data == "": #wait for a packet dmm_data = str(binascii.hexlify(ser.read(14))) g = 0 # concert hex values into binary for i in range(0, len(dmm_data), 2): bin_vals[g] = str( bin(int(dmm_data[i:i+2], 16))[2:].zfill(8)) g=g+1 #print bin_vals get_lower_nibbles(bin_vals) # only interested in lower nibble of each byte #print lower_nibbles decode_data(lower_nibbles) # from this data work out what numbers are displayed on screen time.sleep(0.5)
The output from the Python script at the moment is just the numbers currently being displayed on the multimeter. This is a work in progress, data logging with a microcontroller is something to try out in the future.