Anda di halaman 1dari 8

1:

/*
2:
* final.c
3:
*
4:
*
5:
* Created by Cliff Jao and Xi Guo on 4/14/08.
6:
*
7:
* Voltage on A0
8:
* Current on A1
9:
*
10:
* Serial commands:
11:
* TIME <long seconds>
12:
* RELAY <0/1>
13:
* THRESHOLD <watts>
14:
*/
15:
16: #include <Mega32.h>
17: #include <stdio.h>
18: #include <math.h>
19: #include <string.h>
20:
21: #define SAMPLES 1000
22: #define t1 1000 // 1000 ms.
23: #define t2 1 // 1 ms
24: #define t3 1 // 1 ms
25: #define R_SENSE 0.2
26: #define Vref 5.0
27:
28: char *cmds[] = {"TIME", "RELAY", "THRESHOLD"};
29: #define TIME 0
30: #define RELAY 1
31: #define THRESHOLD 2
32:
33: long FP_ADC_CONV, FP_OFFSET;
34:
35: ////// 20:12 fixed point macros
36: #define int2fix(a)
(((long)(a))<<12)
//Convert char
to fix. a is a char
37: #define float2fix(a) ((long)((a)*4096.0)) //Convert float
to fix. a is a float
38: #define fix2float(a) ((float)(a)/4096.0) //Convert fix
to float. a is an int
39: #define multfix(a,b)
((long)((((long)(a))*((long)(b)))>>12))
40:
41: long fpVSquareSum;
42: long fpISquareSum;
43: long fpPowerSum;
44: float rPower, aPower;
45: float powerFactor;

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:

float iScaleFactor, vScaleFactor, rpScaleFactor;


///// Periods //////
long fpVLastValue;
unsigned long vPeriodSum;
int vLastZeroMsec;
unsigned int vPeriodCount;

///// Watt Hour Stuff ////


float kWattHrs;
unsigned char r_index, r_buffer[40], r_ready, r_char;
unsigned char t_index, t_buffer[350], t_ready, t_char;
void gets_init();
void puts_init();
char time0, time1, time2, time3;
unsigned int sample;
// seconds since January 1, 1970 (UNIX time)
unsigned long unixtime;
unsigned int msecs;
unsigned long offTime;
unsigned long onTime;
long threshold; // power limit
char shutdown; // whether to shut down the relay
void
void
void
void

task1();
task2();
task3();
initialize();

void main() {
initialize();
// launch tasks if necessary
while(1) {
if (time1 == 0) task1();
if (time2 == 0) task2();
if (time3 == 0) task3();
}
}
void task3() {
int int_param, i;

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:

char cmd;
char cmdStr[50];
char param[50];
char *space;
int spaceIndex;
time3 = t3;
// return if not ready yet
if (r_ready != 1) return;
// try to find space
space = strchr(r_buffer, ' ');
if (space != NULL) {
// space was found, extract param
spaceIndex = space - r_buffer;
strncpy(cmdStr, r_buffer, spaceIndex);
cmdStr[spaceIndex] = '\0';
strcpy(param, space + 1);
}
else
{
// space not found, just copy over
strcpy(cmdStr, r_buffer);
}
// cmd will be -1 if no command
cmd = -1;
for (i = 0; i < 3; i++) {
if (!strcmp(cmdStr, cmds[i]))
{
cmd = i;
break;
}
}
switch(cmd) {
case TIME:
sscanf(param, "%ld", &unixtime);
msecs = 0;
break;
case RELAY:
sscanf(param, "%d", &int_param);
if (int_param) shutdown = 0;
else shutdown = 1;
break;
case THRESHOLD:
sscanf(param, "%ld", &threshold);

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:

break;
}
//printf("CMD OK\n\r");
gets_init();
}
void task1() {
time1 = t1;
PORTD.2 = ~PORTD.2;
}
void task2() {
char Ain0, Ain1;
long fpVin0, fpVin1, fpVin, fpIin;
long fpAin0, fpAin1;
float vAvg, iAvg;
int vPeriod;
time2 = t2;
// start conversion for channel 0
ADMUX.0 = 0;
ADCSR.6 = 1;
// wait for conversion to finish
while (ADCSR.6);
// read Ain0
Ain0 = ADCH;
// start conversion for channel 1
ADMUX.0 = 1;
ADCSR.6 = 1;
// wait for conversion to finish
while (ADCSR.6);
// read Ain1
Ain1 = ADCH;
// go to 20:12 fixed point
fpAin0 = (long)Ain0 << 12;
fpAin1 = (long)Ain1 << 12;
// calculate Vin of the ADC
fpVin0 = multfix(fpAin0, FP_ADC_CONV) - FP_OFFSET;
fpVin1 = multfix(fpAin1, FP_ADC_CONV) - FP_OFFSET;

193:
// sum up power or squares
194:
fpPowerSum += multfix(fpVin0, fpVin1);
195:
fpVSquareSum += multfix(fpVin0, fpVin0);
196:
fpISquareSum += multfix(fpVin1, fpVin1);
197:
198:
///////// FREQUENCY CALCULATION //////
199:
if (fpVLastValue < 0 && fpVin0 >= 0) {
200:
// found a zero crossing from neg. to pos.!
201:
vPeriod = msecs - vLastZeroMsec;
202:
203:
// make sure it's not an edge
204:
if (vPeriod > 0) {
205:
vPeriodSum += vPeriod;
206:
vPeriodCount++;
207:
}
208:
209:
vLastZeroMsec = msecs;
210:
211:
}
212:
213:
fpVLastValue = fpVin0;
214:
///////////////////////////////////
215:
216:
sample++;
217:
218:
if (sample == SAMPLES) {
219:
// this only happens once a second,
220:
// so floating point mults should be okay
221:
vAvg = (float) sqrt(vScaleFactor * fpVSquareSum);
222:
iAvg = (float) sqrt(iScaleFactor * fpISquareSum);
223:
rPower = (float) rpScaleFactor * fpPowerSum; // watts
224:
aPower = vAvg * iAvg; // VA
225:
powerFactor = rPower / aPower;
226:
kWattHrs += rPower / 3600000.0;
227:
228:
sprintf(t_buffer,
"%ld:P%3.2f,S%3.2f,I%3.2f,V%3.2f,F%3.2f,E%f,R%3.2f\n\r",
229:
unixtime, rPower, aPower, iAvg, vAvg, 1000.0 *
(float)vPeriodCount
230:
/ (float)vPeriodSum, kWattHrs, powerFactor);
231:
puts_init();
232:
233:
if (rPower > threshold) shutdown = 1;
234:
235:
if (shutdown) PORTD.3 = 0; // turn relay off
236:
else PORTD.3 = 1;
237:
238:
// reset for next sample
239:
fpVSquareSum = 0;

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:

fpISquareSum
fpPowerSum =
vPeriodSum =
vPeriodCount
sample = 0;

= 0;
0;
0;
= 0;

}
}
// compare match interrupt
interrupt [TIM0_COMP] void timer0_compare(void) {
if (time1 > 0) --time1;
if (time2 > 0) --time2;
if (time3 > 0) --time3;
// update wall clock
msecs++;
if (msecs == 1000)
{
msecs = 0;
unixtime++;
}
}
void initialize() {
long t;
/////////////// TIMER 0 ///////////////////////
TIMSK = 2; // turn on timer 0 compare match ISR
OCR0 = 250; // sets compare to 250 ticks
TCCR0 = 0b00001011; // sets prescalar to 64
//set up UART
UCSRB = 0x18;
UBRRL = 103;
unixtime = 0;
msecs = 0;
DDRD = 0xFF; // output
PORTD.2 = 0;
PORTD.3 = 1; // turn relay on
threshold = 1000;
shutdown = 0;
kWattHrs = 0;
time1 = t1;
time2 = t2;

289:
vScaleFactor = 1002001.0 / (4096.0 * SAMPLES);
290:
iScaleFactor = 1 / (R_SENSE * R_SENSE) / (4096.0 *
SAMPLES);
291:
rpScaleFactor = 1001.0 / R_SENSE / (4096.0 * SAMPLES);
292:
293:
// internal Aref = Vcc, left adjust result
294:
ADMUX = 0b01100000;
295:
//enable ADC and set prescaler to 1/128*16MHz=125,000
296:
//and clear interupt enable
297:
ADCSR = 0b11000111;
298:
299:
// calculate conversion factor
300:
//FP_ADC_CONV = float2fix(Vref / 256.0);
301:
FP_ADC_CONV = float2fix(0.512 / 256.0); // opto
302:
//FP_I_CONV = float2fix(1 / R_SENSE);
303:
304:
FP_OFFSET = float2fix(0.256);
305:
#asm("sei")
306:
307:
gets_init();
308: }
309:
310:
//**********************************************************
311: //UART character-ready ISR
312: interrupt [USART_RXC] void uart_rec() {
313:
r_char=UDR;
//get a char
314:
//build the input string
315:
if (r_char != '\r') r_buffer[r_index++]=r_char;
316:
else {
317:
putchar('\n');
//use putchar to
avoid overwrite
318:
r_buffer[r_index]=0x00;
//zero terminate
319:
r_ready=1;
//signal cmd
processor
320:
UCSRB.7=0;
//stop rec ISR
321:
}
322: }
323:
324:
/**********************************************************/
325: //UART xmit-empty ISR
326: interrupt [USART_DRE] void uart_send() {
327:
t_char = t_buffer[++t_index];
328:
if (t_char == 0) {
329:
UCSRB.5=0; //kill isr
330:
t_ready=1; //transmit done
331:
}
332:
else UDR = t_char ;
//send the char

333: }
334:
335:
//**********************************************************
336: // -- non-blocking keyboard check initializes ISR-driven
337: // receive. This routine merely sets up the ISR, which
then
338: //does all the work of getting a command.
339: void gets_init() {
340:
r_ready=0;
341:
r_index=0;
342:
UCSRB.7=1;
343: }
344:
345:
//**********************************************************
346: // -- nonblocking print: initializes ISR-driven
347: // transmit. This routine merely sets up the ISR, then
348: //send one character, The ISR does all the work.
349: void puts_init() {
350:
t_ready=0;
351:
t_index=0;
352:
if (t_buffer[0]>0) {
353:
putchar(t_buffer[0]);
354:
UCSRB.5=1;
355:
}
356: }