Skip to content

Instantly share code, notes, and snippets.

@dreamcat4
Forked from cellularmitosis/README.md
Created August 7, 2022 13:30
Show Gist options
  • Save dreamcat4/51177e4b7601e2108350e13b58820343 to your computer and use it in GitHub Desktop.
Save dreamcat4/51177e4b7601e2108350e13b58820343 to your computer and use it in GitHub Desktop.
Arduino LCD display for HP 34401A

Arduino LCD display for HP 34401A

Here is an Arduino sketch which reads values from an HP 34401A over a serial connection and displays them on an LCD screen.

See also the eevblog thread.

IMG_1551

IMG_1555

Buy why tho?

Whereas the 34401A only displays 6 digits via its front-panel display, it makes a 7th digit available via the serial port.

This sketch makes that 7th digit visible via the LCD display.

RS232 to TTL board

This project uses an RS232-to-TTL adapter, specifically this one from eBay:

IMG_1556

Screen Shot 2022-08-07 at 6 59 42 AM

The HP 34401A requires that the DSR pin be enabled before it will transmit data.

To do this, solder a pull-up resistor (e.g. 10k) from VCC to DB9 pin 6:

IMG_1557

IMG_1558

Caveats

This sketch is too slow to handle some of the faster sample rates (e.g. "fast 4-digit" mode) of the 34401A.

However, the whole point of using this sketch is to get access to the 7th digit, so you'd likely be using fast or slow 6-digit mode, which this sketch handles correctly.

Formatting tests:

IMG_1550

IMG_1549

IMG_1548

IMG_1547

IMG_1546

IMG_1544

IMG_1543

// hp34401a-lcd.ino: Arduino sketch to display HP 34401A readings on a 16x2 LCD
// as well as send them out the serial port.
// Copyright 2022 Jason Pepas.
// Released under the terms of the MIT License.
// See https://opensource.org/licenses/MIT.
// Setup:
// First, set your 34401A to "talk only" mode:
// Menu -> I/O Menu -> HP-IB Addr -> 31.
// Next, prepare a RS232-to-TTL adapter by soldering a pull-up resistor from
// the DB9 pin 6 (the DSR pin) to VCC (5V).
// See https://gist.github.com/cellularmitosis/1582236f226e9d98075a0c971eb4168c for soldering details.
// Thanks to:
// https://www.eevblog.com/forum/testgear/external-display-for-agilent-34401a-(or-any-dmm-with-rs232-output-stream)/msg326470/#msg326470
// "Set DB9 pin 6 DSR high 5V"
// Pins:
#define LED_pin (13) // The onboard Arduino LED.
// The RS232-to-TTL adapter will have four pins:
// Pin 1: GND, connect to Arduino GND.
// Pin 2: RX, connect to hp_rx_pin.
// Pin 3: TX, connect to hp_tx_pin.
// Pin 4: VCC, connect to Arduino 5V.
#define hp_rx_pin (8)
#define hp_tx_pin (9)
// A standard 16x2 "1602" LCD module.
// Pin 1: VSS, connect to Arduino GND.
// Pin 2: VDD, connect to Arduino 5V.
// Pin 3: VO (contrast):
// Create a 0.6V reference by connecting Arduino 5V or 3.3V to a 10k resistor
// to a diode to GND. Connect VO to the 0.6V point of the reference.
// Pin 4: RS, connect to LCD_RS_pin.
// Pin 5: RW, connect to Arduino GND.
// Pin 6: E, connect to LCD_EN_pin.
// Pin 11: D4, connect to LCD_D4_pin.
// Pin 11: D5, connect to LCD_D5_pin.
// Pin 11: D6, connect to LCD_D6_pin.
// Pin 11: D7, connect to LCD_D7_pin.
// Pin 12: A (backlight LED anode):
// Some 1602 boards need a current limiting resistor and some don't.
// Connect a 220R from Arduino 5V to the A pin. If it is very dim, try
// omitting the resistor.
// Pin 13: K (backlight LED cathode), connect to Arduino GND.
#define LCD_RS_pin (3)
#define LCD_EN_pin (2)
#define LCD_D4_pin (4)
#define LCD_D5_pin (5)
#define LCD_D6_pin (6)
#define LCD_D7_pin (7)
#include <LiquidCrystal.h>
LiquidCrystal lcd(LCD_RS_pin, LCD_EN_pin, LCD_D4_pin, LCD_D5_pin, LCD_D6_pin, LCD_D7_pin);
#include <SoftwareSerial.h>
SoftwareSerial hp_serial(hp_rx_pin, hp_tx_pin);
void setup() {
pinMode(LED_pin, OUTPUT);
lcd.begin(16, 2);
Serial.begin(9600);
hp_serial.begin(9600);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("HP 34401A");
delay(1000);
}
// Data will stream from the 34401A in the following format:
// -9.34000000E-07\r\n
// +2.24900000E-06\r\n
#define BUF_LEN (17) // e.g. '+2.24900000E-06\r\n'
char buf[BUF_LEN+1];
void loop() {
// Reset to read the next value.
memset(buf, '\0', BUF_LEN+1);
int chars_read = 0;
while (true) {
// Spin until there is a char available to read.
if (hp_serial.available() == 0) {
continue;
}
// Read one char.
char ch = hp_serial.read();
// Handle the end of the line.
if (ch == '\r' || ch == '\n') {
// The line ending is '\r\n'. Throw away the '\n'.
if (chars_read == 0) {
break;
}
// Convert the line to a float.
float f = atof(buf);
// Determine the exponent value, e.g. 'E-02' == 2.
int exponent = (buf[14] - '0') + (10 * (buf[13] - '0'));
if (buf[12] == '-') {
exponent = -exponent;
}
// Format the value in non-scientific notation.
char formatted[12+1]; // e.g. '-123456789.1', '-0.000000001'
int dot_index = -1;
// -1.0E-3 = -0.001
// -1.0E-2 = -0.01
// -1.0E-1 = -0.1
// -1.0E0 = -1.0
// -1.0E1 = -10.0
// -1.0E2 = -100.0
// -1.0E3 = -1000.0
if (exponent < 1) {
dot_index = 2;
} else {
dot_index = 2 + exponent;
}
formatted[0] = buf[0]; // the leading '+' or '-'.
int in_index = 1;
int out_index = 1;
int trailing_zeros = 0;
if (exponent < -1) {
trailing_zeros = (-exponent) - 1; // e.g. if the exponent is -5, there will be 4 trailing zeros.
}
while (in_index < (11 /* the 'E' */ - trailing_zeros)) {
if (in_index == 2 /* the '.' */) {
in_index += 1;
continue;
} else if (out_index == dot_index) {
formatted[out_index] = '.';
out_index += 1;
continue;
} else if (exponent < 0 && out_index < (-exponent)+2) {
formatted[out_index] = '0'; // leading zero's, e.g. 0.001.
out_index += 1;
continue;
} else {
formatted[out_index] = buf[in_index];
in_index += 1;
out_index += 1;
continue;
}
}
formatted[out_index] = '\0';
// Format the value in non-scientific notation, with commas and underscores.
char formatted2[14+1]; // e.g. '-123,456,789.1', '-0.000_000_001'
int comma1_index = -1;
int comma2_index = -1;
int under1_index = -1;
int under2_index = -1;
if (exponent >= 6) { // at or above 6 we have two commas and no unders.
// -1.0E7 = -10,000,000.0
// -1.0E6 = -1,000,000.0
dot_index += 2;
comma1_index = exponent - 4;
comma2_index = exponent;
} else if (exponent == 4 || exponent == 5) { // for 4 and 5 we have one comma and no unders.
// -1.0E+6 = -1,234,567.8
// -1.0E+5 = -123,456.78
// -1.0E+4 = -12,345.678
// -1.0E+3 = -1,234.567_8
dot_index += 1;
comma1_index = exponent - 1;
} else if (exponent == 3) { // for 3 we have one comma and one under.
// -1.0E+4 = -12,345.678
// -1.0E+3 = -1,234.567_8
// -1.0E+2 = -123.456_78
dot_index += 1;
under1_index = 10;
} else if (exponent == 1 || exponent == 2) { // for 2 and 1 we have no commas and one under.
// -1.0E+3 = -1,234.567_8
// -1.0E+2 = -123.456_78
// -1.0E+1 = -12.345_678
// -1.0E+0 = -1.234_567_8
under1_index = exponent + 6;
} else if (exponent <= 0) { // at or below zero, we no commas and two unders.
// -1.0E+1 = -12.345_678
// -1.0E+0 = -1.234_567_8
// -1.0E-1 = -0.123_456_78
// -1.0E-2 = -0.012_345_678
// -1.0E-3 = -0.001
// -1.0E-4 = -0.000_1
// -1.0E-5 = -0.000_01
under1_index = 6;
under2_index = 10;
}
formatted2[0] = buf[0]; // the leading '+' or '-'.
in_index = 1;
out_index = 1;
int copied_digits = 0;
while (in_index < (11 /* the 'E' */ - trailing_zeros)) {
if (in_index == 2 /* the '.' */) {
in_index += 1;
continue;
} else if (out_index == dot_index) {
formatted2[out_index] = '.';
out_index += 1;
continue;
} else if (out_index == comma1_index || out_index == comma2_index) {
formatted2[out_index] = ',';
out_index += 1;
continue;
} else if (out_index == under1_index || out_index == under2_index) {
formatted2[out_index] = ',';
out_index += 1;
continue;
} else if (exponent < 0 && out_index < (-exponent)+2) {
formatted2[out_index] = '0'; // leading zero's, e.g. 0.001.
out_index += 1;
continue;
} else if (exponent <= -5 && out_index < (-exponent)+3) {
formatted2[out_index] = '0'; // leading zero's, e.g. 0.001.
out_index += 1;
continue;
} else {
formatted2[out_index] = buf[in_index];
in_index += 1;
out_index += 1;
copied_digits += 1;
if (copied_digits == 8) {
break;
}
continue;
}
}
formatted2[out_index] = '\0';
// Send the formatted value out the (hardware) serial port.
Serial.print(formatted);
Serial.print("\n");
digitalWrite(LED_pin, LOW);
// Print the formatted value on the second line of the LCD.
lcd.setCursor(0, 1);
lcd.print(formatted2);
break;
}
// Accumulate chars into the buffer and echo them to the LCD.
digitalWrite(LED_pin, HIGH);
buf[chars_read] = ch;
if (chars_read == 0) {
lcd.clear();
}
lcd.setCursor(chars_read, 0);
lcd.print(ch);
chars_read += 1;
continue;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment