As I could not find any information on this, here is the result of my attempt to reverse engineer the RS-232 protocol the Hapé MI-23 MK3 uses. An example implementation can be found on GitHub.
Serial Port Configuration
The serial port has to be configured as following. Also make sure any special character handling is disabled.
Property | Value |
---|---|
Baud | 2400 |
Data bits | 8 |
Stop bits | 1 |
Parity | None |
Some example code in Python:
import termios, tty # open serial port fd = open('/dev/ttyS0', 'rb') # set raw mode (sets data/stop bits and parity as well) tty.setraw(fd) # set baud rate attr = termios.tcgetattr(f) attr[4] = termios.B2400 # input speed attr[5] = termios.B2400 # output speed (not used, but seems # to be the only one that actually # changes the speed) termios.tcsetattr(f, termios.TCSAFLUSH, attr) |
Protocol
The protocol consists of sending measurements as sequences of 14 bytes, with bits that represent mostly elements on the display. In practice, you might also see an additional byte when RS-232 is switched on (0xf8 for me). As far as I can tell this is not part of the protocol but external "noise".
Each byte in the measurement byte sequence uses the high nibble to indicate the index in the sequence and the low nibble to send actual data. The indices range from 1 to 14. The bytes are always in order. For example:
13 20 30 47 5d 6e 78 80 90 a0 b2 c4 d0 e1 |
Although each "data" bit in the low nibbles can be considered a individual flag, the data in bytes 2 through 9 can be considered to be four groups of two bytes that each describe a single digit of the measured value. As such, I will handle them separately.
Below are the meanings of the data bits for bytes 1 and 10 to 14. Elements in yellow are guesses, elements in red are currently unknown to me.
Index | Data bit | Display symbol | Meaning |
---|---|---|---|
1 | 8 | AC | AC measurement |
1 | 4 | DC measurement | |
1 | 2 | Auto | Auto ranging enabled |
1 | 1 | RS232 | RS-232 output enabled |
a | 8 | μ | Unit prefix 'micro' (10-6) |
a | 4 | n | Unit prefix 'nano' (10-9) |
a | 2 | k | Unit prefix 'kilo' (103) |
a | 1 | (diode) | Diode mode enabled |
b | 8 | m | Unit prefix 'milli' (10-3) |
b | 4 | % | Duty cycle percentage |
b | 2 | M | Unit prefix 'mega' (106) |
b | 1 | (buzzer) | Continuity test enabled |
c | 8 | F | Unit 'farad' |
c | 4 | Ω | Unit 'ohm' |
c | 2 | (triangle) | Relative measurement enabled |
c | 1 | ||
d | 8 | A | Unit 'ampere' |
d | 4 | V | Unit 'volt' |
d | 2 | Hz | Unit 'hertz' |
d | 1 | ||
e | 8 | ||
e | 4 | °C | Unit 'degree Celsius' |
e | 2 | ||
e | 1 | Only off when measuring temperature. |
The remaining unknown bits correspond most likely to the 'hold', battery, 'hfe' and 'k rpm' segments on the display. You can see them displayed shortly when you turn on the device.
For the digits, the data consist of 1+7 bits. The most significant bit indicates either the minus sign, for the first digit (bytes 2 and 3), or the preceding period, for the other three digits. The remaining 7 bits correspond to the 7 segments of the digit on the display. If we label these bits 'abcdefg' (from most significant to least), the relation with the segments is as follows:
c | ||
b | g | |
f | ||
a | e | |
d |
The following digits/symbols are used:
Bits | Hex | Symbol |
---|---|---|
000 0000 | 00 | (space) |
111 1101 | 7d | 0 |
000 0101 | 05 | 1 |
101 1011 | 5b | 2 |
001 1111 | 1f | 3 |
010 0111 | 27 | 4 |
011 1110 | 3e | 5 |
111 1110 | 7e | 6 |
001 0101 | 15 | 7 |
111 1111 | 7f | 8 |
011 1111 | 3f | 9 |
110 1000 | 68 | L |
To illustrate, the value -12.34 would be represented as follows, including high nibbles:
28 35 45 5b 69 7f 82 97 |
Putting everything together, you can deduce that the first example above corresponds to ' 0L MΩ' with 'auto' and 'rs232' on.
Note that when switching modes on the device, sometimes conflicting bits are set that are the result of mixing of the old and new state. This resolves itself with the next sequence.