#pragma PL (60) #pragma PW (120) #pragma OT (3) #pragma ROM (SMALL) #include typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; #define TRUE 1 #define FALSE 0 #define ON 0 #define OFF 1 #define FLASH 2 /* parameters */ #define ONE_OVER_DELTA 128 #define ONE_SECOND 14 /* timers */ /* 1 cpu cycle = 1.085uS */ /* 1 tic = 0xffff cpu cycles */ /* 1 "second" = 14 tics = 995.5uS */ #define MAX_BATT_PERIOD 5530 /* 60ms period, 0.9 volts */ #define MIN_BATT_PERIOD 430 /* 4.67ms period, 10 volts */ #define DEAD_MAN_TIMEOUT 2712 /* 45 minutes */ #define MAINTAINANCE_PERIOD 500 /* 1 pulse in 500 Seconds */ #define INITIALISATION_TIME 20 /* errors */ #define BATTERY_VOLTAGE_OUT_OF_RANGE 0x01 #define BATTERY_CHARGED 0x02 #define DM_TIMEOUT 0x03 /* states */ #define FAULT 0x01 #define INITIALIZING 0x02 #define CHARGING 0x03 #define DONE 0x04 /* global variables */ byte tic; byte state; word seconds; word this_period; word last1; word last2; word last3; word last4; word last5; word last6; word last7; word valley; sbit comp_out = 0x90; /* P1.0 */ sbit clear_cap = 0x93; /* P1.3 */ sbit charge = 0x97; /* P1.7 */ sbit fault_led = 0x80; /* P0.0 */ sbit charge_led = 0x82; /* P0.2 */ word measure_batt(void) { byte tic_now; word interval; tic_now = tic; interval = 0; clear_cap = FALSE; while(!comp_out && tic==tic_now) interval++; clear_cap = TRUE; return (interval); } byte check_limits( word batt_period ) { if ((batt_period > MIN_BATT_PERIOD)&&(batt_period < MAX_BATT_PERIOD)) { return(FALSE); } else { return(BATTERY_VOLTAGE_OUT_OF_RANGE); } } word filter ( word last0 ) { word temp1, temp2, temp3, temp4; word result1, result2; temp1 = ((last0 / 2) + (last1 / 2)); temp2 = ((last2 / 2) + (last3 / 2)); temp3 = ((last4 / 2) + (last5 / 2)); temp4 = ((last6 / 2) + (last7 / 2)); result1 = ((temp1 / 2) + (temp2 / 2)); result2 = ((temp3 / 2) + (temp4 / 2)); last7 = last6; last6 = last5; last5 = last4; last4 = last3; last3 = last2; last2 = last1; last1 = last0; return((result1 / 2) + (result2 / 2)); } byte delta_peak ( word period ) { if (period < valley) valley = period; if (period > (valley + (valley/ONE_OVER_DELTA))) return (BATTERY_CHARGED); else return (FALSE); } byte watchdog ( word now ) { if (now < DEAD_MAN_TIMEOUT) return (FALSE); else return (DM_TIMEOUT); } void charger ( void ) { this_period = measure_batt(); this_period = filter(this_period); switch (state) { case FAULT: { if (!check_limits(this_period)) { seconds = 0; state = INITIALIZING; } else state = FAULT; break; } case INITIALIZING: { if (check_limits(this_period)) state = FAULT; else { charge = TRUE; if (seconds < INITIALISATION_TIME) state = INITIALIZING; else { valley = 0xffff; state = CHARGING; } } break; } case CHARGING: { if (check_limits(this_period)) state = FAULT; else { if (!watchdog(seconds)) { if (delta_peak(this_period)) { state = DONE; seconds = 0; } else { state = CHARGING; charge = TRUE; } } else { state = DONE; seconds = 0; } } break; } case DONE: { if (check_limits(this_period)) state = FAULT; else { if(seconds < MAINTAINANCE_PERIOD) { charge = TRUE; seconds = 0; } state = DONE; } break; } } } void leds ( void ) { switch (state) { case FAULT: { charge_led = OFF; fault_led = ON; break; } case INITIALIZING: { charge_led = ON; fault_led = OFF; break; } case CHARGING: { charge_led = ON; fault_led = OFF; break; } case DONE: { charge_led = !charge_led; fault_led = OFF; break; } } } /* Timer 0 interrupt */ void timer0(void) interrupt 1 { tic++; } void main() { /* initialize pins */ charge=FALSE; charge_led = OFF; fault_led = OFF; /* initialize timer */ TR=1; CT=0; GATE=0; RTH=0; RTL=0; IT0 = TRUE; ET0=1; EA=TRUE; /* initialize globals */ tic=0; seconds = 0; valley = 0xffff; state = FAULT; /* main program scheduler */ while(1) { switch (tic) { case 0: { charger(); while (tic < 1); break; } case 7: { leds(); while (tic < 8); break; } case ONE_SECOND: { tic = 0; seconds++; break; } } } }