Skip to content

Instantly share code, notes, and snippets.

@cellularmitosis
Last active October 18, 2023 09:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cellularmitosis/1582236f226e9d98075a0c971eb4168c to your computer and use it in GitHub Desktop.
Save cellularmitosis/1582236f226e9d98075a0c971eb4168c to your computer and use it in GitHub Desktop.
Arduino LCD display for HP 34401A

Blog 2022/8/7

<- previous | index | next ->

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