File: an429.c

package info (click to toggle)
sdcc 3.5.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 59,964 kB
  • ctags: 66,696
  • sloc: ansic: 422,129; cpp: 49,032; makefile: 46,849; sh: 28,496; perl: 12,125; asm: 11,748; yacc: 6,698; lisp: 1,630; lex: 747; python: 660; awk: 495; sed: 89
file content (402 lines) | stat: -rw-r--r-- 11,897 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
/*
	this program the flow of air through a rotary flowmeter
	and displays the calculated cfm. the output of the meter
	is a small duty cycle pulse, the period of repatition of
	which if proportional to the flow. the flow is compensated
	for changes in pressure and temperature to maintain
	calibration. if the flow exceeds an adjustable setpoint
	it energizes a 2 form c relay for user application use.
*/

#include <reg552.h>
			     
#define	ZERO_K		2730	/* 0 degress centigrade in kelvin       */
#define	ONE_TENTH_CFM	4444444L /* 1/10 cfm in microseconds		*/
#define	STD_TEMP	2980	/* 25 degrees centigrade in kelvin      */
#define	STD_ATM		147	/* one atmosphere in tenths psi         */
#define	LOWEST_CFM	0x40	/* maximun period from meter 0x400000   */
#define	START_ADC0	0x28	/* commands to start appropriate        */
#define	START_ADC1	0x29	/* a/d conversion cycle                 */
#define	START_ADC2	0x2a	/*                                      */
#define	START_ADC3	0x2b	/*                                      */
#define	START_ADC4	0x2c	/*                                      */
#define	ADCI		0x10	/* a/d converter status flags           */
#define	ADCS		0x08	/*                                      */
#define	FREERUN_I	0x10	/*                                      */
#define	SEG_A		0x01	/* P3 position for display segment 'a'  */
#define	CFM		0x01	/* P3 position for 'cfm' led            */
#define	SEG_B		0x02	/* P3 position for display segment 'b'  */
#define	DEGREES		0x02	/* P3 position for 'degrees' led        */
#define	SEG_C		0x04	/* P3 position for display segment 'c'  */
#define	PSI		0x04	/* P3 position for 'psi' led            */
#define	SEG_D		0x08	/* P3 position for display segment 'd'  */
#define	SETPOINT	0x08	/* P3 position for 'setpoint' led       */
#define	SEG_E		0x10	/* P3 position for display segment 'e'  */
#define	SEG_F		0x20	/* P3 position for display segment 'f'  */
#define	SEG_G		0x40	/* P3 position for display segment 'g'  */
#define	SEG_DP		0x80	/* P3 position for display decimal pt.  */

typedef	unsigned char byte;	/* type define objects with             */
typedef unsigned int word;	/* more classical microprocessor        */
typedef unsigned long l_word;	/* meaning                              */

#define TRUE 1			/* define logical true / false          */
#define FALSE 0			/* values for bit variables             */


/*
	define look-up table of possible seven segment display
	characters possible to display.	table contents need to 
	be inverted before use to be compatible with  U2 (udn2585a)
*/

code byte segments[] =
{
    SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F        ,	/* 0 */
    SEG_B | SEG_C                                ,	/* 1 */
    SEG_A | SEG_B |         SEG_D | SEG_E |         SEG_G,	/* 2 */
    SEG_A | SEG_B | SEG_C | SEG_D |                 SEG_G,	/* 3 */
    SEG_B | SEG_C |                 SEG_F | SEG_G,	/* 4 */
    SEG_A |         SEG_C | SEG_D         | SEG_F | SEG_G,	/* 5 */
    SEG_A |         SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,	/* 6 */
    SEG_A | SEG_B | SEG_C                                ,	/* 7 */
    SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,	/* 8 */
    SEG_A | SEG_B | SEG_C | SEG_D |         SEG_F | SEG_G,	/* 9 */
    SEG_A |                 SEG_D | SEG_E | SEG_F | SEG_G	/* error */
};

sbit	RELAY		= 0x96;	/* active hi to turn on setpoint relay  */
sbit	STROBE_0	= 0x80;	/* active hi to enable status led's     */
sbit	STROBE_1	= 0x81;	/* active hi to enable display cr15     */
sbit	STROBE_2	= 0x82;	/* active hi to enable display cr14     */
sbit	NO_FLOW		= 0x83;	/* flag set when no flow detected       */
sbit	STROBE_3	= 0x84;	/* active hi to enable display cr13     */
sbit	SEL_0		= 0x93;	/* active low inputs used to select     */
sbit	SEL_1		= 0x94;	/* mode being displayed                 */
sbit	INTR		= 0x95;	/*                                      */
sbit	UPDATE		= 0x97;	/* flag set when time to update display */
data	word	cfm;		/* gas flow in tenths of a cfm          */
data	word	setpoint;	/* relay setpoint in tenths of a cfm    */
data	word	degree_c;	/* temperature in tenths centagrade     */
data	l_word	corr;		/* intermediate calculation value       */
data	word	psi;		/* pressupe in tenths of a psi          */
data	byte	display0;	/* variables to hold values for the     */
data	byte	display1;	/* displays during refresh              */
data	byte	display2;	/*                                      */
data	byte	display3;	/*                                      */
data	byte	disp_pntr;	/* pointer to next display to enable    */
data	byte	refresh;	/* counter determines display updates   */
data	byte	high;		/* bits 16 - 23 of flow period          */
data	byte	middle;		/* bits 8 - 15 of flow period           */
data	byte	low;		/* bits 0 - 7  of flow period           */
data	byte	ticks;		/* incremented by timer overflow        */

/*
	use the free-running I timer to multiplex the led displays
	at approx. 1000 hz.
*/

void multiplex() interrupt 3
{
	switch(disp_pntr)
	{
	case 0x00:
	    STROBE_3 = FALSE;	/* turn off display cr13        */
	    P3 = 0xff;		/* turn off all segments        */
	    P3 = display0;	/* load segments for led's      */
	    STROBE_0 = TRUE;	/* turn on status led's         */
	    disp_pntr = 1;	/* increment pointer to dsiplay */
	    break;
	case 0x01:
	    STROBE_0 = FALSE;	/* turn off status led's        */
	    P3 = 0xff;		/* turn off all segments        */
	    P3 = display1;	/* load segments for tenths     */
	    STROBE_1 = TRUE;	/* turn on display cr15         */
	    disp_pntr = 2;	/* increment pointer to dsiplay */
	    break;
	case 0x02:
	    STROBE_1 = FALSE;	/* turn off display cr15        */
	    P3 = 0xff;		/* turn off all segments        */
	    P3 = display2;	/* load segments for units      */
	    STROBE_2 = TRUE;	/* turn on display cr14         */
	    disp_pntr = 3;	/* increment pointer to dsiplay */
	    break;
	case 0x03:
	    STROBE_2 = FALSE;	/* turn off display cr14        */
	    P3 = 0xff;		/* turn off all segments        */
	    P3 = display3;	/* load segments for tens       */
	    STROBE_3 = TRUE;	/* turn on display cr13         */
	    disp_pntr = 0;	/* increment pointer to dsiplay */
	    break;
	}
}

/*
	use the free running pwm prescaler to generate
	interrupts every 92 hz. every 32nd interrupt
	set the UPDATE flag to enable the reading of
	the command switches, and updating of the led
	display contents.
*/
void read_switch() interrupt 6
{
	if(refresh++ == 32)
	{	UPDATE = TRUE;
		refresh = 0;
	}
}

/*
	whenever the timer overflows from 0xffff to 0x0000
	increment the variable 'ticks' which represent the
	highest order (16 - 23) bits of the gas flow period
	in microseconds. if the variable 'ticks' is greater
	than the period representing a flow of < 0.1 cfm
	then set the NO_FLOW flag to enable display of 00.0
*/

void overflow() interrupt 1
{
	if(++ticks > LOWEST_CFM)
	{
		cfm = 0;
		ticks = 0;
		NO_FLOW = TRUE;
	}
}

/*
	an external interrupt generated by a tach pulse
	from the flowmeter reads the current value of the
	timer into variables 'low' and 'middle', and then
	resets the timers. the 'ticks' variable described
	above is also copied to variable 'high', and then
	reset to zero. the NO_FLOW flag is cleared to 
	enable display of the calculated cfm.
*/

void calc_cfm() interrupt 0
{
	low = TL0;
	TL0 = 0;
	middle = TH0;
	TH0 = 0;
	high = ticks;
	ticks = 0;
	NO_FLOW = FALSE; 
}

void main()
{
	RELAY		= 0;    /* initialize output pins		*/
	INTR		= 1;
	UPDATE		= 1;
	STROBE_0	= 0;
	STROBE_1	= 0;
	STROBE_2	= 0;
	STROBE_3	= 0;
	NO_FLOW		= 0;
	TL0	= 0;		/* timer 0 period 0x10000 u_seconds	*/
	TH0	= 0;
	PWMP	= 255;		/* pwm timer interrupt at 92 hz		*/
	TR0	= 1;		/* enable timer 0			*/
	IT0	= 1;		/* INT0 is edge active			*/
	ticks	= 0;		/* initialize variables			*/
	cfm	= 0;
	low	= 0;
	middle	= 0;
	high	= 0;
	degree_c = 250;
	psi	= 147;
	corr	= 0;
	refresh = 0;
	disp_pntr = 0;
	IEN0	= 0xab;		/* enable intrrupts			*/
#ifdef MY
/*
	main execution loop, executes forever.
*/

	while(1)
	{

/*
 	calculate base cfm rate - first create long word representing
	flow rate period in microseconds. then subtract out the time
	overhead in servicing the routine 'calc_cfm'. then divide the
	period into the period for 1/10 cfm, to get flow rate in 1/10
	cfm resolution.
*/ 

       		corr = high * 0x10000L;
       		corr += (middle * 0x100L);
		corr += low;
       		corr = ONE_TENTH_CFM / corr;

/*
	read temperature - measure output from the LM35 sensor,
	scaled by the AMP-02. the scaling results in a range
	of 0 to 51.0 degrees centigrade, in 0.2 degree steps.
*/

		ADCON = START_ADC1;
		while(ADCON & ADCS) ;
		degree_c = ((word)ADDATH) << 8 | ADDATL;
		degree_c *= 2;

/*
	compensate cfm rate for temperature - convert temperature
	into degrees kelvin, then divide it into the measured flow
	rate multiplied by the calibration temperature of the flow-
	meter in degrees kelvin. (nominal 25 degrees centigrade)
*/

    		corr *= STD_TEMP;
    		corr /= (ZERO_K + degree_c);   

/*
	read pressure - measure output of the KP100A pressure trans-
	ducer, scaled by the AMP_02. the scaling results in a range
	of 0 to 25.5 psi, in 1/10 psi steps.
*/

    		ADCON = START_ADC0;
     		while(ADCON & ADCS) ;
     		psi = ((word) ADDATH << 8) | ADDATL;

/*
	compensate cfm rate for pressure - multiply measured pres-
	sure and the calculated flow rate, and then divide it by
	the standard atmospheric pressure at sea-level. (nominal
	14.7 psi)

*/

    		corr *= psi;
    		corr /= STD_ATM;   
    		cfm = corr;

/*
	read setpoint pot to obtain setpoint in the range of
	0 - 25.5 cfm in 1/10 cfm steps.
*/

      		ADCON = START_ADC2;
     		while(ADCON & ADCS) ;
      		setpoint = ADAT;

/*
	test if cfm rate greater or equal to the
	setpoint, and if so then energize relay
*/

      		if(setpoint > cfm)
			RELAY = 0;
	       	else
	       	       	RELAY = 1;

/*
	test if update flag has been set, and if so reset flag.
*/

		if(UPDATE)
		{
			UPDATE = 0;

/*
	then test if the no flow flag has been set. if so then
	display 00.0 cfm
*/

			if(NO_FLOW)
			{
 				display0 = ~CFM;
 				display1 = ~segments[0];
 				display2 = ~(segments[0] | SEG_DP);
 				display3 = ~segments[0];
 			}

/*
	if the no flow flag was not set then read the display
	select switches, and display the appropriate data.
*/

 			else if(SEL_0)
 			{
 				if(SEL_1)
 				{

/*
	if no swich is depressed then the default display is
	the flow rate in cfm. test the flowrate is greater than
	or equal to 30 cfm then display the overrange message
	EEE else the flow in XX.X format.
*/

					if(cfm <= 300)
					{
 			        	  	display0 = ~CFM;
 						display1 = ~segments[cfm % 10];
 						cfm /= 10;
 						display2 = ~(segments[cfm % 10]);
 						cfm /= 10;
 						display3 = ~segments[cfm % 10];
					}
					else		    
					{		    
					 	display0 = ~CFM;
 						display1 = ~segments[10];
 						display2 = ~segments[10];
 						display3 = ~segments[10];
					}
 				}

/*
	if switch 1 is depressed then display temperature.
*/

 				else
 				{	
 					display0 = ~DEGREES;
 					display1 = ~segments[degree_c % 10];
 					degree_c /= 10;
 					display2 = ~(segments[degree_c % 10] | SEG_DP);
 					degree_c /= 10;
 					display3 = ~segments[degree_c % 10];
 				}
 			}
 			else
 			{

/*
	if switch 2 depressed then display the pressure.
*/

 				if(SEL_1)
 				{
 					display0 = ~PSI;
 					display1 = ~segments[psi % 10];
 					psi /= 10;
 					display2 = ~(segments[psi % 10] | SEG_DP);
 					psi /= 10;
 					display3 = ~segments[psi % 10];
 				}

/*
	if switch 3 depressed then display the setpoint.
*/

 				else
 				{
 					display0 = ~SETPOINT;
 					display1 = ~segments[setpoint % 10];
 					setpoint /= 10;
					display2 = ~(segments[setpoint % 10] | SEG_DP);
					setpoint /= 10;
					display3 = ~segments[setpoint % 10];
				}
			}
		}
	}
#endif
}