# Op-Amp Gain and Offset Design with the HP-67 Programmable Calculator

December 4, 2008

This is the third in an ongoing series of electronic design programs that I’m writing for the HP-67. This program is for designing offset-and-gain stages using a single operational amplifier. Such stages are often necessary to convert an input signal covering one range of voltages (e.g., 0.1V to 0.2V from a sensor) to an output signal covering a different range (e.g., 1.0 to 4.0V into an A/D converter).

Mathematically, such a stage performs a linear transformation on the input voltage,

`V _{OUT}` =

`m`

`V`+

_{IN}`b`

where `m` is the *slope* and `b` is the *intercept* or *offset*.

Given an input voltage range, `V _{IL}` to

`V`, and an output voltage range,

_{IH}`V`to

_{OL}`V`, the slope and offset are given by:

_{OH}There are four main cases to consider, with different circuits for each, that are addressed by this program:

- Positive slope and offset (
`m`> 0 and`b`> 0) - Positive slope and negative offset (
`m`> 0 and`b`< 0) - Negative slope and positive offset (
`m`< 0 and`b`> 0) - Negative slope and offset (
`m`< 0 and`b`< 0)

### Positive Slope and Offset

A positive slope and offset stage is implemented by the following circuit:

The designer must select values for `R _{1}` and

`R`, and then appropriate values for

_{F}`R`and

_{2}`R`can be calculated using the following formulae:

_{G}After determining theoretically ideal values for `R _{2}` and

`R`, real-world values can be chosen and the following formula applied to

_{G}`V`and

_{IL}`V`to see the resulting values of

_{IH}`V`and

_{OL}`V`respectively:

_{OH}This case is also used to handle the special case where `b` = 0 (postive gain with no offset). In such a case, the formula for `R _{2}` would result in dividing by zero, which means

`R`is infinite. In other words,

_{2}`R`and

_{2}`V`are not needed. The value of

_{REF}`R`won’t matter then either, and can be replaced by a direct connection. The circuit reduces to:

_{1}### Positive Slope and Negative Offset

The following circuit implements a positive slope and negative offset stage:

After choosing values for `R _{1}` and

`R`, values for

_{F}`R`and

_{2}`R`can be be calculated using these formulae:

_{G}The following formula can then be used to determine the effect of real-world values of `R _{2}` and

`R`on the transformation:

_{G}### Negative Slope and Positive Offset

A negative slope and postive offset stage is implemented by the following circuit:

Given values for `R _{1}` and

`R`, values for

_{F}`R`and

_{2}`R`can be be calculated as follows:

_{G}The following formula can then be used to determine the effect of substituting real-world values of `R _{2}` and

`R`:

_{G}This case is also used to handle the special case where `b` = 0 (negative gain with no offset). As in case 1, the formula for `R _{2}` would involve division by zero, so

`R`and

_{2}`V`are not needed. The non-inverting input of the op-amp can be connected directly to ground, giving the following circuit:

_{REF}### Negative Slope and Offset

The following circuit implements a negative slope and offset stage:

This circuit has no `R _{1}`, so it is only necessary to choose a value for

`R`, after which

_{F}`R`and

_{2}`R`are given by:

_{G}The effect of using real-world values of `R _{2}` and

`R`can then be tested using this formula:

_{G}### Limitations

*Theoretically*, the formulae presented here work perfectly well for gains between -1 and 1 (i.e. |`m`| < 1). However, many real-world op-amps are unstable in such cases. Instead, it will usually be necessary to design for a higher gain (|`m`| ≥ 1), with an attenuator on the input side. The design procedures for this are described on Texas Instruments’ *Op Amp Gain and Offset Page*.

## Using the Program

First type in the program and save it, or read it from a previously recorded magnetic card. The card should be labelled as follows:

OP-AMP GAIN AND OFFSET STAGE DESIGN | ||||
---|---|---|---|---|

V_{REF} |
V,_{IL}V_{IH} |
V,_{OL}V_{OH} |
||

→m,b |
→CASE | R,_{1}R→_{F}R,_{2}R_{G} |
R,_{2}R→_{G}V,_{OL}V_{OH} |

### Forward Solution: Finding `R`_{2} and `R`_{G}

_{2}

_{G}

Consider the following example. A sensor has an output ranging from 0.5V to 0.7V, and we want to interface it to an A/D converter that is expecting an input between 1V and 4V. There is no reference voltage available other than the well regulated 5V supply voltage of the circuit. Use a 10kΩ resistor for `R _{1}`, and 100kΩ for

`R`.

_{F}Follow these steps to solve the problem:

Description | Keystrokes | Display |
---|---|---|

Use engineering notation | h ENG DSP 2 |
0.00 00 |

Enter V_{REF} |
5 f a |
5.00 00 |

Enter V and _{IL}V_{IH} |
0.5 ENTER 0.7 f b |
500. -03 |

Enter V and _{OL}V_{OH} |
1 ENTER 4 f c |
1.00 00 |

Compute slope m |
A | 15.0 00 |

Compute offset b |
R/S | -6.50 00 |

Determine case number | B | 2.00 00 |

Enter R and _{1}R, compute _{F}R_{2} |
10 EEx 3 ENTER 100 EEx 3 C |
1.02 03 |

Compute R_{G} |
R/S | 6.21 03 |

#### Notes

It is not necessary to compute the slope and offset (by pressing `A`

) before determining the case number. Likewise, it isn’t necessary to determine the case number (by pressing `B`

) before computing resistor values (although you’ll want to know the case number in order to know which circuit to build). The program keeps track of which information is up to date, and will (re)compute anything that it needs that hasn’t already been computed.

### Reverse Solution: Finding the Effect of `R`_{2} and `R`_{G} on `V`_{OL} and `V`_{OH}

_{2}

_{G}

_{OL}

_{OH}

The closest available 5% resistor values for `R _{2}` and

`R`are 1kΩ and 6.2kΩ respectively. What effect does using these have on the solution? Follow these steps to find out:

_{G}Description | Keystrokes | Display |
---|---|---|

Enter R and _{2}R, compute _{G}V_{OL} |
1 EEx 3 ENTER 6.2 EEx 3 D |
1.13 00 |

Compute V_{OH} |
R/S | 4.15 00 |

This is within the A/D’s input range at the lower bound, but outside the range at the upper bound. What happens if we use the next available value for `R _{G}`, 6.8kΩ, instead?

Description | Keystrokes | Display |
---|---|---|

Enter R and _{2}R, compute _{G}V_{OL} |
1 EEx 3 ENTER 6.8 EEx 3 D |
1.09 00 |

Compute V_{OH} |
R/S | 3.88 00 |

This is almost centered within the desired output range, and covers 93% of it.

The only remaining concern is how component tolerances might affect the solution. This can be analyzed by trying different combinations of `R _{1}`,

`R`,

_{2}`R`, and

_{F}`R`representing resistors that are maximally out of tolerance (±5%) in each direction.

_{G}For example, to test the case where `R _{1}` and

`R`are 5% low and

_{F}`R`and

_{2}`R`are 5% high, follow these steps:

_{G}Description | Keystrokes | Display |
---|---|---|

Enter low R and _{1}R, ignore computed _{F}R_{2} |
0.95 EEx 3 ENTER 95 EEx 3 C |
920. 00 |

Enter high R and _{2}R, compute _{G}V_{OL} |
1.05 EEx 3 ENTER 7.14 EEx 3 D |
808. -03 |

Compute V_{OH} |
R/S | 3.48 00 |

The results show that in this case, the lower limit of the output is out of range, meaning either a redesign is necessary, or tighter tolerance components are needed.

### Cases where `b` = 0

In cases where the offset, `b`, is zero, the program will instead use `b` = 10^{-9} as the offset. This will avoid any division-by-zero errors. The program will then use case 1 (if `m` > 0) or case 3 (if `m` < 0) to compute the solution. In both cases, the computed value for `R _{2}` will be very large, typically around 10

^{9}times the value specified for

`R`. This indicates that

_{1}`R`and

_{2}`V`can be omitted, and that

_{REF}`R`can be replaced by a direct connection.

_{1}## Program Listing

Line | Instruction | Comments |
---|---|---|

001♦ | LBL a | Enter available reference voltage |

002 | STO 9 | |

003 | RTN | |

004♦ | LBL b | Enter V and _{IL}V_{IH} |

005 | STO 6 | Store V_{IH} |

006 | x↔y | |

007 | STO 5 | Store V_{IL} |

008 | CF 0 | Must recompute m and b |

009 | RTN | |

010♦ | LBL c | Enter V and _{OL}V_{OH} |

011 | STO 8 | Store V_{OH} |

012 | x↔y | |

013 | STO 7 | Store V_{OL} |

014 | CF 0 | Must recompute m and b |

015 | RTN | |

016♦ | LBL A | Compute transfer function slope (m) and intercept (b) |

017 | F? 0 | Are m and b already up to date? |

018 | GTO 5 | |

019 | RCL 8 | Compute and store m = (V – _{OH}V) ÷ (_{OL}V – _{IH}V)_{IL} |

020 | RCL 7 | |

021 | − | |

022 | RCL 6 | |

023 | RCL 5 | |

024 | − | |

025 | ÷ | |

026 | STO A | |

027 | RCL 5 | Compute and store b = V – _{OH}m V_{IL} |

028 | × | |

029 | RCL 7 | |

030 | − | |

031 | CHS | |

032 | x≠0? | |

033 | GTO 7 | |

034 | EEx | Make sure b is never exactly 0 |

035 | CHS | |

036 | 9 | |

037♦ | LBL 7 | |

038 | STO B | |

039 | SF 0 | Stored m and b are now up to date |

040 | CF 1 | Must recompute case number now |

041♦ | LBL 5 | Display computed or already up-to-date m and b |

042 | RCL A | |

043 | RTN | Return, leaving m on stack |

044 | RCL B | Display b if user pressed R/S after return |

045 | RTN | |

046♦ | LBL B | Compute case number and store in I |

047 | GSB A | Make sure m and b are up to date |

048 | F? 1 | Is case number already up to date |

049 | GTO 8 | |

050 | x<0? | |

051 | GTO 6 | Handle cases where m < 0 |

052 | 1 | |

053 | ST I | |

054 | RCL B | |

055 | x<0? | |

056 | ISZ I | Case 2: m positive and b negative |

057 | GTO 8 | Case 1: m positive and b positive |

058♦ | LBL 6 | Cases where m is negative |

059 | 3 | |

060 | ST I | |

061 | RCL B | |

062 | x<0? | |

063 | ISZ I | Case 4: m negative and b negative |

064♦ | LBL 8 | Case 3: m negative and b positive |

065 | SF 1 | Case number is now up to date (or was already up to date) |

066 | RC I | Display case number and return |

067 | RTN | |

068♦ | LBL C | Compute solution using appropriate case |

069 | STO 3 | Store R_{F} |

070 | x↔y | |

071 | STO 1 | Store R_{1} |

072 | GSB B | Get case number |

073 | GTO (i) | Branch to appropriate case |

074♦ | LBL 1 | Positive m and positive b |

075 | RCL 1 | Compute and store R = _{2}V _{REF}R _{1}m ÷ b |

076 | RCL 9 | |

077 | × | |

078 | RCL A | |

079 | × | |

080 | RCL B | |

081 | ÷ | |

082 | STO 2 | |

083 | R/S | Display R; 9.99e99 means “open circuit”_{2} |

084 | RCL 9 | Compute and store R = _{G}V _{REF}R ÷ (_{F}V (_{REF}m – 1) + b) |

085 | RCL 3 | |

086 | × | |

087 | GSB 9 | Compute V (_{REF}m – 1) + b |

088 | GTO 5 | Divide, store R, and return, leaving _{G}R on stack_{G} |

089♦ | LBL 2 | Positive m and negative b |

090 | RCL 1 | Compute and store R = –_{2}R _{1}b ÷ (V (_{REF}m – 1) + b) |

091 | RCL B | |

092 | CHS | |

093 | × | |

094 | GSB 9 | Compute V (_{REF}m – 1) + b, leaving V (_{REF}m – 1) in register 0 |

095 | ÷ | |

096 | STO 2 | |

097 | R/S | Display R_{2} |

098 | RCL 1 | Compute and store R = (_{G}R _{1}b + V _{REF}R) ÷ (_{F}V (_{REF}m – 1)) |

099 | RCL B | |

100 | × | |

101 | RCL 9 | |

102 | RCL 3 | |

103 | × | |

104 | + | |

105 | RCL 0 | Subroutine 9 left V (_{REF}m – 1) in register 0 for us |

106 | GTO 5 | Divide, store R, and return, leaving _{G}R on stack_{G} |

107♦ | LBL 3 | Negative m and positive b |

108 | RCL 1 | Compute and store R = _{2}R (_{1}V (_{REF}m – 1) + b) ÷ –b |

109 | GSB 9 | Compute V (_{REF}m – 1) + b |

110 | × | |

111 | RCL B | |

112 | CHS | |

113 | ÷ | |

114 | STO 2 | |

115 | R/S | Display R_{2} |

116 | RCL 3 | Compute and store R = –_{G}R ÷ _{F}m |

117 | CHS | |

118 | RCL A | |

119 | GTO 5 | Divide, store R, and return, leaving _{G}R on stack_{G} |

120♦ | LBL 4 | Negative m and negative b |

121 | RCL 9 | Compute and store R = _{2}V _{REF}R ÷ –_{F}b |

122 | RCL 3 | |

123 | × | |

124 | RCL B | |

125 | CHS | |

126 | ÷ | |

127 | STO 2 | |

128 | R/S | Display R_{2} |

129 | RCL 3 | Compute and store R = _{G}R ÷ _{F}m |

130 | RCL A | |

131 | CHS | |

132♦ | LBL 5 | Common code to compute y ÷ x and store in R_{G} |

133 | ÷ | |

134 | STO 4 | |

135 | RTN | Return, leaving R on stack_{G} |

136♦ | LBL 9 | Compute V (_{REF}m – 1) + b, leaving V (_{REF}m – 1) in register 0 |

137 | RCL A | |

138 | 1 | |

139 | − | |

140 | RCL 9 | |

141 | × | |

142 | STO 0 | Save V (_{REF}m – 1) in register 0 for later |

143 | RCL B | |

144 | + | |

145 | RTN | |

146♦ | LBL D | Compute V,_{OL}V using supplied _{OH}R,_{2}R_{G} |

147 | STO 4 | Store R_{G} |

148 | x↔y | |

149 | STO 2 | Store R_{2} |

150 | GSB B | Get case number |

151 | RCL 5 | |

152 | GSB (i) | Compute V from _{OL}V_{IL} |

153 | R/S | Display computed V_{OL} |

154 | RCL 6 | |

155 | GTO (i) | Compute V from _{OH}V_{IH} |

156♦ | LBL 1 | Compute V for positive _{OUT}m and positive b |

157 | RCL 2 | |

158 | × | |

159♦ | LBL 0 | Entry point to compute (x + V _{REF}R) (1 + _{1}R ÷ _{F}R) ÷ (_{G}R + _{1}R)_{2} |

160 | RCL 9 | |

161 | RCL 1 | |

162 | × | |

163 | + | |

164 | RCL 3 | |

165 | RCL 4 | |

166 | ÷ | |

167 | 1 | |

168 | + | |

169 | × | |

170 | RCL 1 | |

171 | RCL 2 | |

172 | + | |

173 | ÷ | |

174 | RTN | |

175♦ | LBL 2 | Compute V for positive _{OUT}m and negative b |

176 | RCL 1 | |

177 | 1/x | |

178 | RCL 2 | |

179 | 1/x | |

180 | + | |

181 | 1/x | |

182 | RCL 4 | |

183 | + | |

184 | STO 0 | Store R + _{G}R _{1}R ÷ (_{2}R + _{1}R) for later_{2} |

185 | RCL 3 | |

186 | + | |

187 | × | |

188 | RCL 0 | |

189 | ÷ | |

190 | RCL 9 | |

191 | RCL 2 | |

192 | × | |

193 | RCL 3 | |

194 | × | |

195 | RCL 1 | |

196 | RCL 2 | |

197 | + | |

198 | RCL 0 | |

199 | × | |

200 | ÷ | |

201 | − | |

202 | RTN | |

203♦ | LBL 3 | Compute V for negative _{OUT}m and positive b |

204 | 0 | |

205 | GSB 0 | Compute (V _{REF}R) (1 + _{1}R ÷ _{F}R) ÷ (_{G}R + _{1}R)_{2} |

206 | GTO 9 | Subtract V _{IN}R ÷ _{F}R_{G} |

207♦ | LBL 4 | Compute V for negative _{OUT}m and negative b |

208 | RCL 9 | |

209 | RCL 3 | |

210 | × | |

211 | RCL 2 | |

212 | ÷ | |

213 | CHS | |

214♦ | LBL 9 | Entry point to compute x – y R ÷ _{F}R_{G} |

215 | x↔y | |

216 | RCL 3 | |

217 | × | |

218 | RCL 4 | |

219 | ÷ | |

220 | − | |

221 | RTN |

Two interesting aspects of this program are its use of indirect addressing for branching to the forward and reverse solution subroutines for each of the four cases, and its use of repeated labels.

The forward solution for each of the four slope/offset cases is implemented by a sequence of instructions starting with the label corresponding to the case number (1 to 4). When the user presses `C`

, the case number is computed if necessary, and a `GTO (i)`

instruction then branches to the appropriate case.

Similarly, the reverse solution for each case is also labeled according to the case number. When the user presses `D`

, `V _{IL}` is recalled to the stack, after which a

`GSB (i)`

instruction causes `V`to be calculated. Then

_{OL}`V`is recalled, and

_{IH}`GTO (i)`

is used to calculate `V`and then return.

_{OH}So, there are two each of `LBL 1`

through `LBL 4`

. This works because the HP-67 (and other vintage HP calculators) search forwards from the current step for the matching label. Thus the `GTO (i)`

in step 73 will branch to the appropriate forward solution, and the `GSB (i)`

in step 152 and `GTO (i)`

in step 155 will branch to the appropriate reverse solution.

This program also makes use of many small subroutines to compute sub-expressions common to multiple solutions. Since there were not enough labels for all the subroutines needed, the same labels were used more than once. Had this not been done, the same sequence of steps would have been repeated several times, and the program would not have fit into the calculator’s 224 step memory.

## Registers and Flags

Register | Use |
---|---|

0 | Temporary register |

1 | R (Ohms)_{1} |

2 | R (Ohms)_{2} |

3 | R (Ohms)_{F} |

4 | R (Ohms)_{G} |

5,6 | V and _{IL}V, input voltage range_{IH} |

7,8 | V and _{OL}V, output voltage range_{OH} |

9 | V_{REF} |

A | m, slope of transfer function |

B | b, intercept of transfer function |

I | Case number (1,2,3,4) |

Flag | Meaning |
---|---|

0 | m and b are up to date |

1 | Case number is up to date |

## Revision History

2008-Dec-04 — Initial release.

## Related Articles

If you've found this article useful, you may also be interested in:

- Op-Amp Gain and Offset Design with the HP-41C Programmable Calculator
- Op-Amp Oscillator Design with the HP-41C Programmable Calculator
- Low-Sensitivity Sallen-Key Filter Design with the HP-41C Programmable Calculator
- Low-Sensitivity Sallen-Key Filter Design with the HP-67 Programmable Calculator
- Op-Amp Oscillator Design with the HP-67 Programmable Calculator
- Resistor Network Solver for the HP-67 Programmable Calculator
- A Matrix Multi-Tool for the HP 35s Programmable Calculator
- Curve Fitting for the HP 35s Programmable Calculator

Buy Stefan a coffee! If you've found this article

useful, consider
leaving a donation to help support

stefanv.com

**Disclaimer:** Although every effort has been
made to ensure accuracy and reliability, the information on this web
page is presented without warranty of any kind, and Stefan Vorkoetter
assumes no liability for direct or consequential damages caused by its
use. It is up to you, the reader, to determine the suitability of, and
assume responsibility for, the use of this information. Links to
Amazon.com merchandise are provided in association with Amazon.com.
Links to eBay searches are provided in association with the eBay
partner network.

**Copyright:** All materials on this web site, including the
text, images, and mark-up, are Copyright © 2023 by Stefan Vorkoetter unless otherwise noted. All rights reserved.
Unauthorized duplication prohibited. You __may__ link to this site
or pages within it, but you may __not__ link directly to images on
this site, and you may __not__ copy any material from this site to
another web site or other publication without express written
permission. You may make copies for your own personal use.

Saim Sharik

November 25, 2010

opamp

Willy Kunz

May 15, 2013

I entered the program into my iPad HP-67 emulator (“RPN-67 Pro”) and got a few differing results. Specifically, in section “Reverse Solution: Finding the Effect of R2 and RG on VOL and VOH” the first result was 1.14 instead of 1.13. More seriously, the last three results were totally off the mark:

97.2 instead of 920, -25.9 instead of 808, and -23.2 instead of 3.48. After checking the listing several times, I entered the program into a physical HP-67. It returned results in exact agreement with the emulator. I suspect there’s a typo in the listing, but I haven’t figured it out yet.

Stefan Vorkoetter

May 15, 2013

I’ll have to double check the listing against the actual program. Thing is, I develop HP programs using a text editor, and then enter the program and generate the listings for my articles from the same original source, so I’m not sure how an error could have crept in. But anything’s possible.

Willy Kunz

May 16, 2013

It seems the listing is okay. What’s wrong is the value entered for low R1 in the example. Instead of 0.95 EEx 3 it should be 9.5 EEx 3. The resulting display then is 972. 00 (not 920. 00). VOL will be 512.-03 (not 808.-03) and VOH will be 3.08 00 (not 3.48 00).

(Stefan, please contact me by e-mail.)