HP-97 and HP-82143A printers
#1

Hi. I had perhaps the same type problem that Katie Wasserman had, in that the yellow colored printer gear was damaged and missing some teeth. I took the thermal printer assembly out of a HP-82143A that is used for the HP-41C series. It seemed that the HP-97 and HP82143A printers were very similar, and the unit fit right into the HP-97. These printers are also alot more plentiful than parts HP-97's, but they do not use the drive gears, but instead use a rubber band to move the print mechanism. After I installed the HP-82143A printer into the HP-97, everything seemed to work except that it did not print. It tried to print however(print arm moved etc..).I am not sure why it didn't print, but suspected that perhaps the print head is slightly different, or the chip drivers were different. I never tried exchanging the HP-97 print head with the HP-82143A print head, because my HP-97 head was damaged. Has anyone out there ever tried this swap before and had any success?

#2

I had the same idea as Erik but didn't have a HP82143A around to try. I did think about using the printing mechanism from a 82240A (or B) which takes the same size paper as the 97 but would need to be adapted to mount in the space on the 97, also the interface is entirely different. I'm considering using a small microprocessor (a PIC most likely) to read the print head driver output (and motor drive output) and translate these into the needed codes that would then be sent via IR to a 82240A/B. My guess is that this would not be too hard to do, since the 82240A/B can accept bit-column graphics (what the 97 send to the print head). The same idea would work for the other 9x machines and the 19C and 10. The one piece of information that I need, however, is the bit stream format of the IR commands that the 82240A/B need. (I'm not wild about trying to reverse engineer these.) Does anyone have these specs?

#3

The HP 82440 IR protocol is documented in a 1986 HP Journal issue. It's either the same issue with the HP-18C articles,
or the following one.

A specification document was reportedly available from HP Corvallis years ago, but I've never seen it.

Several people have reverse-engineered it, apparently without realizing that it was documented in HP Journal. However both of the reverse-engineering efforts I've seen (including one published in Circuit Cellar Ink) got details wrong, and in fact made it out to be more complex than it really is.

I've been considering designing PIC microcontroller based hacks to add printing output to HP calculators that didn't have it, such as the HP-67. It never occurred to me that this might be useful to people with broken HP-97s.

#4

I looked it up, the issue of the HP Journal with the 82440 printer protocol information is October 1987.

#5

I had it all the time and didn't realise it.

Thanks.

#6

Does anyone have the IR printer article readily available for email or fax. I don't have the 10/87 issue of HPJ around. (Of course, I could order it from one of those services that the HP Journal site points you too, but...)

#7

What information do you need? I can transacribe the essential bits for you if you like.

#8

I need to know enough about the bit patterns to generate them and control the IR LED hooked into the PIC. I also need to know the carrier frequency that the IR receiver uses (probably 40KHz). Steve, I appreciate your offer to transcribe the info, but it's going to be a lot. If you have a scanned copy of the article that you could email, that would be great, if not I can get it from one of the journal reprint services. Perhaps a scan of this info could be added to the other HPJ articles on the CD ROM set so that it would be available to everyone.

#9

Ahhh, it's simple enough!

Basics

The carrier frequency is 32.768Khz. (for the HP-18C)

The carrier has an even mark and space of approximately 15.26uS

The carrier is modulated by a square wave with a fixed mark, but variable space. Thus the information is carried by the gaps between pulses, not the pulses themselves!

Data Encoding

The data is encoded bit by bit. Bit times are fixed (28 pulses of the carrier, or approx 854.5uS). This bit time is broken into two halves.

* A 1 bit is defined as a burst in the first half of the bit time, and no pulse in the second half

* A 0 bit is defined as a burst in the second half, but not in the first half.

* A start bit is defined as a burst at the begining of three successive half bit times (an otherwise illegal combination)

Note that this makes a start bit 50% longer than a normal bit.

An Example

If I were drawing things, it would look like this:

(this is a start bit followed by a 1 and a 0.) Note that you don't start counting until you see the first rising edge. To make things easier, I only show 4 pulses per 1/4 bit time, rather than the 6 to 8 that you may see in practice.

Also note that while HP talks of 1/2 bit times, you can usefully think in terms of 1/4 bit times with the even 1/4's ALWAYS in a space, and the mark only ever occuring in one of the odd 1/4's.

___||||____||||____||||____||||________________________||||____

To break that up:

___
is some amount of space between characters

||||____||||____||||____
is three half bit times with pulses in their first half. (and is thus a start bit)

||||____________
is two half bit times with pulses in the first half bit time (a 1)

________||||____
is two half bit times with pulses in the second half bit time (a 0)

Data is sent in frames. Each frame consists of a start bit, 4 ECC bits, and 8 data bits.

If you look at the output of one of these IR devices on a storage scope, or via some other method, you'll notice immediatly that the frames stand out like islands of data in the sea of noise. As you look closer you'll see the groups of pulses and the spacing between them. You'll notice the three different size gaps. These are 1 unit, 3 units, and 5 units. Coding these gaps is actually one way of coding the data.

A Table to Cheat By :-)

Here is a table that some of my software uses to decode these gaps. Note that it was devises BEFORE I knew anything about how te data was decoded.

const
FrameChars : Array[0..255] of string[14] = (
'11222222222222', // 0
'11221232222221', // 1
'11213132222213', // 2
'11212322222212', // 3
'11212322222132', // 4
'11213132222131', // 5
'11221232222123', // 6
'11222222222122', // 7
'11132132221322', // 8
'11131322221321', // 9
'11123222221313', // 10
'11122232221312', // 11
'11122232221232', // 12
'11123222221231', // 13
'11131322221223', // 14
'11132132221222', // 15
'11131322213222', // 16
'11132132213221', // 17
'11122232213213', // 18
'11123222213212', // 19
'11123222213132', // 20
'11122232213131', // 21
'11132132213123', // 22
'11131322213122', // 23
'11221232212322', // 24
'11222222212321', // 25
'11212322212313', // 26
'11213132212312', // 27
'11213132212232', // 28
'11212322212231', // 29
'11222222212223', // 30
'11221232212222', // 31
'11123222132222', // 32
'11122232132221', // 33
'11132132132213', // 34
'11131322132212', // 35
'11131322132132', // 36
'11132132132131', // 37
'11122232132123', // 38
'11123222132122', // 39
'11213132131322', // 40
'11212322131321', // 41
'11222222131313', // 42
'11221232131312', // 43
'11221232131232', // 44
'11222222131231', // 45
'11212322131223', // 46
'11213132131222', // 47
'11212322123222', // 48
'11213132123221', // 49
'11221232123213', // 50
'11222222123212', // 51
'11222222123132', // 52
'11221232123131', // 53
'11213132123123', // 54
'11212322123122', // 55
'11122232122322', // 56
'11123222122321', // 57
'11131322122313', // 58
'11132132122312', // 59
'11132132122232', // 60
'11131322122231', // 61
'11123222122223', // 62
'11122232122222', // 63
'11122321322222', // 64
'11123131322221', // 65
'11131231322213', // 66
'11132221322212', // 67
'11132221322132', // 68
'11131231322131', // 69
'11123131322123', // 70
'11122321322122', // 71
'11212231321322', // 72
'11213221321321', // 73
'11221321321313', // 74
'11222131321312', // 75
'11222131321232', // 76
'11221321321231', // 77
'11213221321223', // 78
'11212231321222', // 79
'11213221313222', // 80
'11212231313221', // 81
'11222131313213', // 82
'11221321313212', // 83
'11221321313132', // 84
'11222131313131', // 85
'11212231313123', // 86
'11213221313122', // 87
'11123131312322', // 88
'11122321312321', // 89
'11132221312313', // 90
'11131231312312', // 91
'11131231312232', // 92
'11132221312231', // 93
'11122321312223', // 94
'11123131312222', // 95
'11221321232222', // 96
'11222131232221', // 97
'11212231232213', // 98
'11213221232212', // 99
'11213221232132', // 100
'11212231232131', // 101
'11222131232123', // 102
'11221321232122', // 103
'11131231231322', // 104
'11132221231321', // 105
'11122321231313', // 106
'11123131231312', // 107
'11123131231232', // 108
'11122321231231', // 109
'11132221231223', // 110
'11131231231222', // 111
'11132221223222', // 112
'11131231223221', // 113
'11123131223213', // 114
'11122321223212', // 115
'11122321223132', // 116
'11123131223131', // 117
'11131231223123', // 118
'11132221223122', // 119
'11222131222322', // 120
'11221321222321', // 121
'11213221222313', // 122
'11212231222312', // 123
'11212231222232', // 124
'11213221222231', // 125
'11221321222223', // 126
'11222131222222', // 127
'11212223222222', // 128
'11213213222221',
'11221313222213',
'11222123222212',
'11222123222132',
'11221313222131',
'11213213222123',
'11212223222122',
'11122313221322',
'11123123221321',
'11131223221313',
'11132213221312',
'11132213221232',
'11131223221231',
'11123123221223',
'11122313221222',
'11123123213222',
'11122313213221',
'11132213213213',
'11131223213212',
'11131223213132',
'11132213213131',
'11122313213123',
'11123123213122',
'11213213212322',
'11212223212321',
'11222123212313',
'11221313212312',
'11221313212232',
'11222123212231',
'11212223212223',
'11213213212222',
'11131223132222',
'11132213132221',
'11122313132213',
'11123123132212',
'11123123132132',
'11122313132131',
'11132213132123',
'11131223132122',
'11221313131322',
'11222123131321',
'11212223131313',
'11213213131312',
'11213213131232',
'11212223131231',
'11222123131223',
'11221313131222',
'11222123123222',
'11221313123221',
'11213213123213',
'11212223123212',
'11212223123132',
'11213213123131',
'11221313123123',
'11222123123122',
'11132213122322',
'11131223122321',
'11123123122313',
'11122313122312',
'11122313122232',
'11123123122231',
'11131223122223',
'11132213122222', // 191
'11132122322222', // 192
'11131312322221',
'11123212322213',
'11122222322212',
'11122222322132',
'11123212322131',
'11131312322123',
'11132122322122',
'11222212321322',
'11221222321321',
'11213122321313',
'11212312321312',
'11212312321232',
'11213122321231',
'11221222321223',
'11222212321222',
'11221222313222',
'11222212313221',
'11212312313213', // 210
'11213122313212',
'11213122313132',
'11212312313131',
'11222212313123',
'11221222313122',
'11131312312322',
'11132122312321',
'11122222312313',
'11123212312312',
'11123212312232', // 220
'11122222312231',
'11132122312223',
'11131312312222',
'11213122232222',
'11212312232221',
'11222212232213',
'11221222232212',
'11221222232132',
'11222212232131',
'11212312232123', // 230
'11213122232122',
'11123212231322',
'11122222231321',
'11132122231313',
'11131312231312',
'11131312231232',
'11132122231231',
'11122222231223',
'11123212231222',
'11122222223222', // 240
'11123212223221',
'11131312223213',
'11132122223212',
'11132122223132',
'11131312223131',
'11123212223123',
'11122222223122',
'11212312222322',
'11213122222321',
'11221222222313', // 250
'11222212222312',
'11222212222232',
'11221222222231',
'11213122222223',
'11212312222222' ) ; // 255

This table encodes the GAPS between modulation pulses for each character. 1 indicates a short gap, 2 the middle size gap, and 3 the long gap. Knowing that the pulses fit around each gap, that the gaps are in the proportion 1:3:5, and that you should send 7 carrier pulses at 32767Hz, this is probably enough info.

How To Cheat

So, character A is 65 and is '11123131322221'

You would send:

|_|_|_|___|_____|_|_____|_|_____|___|___|___|___|_|

Where each | is 7 carrier pulses, and each _ is a gap of equivalent size.

If you're further interested...

|_|_|_|___|_____|_|_____|_|_____|___|___|___|___|_|
SSSSSS111111110000111100001111000000000000000000001111
And yes the 1's do extend out beyond the end! This is becasue the last set of pulses occur in the first quarter of the last bit time (first half of the first half of the last bit time!!!). So even though we're encoding information in the gaps, the last gap does not need to be terminated.

SSSSSS = start bit

1111 = 1 bit

0000 = 0 bit

So it was S110101000001

1101 is the ECC
01000001 is the code for A in ASCII MSB first

Calculating the ECC

How do we get the ECC? well it's like this...

The 4 bits (call them H1, H2, H3, and H4) are calculated individually

Firstly for each bit you apply a mask (AND) to the data

the masks are:

H1 01111000

H2 11100110

H3 11010101

H4 10001011

So for the code 01000001 the resulting data for these is

H1 01000000

H2 01000000

H3 01000001

H4 00000001

Then you calculate the EVEN parity bit required for these (i.e. the bit required so that there are an EVEN number of bits. Since H1, H2, and H4 have an odd number of bits, the parity bit for these would be 1, bit for H3 it is 0.

Then you string them together (the parity bits) this gives you:

1101 which is what we found above!

These parity bits can be used to detect and correct up to two missed bits (though how you do that is well beyond what I'm prepared to go into!)

But, my software DOES decode these without resorting to calculating the ECC bits (although I may add that some time)

But you're trying to SEND this data right? So the lookup table I've given you should be all you need, unless you want to do all the hard work yourself :-)

P.S.

An easy way to play with this is to capture it with your sound card... (Oh damn, I've let out my secret). It has the advantage of handling all the timing for you, so software speed is no longer an issue. This is especially important when using an operating system that multi-tasks.

An observation about formating

You can really stuff up the formatting (especially with the pre: tag if you include a ']' in your text. Our esteemed host has allowed things like '\]' for ']' (and thus '\[' for '[') to escape the special processing as I've just discovered.

Thanks :-D

I may even write an editor to make this process somewhat faster. Formatting really takes a while to do... Anyone interested?

#10

Since you're using a PIC, it's probably far better to calculate the ECC bits. Probably more fun too.

Are you going to impliment a bidirectional interface (or even better a bidirectional interface for the HP41!)

#11

This table indicates what you should do when you receive a bit (i.e. a rising edge) after x timer ticks (a timer tick is 1/32768 sec)

Ticks      Bit      Comment

0 - 2 Ignore (too short)

3 - 7 X 2 pulses in the same bit time
(treat as a missed bit)

8 - 12 1

13 - 17 0

18 - 23 X 1 Missed bit followed by a 1

23 - 28 X 0 Missed bit followed by a 0

28 - 34 X X 1 2 mised bits then a 1

33 - 39 X X 0 2 missed bits then a 0

You can use the ECC to determine what the bits are, as long as you know which are missing (which you probably will).

What I do is to decode the gaps, then use some heuristics to determine what the gap is likely to be, then do pattern matching to determine which is the most likely. This is probably too code intensive for a PIC, bit the calculation of bits using the ECC should be OK.

Reply if you need an explanation of how to do it.

#12

Thanks very much for all that Steve! I think that it should be enough infomation for me, especailly since I'm going the other way with this. It's going to be a uni-directional interface. The idea is to read the 7-bit print head pulses from a 97 (19C or 10C) and send off a column of dots to an HP 82240 via IR. Reading the print head pulses should be relatively easy if I can sync to the clock line on the print head driver and the motor forward start line. In think that you supplied enough info to generate the IR signals and the manual for the 82240 shows the escape sequence needed to send out to print a single column of dots.

#13

Because the IR interface is one-way, there is no way to detect that the buffer is full. Thus the sender needs to send data in such a way that the buffer never overflows.

With new batteries, the IR printer can print about 2 lines per second. When the batteries are almost exhauseted, this drops as far as 1 second per line.

The buffer in the printer can contain 200 characters.

Becasue you're sending graphics, you will not be able to take advantage of the sort of buffering that calculators sending whole characters do.

The easiest algorithm is to send a line, then wait 1 second before sending another. However if you can determine how long it takes to print a line (worst case) then you may be able to take advantage of the buffer by sending several short lines at once, and then waiting until you're sure the buffer can accept more characters.

If you're sending to another device (say a PC with the IR interface) then you can go as fast as you desire :-)

#14

(a timer tick is 1/32768 sec)

Actually, in that table the described timer tick is for the timer in the 8050 microcontroller in the 82440A printer, and is longer longer than 1/32768 sec. I don't know the value offhand.

The table values are for a nominal 5 ticks per half bit time. Since a half bit time is nominally about 427 microseconds, the tick must be about 2.1 ms.

The table values are based on the sender's clock being within a certain tolerance. This is why the larger entries
in the table overlap; a fast sender's "two missed bits then a 0" case may be indistinguishable from a slow sender's "two missed bits then a 1" case, unless you've already determined the sender's clock error.

However, for *sending* the IR data, you don't need this sort of table.

#15

I still have a thermal printer for sale.....

Menno



Possibly Related Threads…
Thread Author Replies Views Last Post
  HP-97 Printer Malfunction Dan Lewis 17 5,181 11-25-2013, 10:18 AM
Last Post: Thomas Chrapkiewicz
  request M.E. pac for HP-67/97 wallet cover scan Ignacio Sánchez 0 1,046 11-06-2013, 09:36 AM
Last Post: Ignacio Sánchez Reig
  HP-67/97 Mechanical engineering PAC cover Ignacio Sánchez 0 999 10-30-2013, 04:35 AM
Last Post: Ignacio Sánchez Reig
  HP-97 Printer Troubleshooting aj04062 6 2,476 10-15-2013, 08:45 PM
Last Post: Eric Smith
  HP-97 Service Manual, newer model davorin 6 2,440 09-16-2013, 10:45 AM
Last Post: davorin
  HP-97 card reader pinch roller axle davorin 2 1,578 09-15-2013, 08:47 AM
Last Post: aj04062
  HP-97 Card Reader davorin 3 1,859 09-13-2013, 04:21 PM
Last Post: Stephan Matthys
  HP-97 Printer Head aj04062 1 1,148 09-11-2013, 09:18 PM
Last Post: Randy
  HP-97 Printer Head aj04062 0 919 09-10-2013, 09:19 PM
Last Post: aj04062
  HP-97 thermal head movement davorin 6 2,229 09-08-2013, 03:09 AM
Last Post: davorin

Forum Jump: