/* SW-COMPUTER Factory Control Program WWW.EXTREME-FIRE.COM Target controller = ATTINY85-20PU microcontroller from ATMEL. Clock speed = 8 MHz. Development platform = AVR Studio 4 Version 4.13 Service Pack 1 Build 557. C compiler = WinAVR 20070525 Programer = AVR Dragon Hardware Schematic = SW-COMPUTER all versions. Hardware Layout = SW-COMPUTER all versions. This program is fully released to the Public Domain by Terry Fritz 2007. History 001 - Initial release Nov. 23, 2007 Terry Fritz 002 - Next generation Nov. 25, 2007 Terry Fritz 002.40 - First real release. 002.41 - Fixed Vibration timing problem, set peak current to 250 amps. Dec. 26, 2007 9:24AM 002.42 - Added Temperature sensing. Dec. 26, 2007 1:10PM Known issues: To use pin 1 (AUX) the Reset Disable Fuse has to be set and the Debug Wire Enable Fuse has to be clear. ( RSTDISBL = 1 DWEN = 0 ) They use pin 1 by defalt and will keep the pin high if not fixed. Set BrownOut voltage to 4.3V in fuses. Future changes: None */ /* Include libraries */ #include /* For all the odd ATTINY stuff */ /* Define ATTINY85 ports (PBx) to the gun controls */ /* Note that these port numbers or NOT the physical pin numbers! */ #define Drain 2 /* FET drain voltage port */ #define Aux0 3 /* AUX 0 I/O port */ #define Trigger 4 /* Trigger voltage port */ #define Aux1 5 /* AUX 0 I/O port */ #define Ground 10 /* Internal A/D ground used for calibration */ #define Temperature 11 /* Internal temperature probe. Only use in mode 2 */ /* Variable definitions */ #define VersionNumber 0x24 /* Software version number programed to EEPROM */ #define HighBatteryVoltage 16000 /* In mV */ #define LowBatteryVoltage 7000 /* In mV */ #define TriggerFiringVoltagePercent 80 /* Perent */ #define BatteryVoltageDroopWarningPercent 85 /* Percent */ #define TriggerHoldVoltage 3000 /* In mV */ #define DrainCurrentPeakLimit 250 /* In Amps */ #define RDSon 2870 /* In uOhms */ #define TemperatureLimit 75 /* In Celcius */ #define BreakTime 100 /* mS */ #define VibrateFrequency 40 /* Hz */ #define Normal 1 /* These are GunModes made easy to read */ #define ThreeRound 2 #define ThreeRoundAuto 2 #define SemiOnly 3 /* Semi Only gun function */ /* Function prototypes */ void MotorOFF(void); /* Turns the motor off */ void MotorON(void); /* Turns the motor on */ void BreakOFF(void); /* Turns the break off */ void BreakON(void); /* Turns the break on */ void EnergizeFETs(void); /* Enables the FETs in a controled way */ void Timer(long Time); /* A mS timer Timer(123) = 123mS */ void FastTimer(long Time); /* An unclaibrated ~15uS fast timer */ long GetVoltage(unsigned char Sensor, unsigned char ADCRange); /* Gets the Voltage (in mV) from the chosen source (Drain, Trigger, Aux) */ void Vibrate(void); /* Vibrates the gun's motor for signaling the user */ void CalibrateAtoD(void); /* Calibrates A/D convertor */ void EEPROM_write(unsigned char ucAdress, unsigned char ucData); /* Write to EEPROM */ unsigned char EEPROM_read(unsigned char ucAddress); /* Read from EEPROM */ void ProgramEEPROM(void); /* User programming of the EEPROM */ void ReadEEPROM(void); /* Get stored EEPROM data */ void SetBurstTime(long ShotCounter); /* Set burst time function */ void MotorPWM(char PWMduty); /* Motor PWM function */ void SetAUXPorts(void); /* Setup AUX ports */ void FactoryDiagnostics(void); /* Factory test */ /* Initialize variables */ /* long is a 4 byte integer */ long BatteryVoltageDroopWarning = 5500;/* mV */ long TriggerFiringVoltage = 6000; /* mV */ long InitialBatteryVoltage = 0; /* mV */ long BurstTimeFactor = 80; /* The single to three round burst ratio DEFAULT if EEPROM = FF*/ /* 100 = 3.00 X the single shot time. 2X+100% */ long BurstTimeFactorPercent = 0; /* Real BurstTimeFactorPercent */ unsigned char MotorSpeed = 100; /* 0 to 254 PWM value */ long VibrateTime = 500; /* Time the vibrator is on in mS*/ long SingleShotTime = 70; /* Default loops for single shot */ long BurstTime = 205; /* Default motor on time for a burst */ long TimeFactor = 100; /* Adjust for 1mS step. Magically, the calibration factor = 100 */ long SingleShotTimeOld = 0; /* Old value of single shot time */ long TimeFactorFast = 1; /* A sub mS timer counter */ unsigned char ErrorCode = 0; /* The Errors are each given a unique number */ long TriggerVoltage = 0; /* The voltage on the trigger input in mV */ long DrainCurrent = 0; /* The current through the drive FET in Amps */ long DrainVoltage = 0; /* The voltage on the MOSFET drains mV */ long counter2 = 0; /* Counter for Vibrate function */ long Time = 0; /* Variable for Timer function */ long counter = 0; /* Counter for Timer function */ unsigned char Sensor = 0; /* Input pin number for ADC */ long Voltage = 0; /* A/D convertor returned voltage in mV */ long count = 0; /* local counter */ long VoltageOffset0 = 0; /* A/D 5.0V REF offest error */ long VoltageOffset1 = 0; /* A/D 2.56V REF offest error */ long VoltageOffset2 = 0; /* A/D 1.1V REF offest error */ long MotorRunningLoopCounter = 0; /* Counts loops while firing */ unsigned char GunMode = Normal; /* 1=trigger control (Normal) 2=burst (ThreeRoundAuto) */ long ShotCounter = 0; /* Shot count inside a burst */ unsigned char TriggerHold = 0; /* Hold further shotting until trigger is released */ long ModeCounter = 0; /* A main loop counter for the threeround auto fuction */ unsigned char GunFunction = Normal; /* Operating mode DEFAULT if EEPROM = FF */ /* 1 = Normal 2 = ThreeRound 3 = Semi Only*/ unsigned char ucAddress = 0x00; /* For EEPROM functions */ unsigned char ucData = 0x00; /* For EEPROM functions */ unsigned char ADCRange = 0; /* 0 = 5.0V REF 1 = 2.56V REF */ long count1 = 0; /* Error loop counter */ long counter3 = 0; /* Timer counter */ long counter4 = 0; /* FastTimer counter */ long SBTCounter = 0; /* Burst time function counter */ unsigned char PWMduty = 0x00; /* Motor PWM control variable */ long counter5 = 0; /* Master Reset time counter */ long GunFunctionFlag = 0; /* Counter used in mode programing */ unsigned char BatteryVoltageEEPROM = 0; /* Stored initial battery voltage */ unsigned char DroopWarningFlag = 0; /* Droop warning counter */ long counter6 = 0; /* Motor softstart counter */ long RampSpeed = 0; /* MotorRampSpeed variable */ long TestValue = 0; /* Factory test variable */ unsigned char TestCode = 0; /* Facotry test variable */ unsigned char TestCounter = 0; /* Factory test counter */ int main(void) { /* MAIN POWER UP */ /* Wait 2 seconds for hardware to stabilize */ Timer(2000); ErrorCode = 1; GunMode = Normal; /* Setup A/D parameters */ CalibrateAtoD(); /* Check trigger voltage */ if (GetVoltage(Trigger,0) > 500) {ErrorCode = 4;} /* Get EEPROM data */ ReadEEPROM(); /* Energize drive circuits */ EnergizeFETs(); /* Setup AUX ports */ SetAUXPorts(); /* Check drain voltage */ DrainVoltage = (GetVoltage(Drain,0)); if (DrainVoltage < LowBatteryVoltage) {ErrorCode = 2;} if (DrainVoltage > HighBatteryVoltage) {ErrorCode = 3;} /* Set Battery Limits */ if (InitialBatteryVoltage == 0) {InitialBatteryVoltage = DrainVoltage;} TriggerFiringVoltage = (InitialBatteryVoltage * TriggerFiringVoltagePercent) / 100; BatteryVoltageDroopWarning = (InitialBatteryVoltage * BatteryVoltageDroopWarningPercent) / 100; if ((InitialBatteryVoltage > 10000) && (MotorSpeed = 0xFF)) {MotorSpeed = 100;} /* Slow motor down by default if high battery voltage */ /* Vibrate status to motor */ for (count1 = 0; count1 < ErrorCode; count1++) { Timer(500); Vibrate(); } /*Factory Test */ FactoryDiagnostics(); /* If the battery voltage is not safe, force a shutdown */ Halt: if (ErrorCode > 1) {goto Halt;} /* Error Codes 1 Normal operation 2 Battery voltage too low 3 Battery voltage too high 4 Trigger voltage too high 16 Low battery 17 High motor peak current 18 Overheating */ /* Wait for trigger pull to enter programming mode (2 seconds) */ for (count=0; count < 1185; count++) { if (GetVoltage(Trigger,0) > TriggerFiringVoltage) {ProgramEEPROM();} } /* MAIN SCANNING LOOP */ Vibrate();Vibrate();Vibrate();Vibrate(); MainLoop: ModeCounter++; /* Set motor to off no matter what is going on */ MotorOFF(); /* Check trigger voltage */ TriggerVoltage = GetVoltage(Trigger,0); if ((TriggerVoltage > TriggerFiringVoltage) && (TriggerHold == 0)) { /* Check trigger voltage incase the battery is dying. Check three times to stop false warnings */ if (TriggerVoltage < BatteryVoltageDroopWarning) {DroopWarningFlag++;} else {DroopWarningFlag = 0;} if (DroopWarningFlag > 2) {ErrorCode = 16;} goto Fire; } if (TriggerVoltage < 500) {TriggerHold = 0; GunMode = Normal; ModeCounter = 0;} /* Goto full auto in three round burst mode if trigger is held down 1/2 second longer */ if ((ModeCounter > 200) && (TriggerHold == 1) && GunFunction != 3) {GunMode = ThreeRoundAuto; goto Fire;} /* Return to top and loop again */ goto MainLoop; /* FIRING LOOP */ Fire: /* MOTOR IS ON!!!!! */ MotorON(); Timer(1); /* A delay to avoid the motor start up electrical noise burst */ ShotCounter = 0; MotorRunningLoopCounter++; /* increment loop counter */ ShotDetect: /* Main firing loop. */ ShotCounter++; TriggerVoltage = GetVoltage(Trigger,1); /* Get trigger voltage */ if (TriggerVoltage < TriggerHoldVoltage) /* Is trigger off now?*/ { if ((GunFunction == Normal) || (GunMode == ThreeRoundAuto)) {GunMode = Normal; goto CeaseFire;} /* normally just CeaseFire */ if (TriggerHold == 0) {goto CeaseFire;} } if ((GunMode == ThreeRoundAuto) || (GunFunction == Normal)) {goto ShotDetect;} /* Keep cycling in auto modes */ if (ShotCounter > BurstTime) {TriggerHold = 1; goto CeaseFire;} /* Three round time delay wait */ goto ShotDetect; /* FIRING HALT */ CeaseFire: /* The motor ON and OFF functions have a 1mS anti cross conduction safety delay built in */ /* Turn motor to off */ MotorOFF(); /* Turn break to on */ BreakON(); /* Leave the break on for some time in mS */ Timer(BreakTime); /* Turn break to off */ BreakOFF(); /* If in semi mode, set burst time */ if (TriggerHold ==0) {SetBurstTime(ShotCounter);} /* Check unit temperature */ if (GetVoltage(Temperature,2) > 283 + ((TemperatureLimit * 13) / 10)) {ErrorCode = 18;} ModeCounter = 0; /* If an error occured report it */ if (ErrorCode == 0) {goto MainLoop;} /* 16 - Low battery - Vibrate motor once after firing 17 - High motor peak current - Vibrate motor twice 18 - Overheating */ Timer(100); if (ErrorCode == 16) {Vibrate();} if (ErrorCode == 17) {Vibrate(); Timer(500); Vibrate();} if (ErrorCode == 18) {Vibrate(); Timer(500); Vibrate(); Timer(500); Vibrate();} ErrorCode = 0; goto MainLoop; } /* End of main */ /* FUNCTIONS */ /* For safety in that "nothing can go wrong", the motor drive ports are controlled directly */ void MotorOFF(void) { MotorPWM(0); } void MotorON(void) { PORTB = 0x01; /* Be REALLY(!!) sure break is off */ Timer(1); /* Wait 1mS for anti-cross conduction */ PORTB = 0x03; /* motor is on for peak current test */ Timer(1); /* Wait to stabalize */ /* Check drain current for over peak current limit */ DrainCurrent = GetVoltage(Drain,1); PORTB = 0x01; /* motor is off after test */ if ((DrainCurrent * 1000 / RDSon) > DrainCurrentPeakLimit) {PORTB = 0x01; ErrorCode = 17; return;} /* Shutdown if overcurrent */ // MotorPWM(MotorSpeed); MotorPWM(1); /* Soft Start */ for (counter6 = 0; counter6 < 51; counter6++) { RampSpeed = MotorSpeed / 2 + (MotorSpeed * counter6) / 100; OCR0B = (char)RampSpeed; } } void BreakOFF(void) {PORTB = 0x01;} /* The break signal is negative logic */ void BreakON(void) { PORTB = 0x01; /* Be REALLY(!!) sure motor is off */ Timer(1); /* Wait 1mS for anti-cross conduction */ PORTB = 0x00; /* The break signal is negative logic */ } void Timer(long Time) /* Timer(100) = 100mS */ {Time = Time * TimeFactor; for (counter3 = 0; counter3 <= Time; counter3++) {};} void FastTimer(long Time) /* Timer(50) = 672uS */ {Time = Time * TimeFactorFast; for (counter4 = 0; counter4 <= Time; counter4++) {};} void EnergizeFETs(void) { /* Energize break circuit */ /* Break is on PB0 */ PORTB = 0x00; /* Set pullups off */ DDRB = 0x01; /* Set port B pin 0 for output */ PORTB = 0x01; /* Set port B pin 0 to 1 and all others to 0 */ /* Wait 1000mS for capacitive break circuit to stabilize (very important!!) */ Timer(1000); /* Energize motor circuit */ /* Motor is on PB1 */ DDRB = 0x03; /* Set port B pins 0 and 1 for output */ PORTB = 0x01; /* Set port B pin 0 to 1 and pin 1 to 0 */ /* Wait 1mS */ Timer(1); } void SetAUXPorts(void) { /* Set AUX ports */ /* Turn on DB5 and DB3 for diagnostics */ DDRB = 0x2B; PORTB = 0x01; } long GetVoltage(unsigned char Sensor, unsigned char ADCRange) { /* Select input Source */ if (ADCRange == 0) /* 0-20V range */ { if (Sensor == Aux1) {ADMUX = 0x00;} if (Sensor == Drain) {ADMUX = 0x01;} if (Sensor == Trigger) {ADMUX = 0x02;} if (Sensor == Aux0) {ADMUX = 0x03;} if (Sensor == Ground) {ADMUX = 0x0D;} /* Internal ground for calibration */ } if (ADCRange == 1) /* 0-10.23V range */ { if (Sensor == Aux1) {ADMUX = 0x90;} if (Sensor == Drain) {ADMUX = 0x91;} if (Sensor == Trigger) {ADMUX = 0x92;} if (Sensor == Aux0) {ADMUX = 0x93;} if (Sensor == Ground) {ADMUX = 0x9D;} /* Internal ground for calibration */ } if (ADCRange == 2) /* 0-1.1V range */ { if (Sensor == Aux1) {ADMUX = 0x80;} if (Sensor == Drain) {ADMUX = 0x81;} if (Sensor == Trigger) {ADMUX = 0x82;} if (Sensor == Aux0) {ADMUX = 0x83;} if (Sensor == Ground) {ADMUX = 0x8D;} /* Internal ground for calibration */ if (Sensor == Temperature) {ADMUX = 0x8F;} /* Can only be used with 1.1V referance */ } /* Start A/D conversion */ ADCSRA = 0b11000110; /* Start A/D conversion (bit 6 is set) 125kHz clock*/ /* Test if done (bit 6 goes clear, but is set when A/D is complete) */ do {} while (bit_is_set(ADCSRA,6)); /* Get voltage Vref = 5000mV Rdivider = 1/4 Full range is 20V */ Voltage = ADCW; /* This word is the 10 bit A/D result */ if (ADCRange == 0) { Voltage = Voltage - VoltageOffset0; /* A/D Offset error adjustment */ if (Voltage < 0) {Voltage = 0;} Voltage = ((Voltage * 20000) / 1023); /* Convert A/D full range (1023) to 19980mV or 19.98V */ } if (ADCRange == 1) { Voltage = Voltage - VoltageOffset1; /* A/D Offset error adjustment */ if (Voltage < 0) {Voltage = 0;} Voltage = Voltage * 10; /* Convert A/D full range (1023) to 10230mV or 10.23V */ } if (ADCRange == 2) { Voltage = Voltage - VoltageOffset1; /* A/D Offset error adjustment */ if (Voltage < 0) {Voltage = 0;} Voltage = Voltage * 1100 / 1023; /* Convert A/D full range (1023) to 1100mV or 1.100V */ } return Voltage; } void CalibrateAtoD(void) { /* 5.0V REF Range = 20V */ VoltageOffset0 = 0; /* Clear old value */ VoltageOffset0 = GetVoltage (Ground, 0); /* Run the converter with grounded input */ VoltageOffset0 = ADCW; /* 2.56V REF Range = 10.23V */ VoltageOffset1 = 0; /* Clear old value */ VoltageOffset1 = GetVoltage (Ground, 1); /* Run the converter with grounded input */ VoltageOffset1 = ADCW; /* Get the raw A/D converter output word */ /* 1.1V REF Range = 1.1V */ VoltageOffset2 = 0; /* Clear old value */ VoltageOffset2 = GetVoltage (Ground, 2); /* Run the converter with grounded input */ VoltageOffset2 = ADCW; /* Get the raw A/D converter output word */ } void Vibrate(void) { /* Vibrate for 1/2 second */ BreakOFF(); Timer(1); for (counter2 = 0; counter2 < (VibrateFrequency * VibrateTime / 1000); counter2++) { PORTB = 0x03; FastTimer(20); /* Wait 500uS for motor on pulse */ PORTB = 0x01; Timer(1000 / VibrateFrequency); } } /* EEPROM stuff copied directly from ATMEL data sheet */ void EEPROM_write(unsigned char ucAddress, unsigned char ucData) { /* Wait for completion of previous write */ while (EECR & (1< TriggerFiringVoltage)) && (TriggerHold == 0)) { GunFunctionFlag++; GunFunction = GunFunctionFlag; if (GunFunction > 3) {GunFunction = 3;} /* limit is mode 3 */ count = 0; TriggerHold = 1; } } Vibrate();Timer(250);Vibrate(); /* Pull Trigger now to go to decrease BurstTimeFactor by number of trigger pulls. Limit = 0*/ for (count=0; count < 600; count++) { if (GetVoltage(Trigger,0) < 500) {TriggerHold = 0;} /* Tigger hold is a debounce for the trigger switch */ if (((GetVoltage(Trigger,0) > TriggerFiringVoltage) && (TriggerHold == 0) && (BurstTimeFactor > 0))) {BurstTimeFactor--; count = 0; TriggerHold = 1;} } Vibrate();Timer(250);Vibrate();Timer(250);Vibrate(); /* Pull Trigger now to go to increase BurstTimeFactor by number of trigger pulls. Limit = 250 */ for (count=0; count < 600; count++) { if (GetVoltage(Trigger,0) < 500) {TriggerHold = 0;} /* TiggerHold is a debounce for the trigger switch */ if (((GetVoltage(Trigger,0) > TriggerFiringVoltage) && (TriggerHold == 0) && (BurstTimeFactor < 250))) {BurstTimeFactor++; count = 0; TriggerHold = 1;} } Vibrate();Timer(250);Vibrate();Timer(250);Vibrate();Timer(250);Vibrate(); /* Pull Trigger now to go to decrease MotorSpeed by number of trigger pulls. Limit = 0*/ for (count=0; count < 600; count++) { if (GetVoltage(Trigger,0) < 500) {TriggerHold = 0;} /* Tigger hold is a debounce for the trigger switch */ if (((GetVoltage(Trigger,0) > TriggerFiringVoltage) && (TriggerHold == 0) && (MotorSpeed > 0))) {MotorSpeed = (MotorSpeed * 9) / 10; count = 0; SBTCounter = 0; TriggerHold = 1;} } Vibrate();Timer(250);Vibrate();Timer(250);Vibrate();Timer(250);Vibrate();Timer(250);Vibrate(); /* Pull Trigger now to go to increase MotorSpeed by number of trigger pulls. Limit = 255 */ for (count=0; count < 600; count++) { if (GetVoltage(Trigger,0) < 500) {TriggerHold = 0;} /* TiggerHold is a debounce for the trigger switch */ if (((GetVoltage(Trigger,0) > TriggerFiringVoltage) && (TriggerHold == 0) && (MotorSpeed < 255))) { if (MotorSpeed < 232) {MotorSpeed = (MotorSpeed * 11) / 10; count = 0; SBTCounter = 0; TriggerHold = 1;} else {MotorSpeed = 254;count = 0; SBTCounter = 0; TriggerHold = 1;} } } /* Store EEPROM data */ /* Gun Function */ EEPROM_write (0x01, (char)GunFunction); /* Burst time factor */ if (BurstTimeFactor < 1) {BurstTimeFactor = 1;} if (BurstTimeFactor >250) {BurstTimeFactor = 250;} EEPROM_write(0x02, (char)BurstTimeFactor); /* MotorSpeed */ if (MotorSpeed < 1) {MotorSpeed = 1;} if (MotorSpeed >254) {MotorSpeed = 254;} EEPROM_write(0x04, (char)MotorSpeed); BatteryVoltageEEPROM = (char)(InitialBatteryVoltage / 100); EEPROM_write(0x05, (char)BatteryVoltageEEPROM); Vibrate();Timer(250);Vibrate();Timer(250);Vibrate();Timer(250);Vibrate();Timer(250);Vibrate();Timer(250);Vibrate(); /* Pull Trigger now to go to Master Reset */ counter5 = 0; for (count=0; count < 600; count++) { while (GetVoltage(Trigger,0) > TriggerFiringVoltage) { counter5++; if (counter5 > 1500) { EEPROM_write(0x00,0xFF); EEPROM_write(0x01,0xFF); EEPROM_write(0x02,0xFF); EEPROM_write(0x03,0xFF); EEPROM_write(0x04,0xFF); EEPROM_write(0x05,0xFF); Vibrate();Vibrate();Vibrate();Vibrate();Vibrate();Vibrate();Vibrate();Vibrate();Vibrate();Vibrate(); Halt1: goto Halt1; } } } } void ReadEEPROM(void) { /* Note - Erased EEPROM = FF not 00 */ /* 0x00 = Version Number 0x01 = GunFunction 0x02 = BurstTimeFactor 0x03 = SingleShotTime 0x04 = Motor Speed 0x05 = Initial Battery Voltage / 100 */ /* Version */ EEPROM_write(0x00, (char)VersionNumber); /* Gun Function */ if (EEPROM_read(0x01) != 0xFF) {GunFunction = EEPROM_read(0x01);} /* Burst time factor */ if (EEPROM_read(0x02) != 0xFF) {BurstTimeFactor = EEPROM_read(0x02);} /* Single Shot Time */ if (EEPROM_read(0x03) != 0xFF) { SingleShotTime = EEPROM_read(0x03); SBTCounter = 0; BurstTimeFactorPercent = 2 * BurstTimeFactor + 100; BurstTime = (BurstTimeFactorPercent * 117 * SingleShotTime) / 120 / 100 + (37 * (BurstTimeFactorPercent - 100) / 120); if (GunFunction == 3) {BurstTime = SingleShotTime;} /* Semi only mode */ } /* Motor Speed */ MotorSpeed = EEPROM_read(0x04); /* 0x05 = Initial Battery Voltage / 100 */ if (EEPROM_read(0x05) != 0xFF) {InitialBatteryVoltage = EEPROM_read(0x05) * 100;} } void SetBurstTime(long ShotCounter) { SBTCounter++; /* Shot Three after gun is powered up is the golden shot */ if (SBTCounter == 3) {SingleShotTime = ShotCounter;} /* Do not update if ShotCounter is < 90% or > 110% of SingleShotTime (early user trigger release) */ if (SBTCounter > 3) { if ((ShotCounter > (SingleShotTime * 11) / 10) || (ShotCounter < (SingleShotTime * 9) / 10)) {return;} } else {SingleShotTime = ((SingleShotTime * 5) + ShotCounter) / (5 + 1);} /* SingleShotTime = 1.17 x ShotCounter + 37 in mS. BurstTime = 1.20 x ShotCounter + 37 in mS. BurstTime = BurstTimeFactor x 1.17 / 1.20 x SingleShotTime + 37 / 1.20 x (BurstTimeFactor - 1) */ BurstTimeFactorPercent = 2 * BurstTimeFactor + 100; BurstTime = (BurstTimeFactorPercent * 117 * SingleShotTime) / 120 / 100 + (37 * (BurstTimeFactorPercent - 100) / 120); if (BurstTime < SingleShotTime) {BurstTime = SingleShotTime;} /* Be sure a BurstTime error will not lock out the gun */ /* Store SingleShotTime now */ if (SingleShotTime < 0) {SingleShotTime = 1;} if (SingleShotTime >254) {SingleShotTime = 254;} if (SingleShotTime != SingleShotTimeOld) { EEPROM_write(0x03, (char)SingleShotTime); SingleShotTimeOld = SingleShotTime; } /* Semi only mode */ if (SBTCounter < 3) {BurstTime = 2 * SingleShotTime;} else { if (GunFunction == 3) {BurstTime = SingleShotTime - 2;} } } void MotorPWM(char PWMduty) /* Controlling OC0B which is pin 6 to the motor drive */ { if (PWMduty == 0) {TCCR0A = 0x03; GTCCR = 0x80; PORTB = 0x01; return;} /* Shutdown */ GTCCR = 0x81; /* HALT, SYNC, and RESET the PWM counter */ TCCR0A = 0x23; /* Enable PWMcontrol of motor and set function */ TCCR0B = 0x01; /* Divide by 8 for ~500hZ */ TCNT0 = (char)PWMduty; /* Zero the counter */ OCR0B = (char)PWMduty; /* This is the PWM comparator test value */ TIMSK = 0x08; /* Be sure the harware interupts are off but compare OS0B */ GTCCR = 0x00; /* Start the PWM */ } void FactoryDiagnostics(void) /* Factory test */ { /* Test for Trigger Key voltage */ TestValue = GetVoltage(Trigger,0); if ((TestValue < 4392) || (TestValue > 5368)) {return;} TestResult: TestCode = 1; PORTB = 0x01; /* Turn FETs off */ Timer(2000); TestValue = GetVoltage(Trigger,0); /* Trigger sense test */ if ((TestValue < 4734) || (TestValue > 5025)) {TestCode = 2;} TestValue = GetVoltage(Trigger,1); /* Trigger sense test */ if ((TestValue < 4734) || (TestValue > 5025)) {TestCode = 3;} TestValue = GetVoltage(Drain,1); /* Drain sense test */ if ((TestValue < 4734) || (TestValue > 5025)) {TestCode = 4;} PORTB = 0x03; /* Turn Q1 Drive FET on */ Timer(1); TestValue = GetVoltage(Drain,1); /* Q1 test */ if ((TestValue < 0) || (TestValue > 10)) {TestCode = 5;} PORTB = 0x01; /* Turn Q1 Drive FET off */ Timer(1); PORTB = 0x00; /* Turn Q2 Break FET on */ Timer(1); TestValue = GetVoltage(Drain,1); /* Q2 test */ if ((TestValue < 9801) || (TestValue > 10201)) {TestCode = 6;} PORTB = 0x01; /* Turn Q2 Break FET off */ Timer(1); /* Blink Error Code to AUX5 LED */ for (TestCounter = 0; TestCounter < TestCode; TestCounter++) { PORTB = 0x21; /* LED on */ Timer(500); /* Wait 500mS */ PORTB = 0x01; /* LED off */ Timer(500); /* Wait 500mS */ } if (TestCode != 1) { /* Output bad value visually in mS */ Timer(1500); PORTB = 0x21; /* LED on */ Timer(TestValue); PORTB = 0x01; /* LED off */ Timer(2000); } goto TestResult; /* Keep Flashing Code */ /* 1 = Normal 2 = 20V Trigger Voltage 3 = 10V Trigger Voltage 4 = Drain open circuit voltage 5 = Q1 FET drive 6 = Q2 FET drive */ } /* End of program */