Basic Starter Package - Tutorial #7

The RCTIME Command

copyright, Peter H. Anderson, Dept of EE,
Morgan State University, Baltimore, MD, Nov 30, '97

Note.

The Basic Starter Package includes a number of tutorials. The intent is to teach the user how to effectively use the Stamp in the context of various applications.

This section has been completed.

Overview

This tutorial focuses on the RCTIME command which may be used to determine an unknown resistor or capacitor value.

The field of electrical engineering has burgeoned as a result of the transistor. Any quantity that can be converted to an electrical parameter can be measured and processed using relatively inexpensive technology.

In general, electrical engineers work with either voltage or time measurments or both. However, we can readily convert frequency, current, resistance, capacitance and inductance to either a voltage or a time quantity and thus we have all of these other tools available as well, which permits us to measure all manner of phenomenon. For example;

The list goes on and on. Gone are the days when a human hair was strung between two points and maintained at a constant tension with someone constantly measuring the length to determine the relative humidity. Today, Philips has a capacitor that varies as a function of relative humidity and it is a simple matter to convert capacitance to time and calculate the relative humidity.

Thus, between the RCTIME and the COUNT commands and the ability to interface with an A/D converter, you have the ability to measure virtually anything.

RCTIME Command

Please see Figure #1.

Note that the configuration may be different from those you may see elsewhere. The reason is that many I have seen in the manuals are wrong, a classic case of someone drawing a line in the wrong place. But, among those which are correct, this circuit provides an improved means of calibration while avoiding burning out your potentiomenter or Stamp or both.

The idea of the RCTIME command is that an output from the Stamp is brought high for a period of time to charge the capacitor. Let's assumme to +5.0 Volts. Execution of the RCTIME command causes the output pin to turn around and become an input, and is thus seen as a high impedance by the RC network. The capacitor then discharges toward ground through R_eq;

(1)	V_c = V_cc * (1.0 - 1.0 * exp (-t/(R_eq * C))
At some time during the discharge, the input to the Stamp will drop below what is seen as a logic one, V_thresh, which is nominally 1.4 V. The Stamp reports the time from when it turned the pin around to the time it sees the input as a logic zero. This time is reported as the number of 2 usecs intervals and is stored as a word. Note that the maximum is 65,535 * 2 usecs or nominally 135 msecs.

By rearranging equation (1) and solving for t when V_c crosses V_thresh;

(2)	t_1 = R_eq * C * ln (V_cc/V_th)
For example, if C=0.1 uFd, R_eq = 110K, V_CC = 5.0 and V_th = 1.4;
	t_1 = 14,002 usecs 
Note that the Stamp will report this as 7001 two usec counts.

Although, this is but one tenth the capability of the Stamp, it permits one to use a relatively inexpensive, but stable mylar capacitor and four stable 0.1 mylar capacitors have been included in the Basic Starter package.

Rearranging equation (2) so as to solve for R_eq;

(3)	R_eq = t_1 / (C * ln (V_cc/V_th))
Assumming you use a capacitor of 0.1 uFd;
(4) 	R_eq = 2_usec_count * 2 / (0.1 * ln(V_cc/V_th))
Or, in general form as;
(5)	R_eq = 2_usec_count * k
where;
(6)	k = 2 / (0.1 * (ln(V_CC/V_th)
if C is indeed 0.1 uFd, V_cc is 5.0 and V_th is 1.4;
	k = 15.74
Thus, a simple algorithm is to execute the RCTIME command, take the result and multiply by 15.74. More on this below.

However, note that in Figure #1, R_eq is the series combination of a 1.0K calibration resistor R_cal, and the unknown resistance R_unknown. R_unkown is then calculated as;

	R_unknown = T_COUNT * 15.74 - 1000
A simple implementation of this is illustrated in program RCTIME_1.BS2.

Program RCTIME_1.BS2.

Wire as shown in Figure #2. Note that Stamp terminal 5 corresonding to P0 is connected to the parallel RC network. The pushbutton will be used as an input in the next routine and it is configured on terminal 16, corresponding to P11.

' Program RCTIME_1.BS2
'
' Measures and displays the value of R_UNK.  RC Network on Terminal 5.
'
' P. H. Anderson, Nov 29, '97

R_EQ 	VAR WORD
R_UNK	VAR WORD
T_COUNT VAR WORD

	DIRS=$00FF
TOP:
	DIR0 = 1	' be sure P0 is an output
	OUT0 = 1	' charge the capacitor
	PAUSE  100	' give it time to charge

	RCTIME 0, 1, T_COUNT
	'DEBUG ?T_COUNT

	' R_EQ = 15.74 * T_COUNT

	R_EQ = (T_COUNT * 15) + (T_COUNT * 7/10) + (T_COUNT * 4/100)
	R_UNK = R_EQ - 1000	' subrtract the 1.0 K resistor
	DEBUG ? R_UNK		
	PAUSE 1000
	GOTO TOP
Note that the Stamps does not handle decimal. However;
	15.74 = 15 + 7/10 + 4/100
Thus T_COUNT*15.74 can be implemented as;
	R_EQ = (T_COUNT * 15) + (T_COUNT * 7/10) + (T_COUNT * 4/100)
Note that if R_EQ is nominally 65K, an overflow will occur as numbers larger than 65,535 cannot be stored in a word (16 bits). In such cases, the following may be workable;
	R_EQ_DIV_10 = T_COUNT * 1.574

	R_EQ_DIV_10 = (T_COUNT) + (T_COUNT * 5/10) 
				+ (T_COUNT * 7/100) + (T_COUNT * 4/1000)
That is, you work with one tenth the value of the resistor. If neccessary to display it, simply add a zero;
	DEBUG DEC R_EQ_DIV_10, "0"
Continuation of the Main Discussion.

Note that the derivation of the constant k in equation (6) assummed the capacitor was exactly 0.1 uFd, that the high output of the Stamp is 5.0 V and the threshold is 1.4 and these can vary from capacitor to capacitor and Stamp to Stamp and from one supply to another.

Thus, another approach might be to perform a simple calibration with the R_desired replaced with a short. Thus, R_eq is simply R_cal or 1.0K. Peforming RCTIME will result in T_COUNT_CAL which may be stored in EEPROM.

During normal operation, R_eq = R_cal + R_unknown.

Thus, R_eq = T_COUNT / T_COUNT_CAL * R_cal.

Arithmetic is not easy on the Stamp and there is no simple unique solution. Rather, you have to tinker and the Stamp is a marvelous machine to tinker with. With a few key strokes, you can edit your code and instantly download.

There are two obstacles which tend to work against each other to give you a challenge.

The first is truncation error. If T_COUNT_CAL is 60 corresponding to R_cal of 1000, and R_eq is 2.95K, the result will be a T_COUNT of of 177 and unfortunately the above will evaluate;

	R_eq = 177 / 60 * 1000 = 2000
In fact, if you use the above, in the order it is presented, the resolution of R_eq will be 1000. Not much point in performing the calibration.

But, keep going. There usually is a work around.

Perhaps, if we reorder the above;

	R_eq = (T_COUNT * R_cal) / T_COUNT_CAL
Here, we run into the second obstacle; overflow. If T_COUNT is 177 and R_cal is 1000, the result is 177,000; much too large a quantity to accommodate in a word (65,535 max).

Perhaps;

	R_eq = T_COUNT * (R_cal / T_COUNT_CAL)
This may have possibilities. If R_cal is 1000 and T_COUNT_CAL is nominally 60, there will be some truncation error, but certainly not as severe as the case noted above.

But, the point of the calibration was accuracy and in program RCTIME_2.BS2, I carried the accuracy to the extreme;

	R_eq = (T_COUNT * (R_cal DIG 3) / T_COUNT_CAL) * 1000
	     + (T_COUNT * (R_cal DIG 2) / T_COUNT_CAL) * 100
	     + (T_COUNT * (R_cal DIG 1) / T_COUNT_CAL) * 10
	     + (T_COUNT * (R_cal DIG 0) / T_COUNT_CAL) * 1
Note that the DIG operator conveniently isolates the number of thousands, hundreds, tens and units.

This took me several hours. I can't say it was unpleasant as fooling with embedded proocessor control is both my job and my hobby. I approach such problems as challenges. Some get solved in an hour, others take a lot longer and there are a few I have never solved.

Note that by using this calibration technique, C, V_cc and V_th are not even in the equation. Any deviation in C, V_cc or V_th has already been reflected in T_COUNT_CAL.

Program RCTIME_2.BS2 performs a calibration when pushbutton PB11 is depressed and the value of T_COUNT_CAL is saved to EEPROM. In addition, I measured my value of R_cal using a DVM and this is stored in EEPROM prior to running the program.

Program RCTIME.BS2

' Program RCTIME_2.BS2
'
' Measures and displays the value of R_DES using RCTIME command.
'
' C = 0.1 uFd.
'
' This routine includes a provision for calibration.  When pushbutton
' on P11 is depressed, RCTIME is executed with calibration resistor.
'
' This is value of T_COUNT_CAL is saved to EEPROM.
'
' Note that on download, T_COUNT_CAL is set to a default of 63.  This 
' is updated if the user performs the calibration.
'
' On download, the value of R_cal/10 is stored in EEPROM.  
' 
' P. H. Anderson, Nov 29, '97

EE_R_CAL_DIV_10	DATA 97		' R_CAL is 970 Ohms
EE_T_COUNT_CAL	DATA  63	' theoretical T_COUNT_CAL

T_COUNT_CAL	VAR BYTE
R_CAL		VAR WORD
R_EQ 		VAR WORD
R_UNK		VAR WORD
T_COUNT 	VAR WORD

	DIRS=$00FF
TOP:
	
	DIR0 = 1	' be sure P0 is an output
	OUT0 = 1	' charge the capacitor
	PAUSE  100	' give it time to charge

	RCTIME 0, 1, T_COUNT
	
	IF (IN15<>0) THEN MEASURE

CALIBRATE:
	WRITE EE_T_COUNT_CAL, T_COUNT.BYTE0
	DEBUG "FINISHED CALIBRATION", CR
	DEBUG "RELEASE PUSHBUTTON", CR
	GOTO TOP
	
MEASURE:
	READ EE_R_CAL_DIV_10, R_CAL	
	R_CAL = R_CAL * 10 	
	
	READ EE_T_COUNT_CAL, T_COUNT_CAL
	DEBUG ? T_COUNT_CAL
	R_EQ = (R_CAL DIG 3) * T_COUNT / T_COUNT_CAL * 1000
	debug ?R_EQ
	R_EQ = R_EQ + (((R_CAL DIG 2) * T_COUNT / T_COUNT_CAL) * 100)
	debug ?R_EQ
	R_EQ = R_EQ + (((R_CAL DIG 1) * T_COUNT / T_COUNT_CAL) * 10)
	debug ?R_EQ
	' units is not necessary as least significant digit is zero
	R_UNK = R_EQ - R_CAL	' subtract the 1.0 K resistor
	
	PAUSE 1000
	GOTO TOP

Note that the value of R_CAL is actually saved to EEPROM as one tenth of its value. This avoided saving it as a word in EEPROM. However, on reading this from EEPROM, it is multiplied by 10.

Note that T_COUNT is a word. To limit this to a byte would limit the measurement capability to resistor values of less than 4,000 Ohms. However, EE_T_COUNT_CAL in EEPROM is a byte as a typical value is 60.

Thus, I was attempting to store a word in a byte location in EEPROM. This was solved by;

	WRITE EE_T_COUNT_CAL, T_COUNT.BYTE0
In fact, this may not have been necessary. In debugging the program, I continually examined data memory using the ctrl-m command after this write to EEPROM and was continually frustrated to see that it was apparently unchanged from the default value which was downloaded.

I now see my foolish reasoning. The memory map when using the programming package can only show you what it downloaded. After that, the Stamp takes over. The Stamp was in fact writing the value to EEPROM and all I was examining in using the ctrl-m command was what the PC originally downloaded.