COMMUNICATING WITH THE HP 59309A HP-IB DIGITAL CLOCK
The Hewlett-Packard 59309A digital clock, introduced in 1974, is able to communicate via an HP-IB (Hewlett-Packard Interface Bus), a precursor to the GPIB (General Purpose Interface Bus), defined by the IEEE-488 standard.

These days HP-IB is mostly relegated to test instruments, so HP-IB interfaces for modern computers are not exactly common. I recently purchased an inexpensive (about $40 US) HP-IB (GPIB) to USB interface from LQ Electronics called the UG Simple. The product consists of a single cable with a USB connector at one end and a GPIB connector at the other end, along with an optical disk containing driver software.

The LQ driver provides two functions:

  • Gwrite( address, command ) to send command to GPIB device at address
  • answer = Gread( address ) to read answer from GPIB device at address

This code compiles in Microsoft's free Visual Studio Community 2019 and produces a Windows console application that demonstrates reading and writing commands from and to the clock using the LQ Electronics UG Simple interface.

59309 Back Requirements:

  • Set clock switches A6 and A7 up (allows the clock to be addressed).
  • Set the HPIB_ADDRESS value to the bus address of the clock (clock switches A1 through A5).
  • Confirm the location of the .dll file provided by LQ Electronics, used in the Loaddll function.


// LQ_59309.cpp
// Read and set a Hewlett-Packard HP 59309A clock via LQ UGSimple interface
// Last revised 27 April 2019
//

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include <windows.h>
#include <winuser.h>

#define HPIB_ADDRESS	1


int	day_counts[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };


//Define loading function pointers
typedef	int (*gwrite1)(int address, char* scpi);
typedef	char* (*gread1)(int address);

//point the function pointer to specific function
gwrite1	Gwrite;
gread1	Gread;


void	fatal_exit(const char* s)
{
	printf("Fatal: %s\n", s);
	exit(-1);
}


void Loaddll(void)
{
	HINSTANCE	hInst = NULL;


	hInst = LoadLibrary(TEXT("C:\\Program Files (x86)\\LQElectronics\\UGSimple\\UGSimpleAPI\\LQUGSimple_c.dll"));
	
	if (hInst == NULL)
	{
		fatal_exit( "Error loading UG DLL" );
	}
	
	Gwrite = (gwrite1)GetProcAddress(hInst, "Gwrite");
	Gread = (gread1)GetProcAddress(hInst, "Gread");
}


int main()
{
	time_t	now;
	struct tm tm;

	int	clock_address;
	char	command[128];
	int	result;
	int	i;
	char	*answer = new char[500];
	int	month_number;


	Loaddll();

	now = time(0);
	localtime_s(&tm, &now);

	printf("Now: %4d-%02d-%02d %02d:%02d:%02d\n",
		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
		tm.tm_hour, tm.tm_min, tm.tm_sec);


	clock_address = HPIB_ADDRESS;

	// Request the current clock values

	command[0] = 'C';
	command[1] = '?';
	command[2] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		exit(-2);

	answer = Gread(clock_address);
	if (answer)
	{
		printf("Answer (%d): ", (int)strlen(answer));

		for (i = 0; i < (int)strlen(answer); i++)
			if ((answer[i] >= ' ') && (answer[i] <= 128))
				printf("%c", answer[i]);
			else
				printf("\\%02X", answer[i]);
		printf("\n");
	}
	else
	{
		printf("No answer.\n");
	}


	// Set the time by stopping the clock (P), resetting the clock (R),
	// then moving ahead the proper number of seconds (S), minutes (M),
	// hours (H) and days (D),
	// then start the clock (T)

	command[0] = 'P';
	command[1] = 'R';
	command[2] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		fatal_exit("Stop Clock");


	// Adjust seconds

	for (i = 0; i < tm.tm_sec; i++)
		command[i] = 'S';
	command[i] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		fatal_exit("Set Seconds");


	// Adjust minutes

	for (i = 0; i < tm.tm_min; i++)
		command[i] = 'M';
	command[i] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		fatal_exit("Set Minutes");


	// Set hours

	for (i = 0; i < tm.tm_hour; i++)
		command[i] = 'H';
	command[i] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		fatal_exit("Set Hours");


	// Set Days

	for (i = 0; i < tm.tm_mday - 1; i++)
		command[i] = 'D';
	command[i] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		fatal_exit("Set Days");


	// Set months by moving Day counter forward for each month

	for (month_number = 0; month_number < tm.tm_mon; month_number++)
	{
		for (i = 0; i < day_counts[month_number]; i++)
			command[i] = 'D';
		command[i] = 0x00;

		result = Gwrite(clock_address, command);
		if (result < 0)
			fatal_exit("Set Months");
	}


	// Start the clock

	command[0] = 'T';
	command[1] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		fatal_exit("Start Clock");


	// Clear the bus

	command[0] = '?';
	command[1] = 0x00;

	result = Gwrite(clock_address, command);
	if (result < 0)
		fatal_exit("Clear Addressed");

	exit(0);
}


Comments to Dan Veeneman

Click here for the Wanted page.
Click here for the Main page.

Last updated April 27, 2019