Timer

article published on 28th October 2019 (last modification on 3rd August 2022)

During the construction of a rocket with the club SpaceCampus of the University of Bordeaux, I had to design and assemble a small circuit handling the opening of the parachute hatch.

The purpose of this circuit is to deploy the parachute at the right time, that is, when the rocket reaches the apogee. To do this, I chose to use a small microcontroller called PIC12F683. It detects when the rocket takes off thanks to a cable attached to the launch pad which disconnects from the PCB at launch. Then, the chip starts a countdown of 5.3 seconds before commanding the opening of the parachute hatch. This duration of 5.3 seconds was calculated using a simulation (Stabtraj).

This is what the PCB looks like when printed and when all the components are soldered:

timer

You will have noticed several connectors. As you can see in the diagram below, each one is labeled with a letter:

schema

Here is the signification of the letters:

As for the code, you can find it below. It is quite short, but it doesn't mean that it is uninteresting. Indeed, it directly manipulates certain low-level registers of the chip.

#include <xc.h>
#include <pic12f683.h>
#define _XTAL_FREQ 125000

// CONF
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Detect (BOR disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)

const unsigned char DUTY_CYCLE_START_VALUE = 31;
const unsigned char DUTY_CYCLE_END_VALUE = 62;

void setAngle(int angle) {
	int value = (int) ((angle + 90) / 180.0 * (DUTY_CYCLE_END_VALUE - DUTY_CYCLE_START_VALUE)) + DUTY_CYCLE_START_VALUE;
	CCPR1L = value >> 2;
	CCP1CON = (CCP1CON & 0b11001111) | ((value & 0b00000011) << 4);
}

void main(void) {
	INTCON     = 0b00000000; // disable interrupts
	IOC        = 0b00000000; // disable GPIO interrupts on change
	PIE1       = 0b00000000; // disable various interrupts
	OPTION_REG = 0b00001111; // weak pullups global enable,
	WPU        = 0b00110111; // individual weak pullups enabled
	OSCCON     = 0b00010001; // select internal oscillator and set it to 125Khz
	T1CON      = 0b10110111; // enable timer1 and set prescaler div. by 1
	T2CON      = 0b00000101; // enable timer2 and set prescaler div. by 4 and postscaler div. by 1
	CCP1CON    = 0b00001100; // Set PWM mode, active high
	ADCON0     = 0b00000000; // disable A/D converter
	ANSEL      = 0b00000000; // Disable analog assignment to pins
	CMCON0     = 0b00010111; // Disable comparator, use internal reference, invert output.
	CMCON1     = 0b00000000; // comparator gating timer 1 asynchronously
	VRCON      = 0b00100001; // Disable internal comparator Vref, use low range, set Vref to 0.15V
	WDTCON     = 0b00010100; // Assign the right prescaler value to the watchdog timer. Keep WTD off for now.
	GPIO       = 0b00110000; // Set output pins initially before enabling them.
	TRISIO     = 0b00011011; // GPIO first disabled, but assigned as follows

	PR2 = 155;

	// Close the parachute hatch.
	setAngle(30);
	// Turn the LED off.
	GP5 = 0;

	// If no jack is detected...
	if (!GP4) {
		// ...flicker the LED to signal the problem.
		while (1) {
			GP5 = 1;
			__delay_ms(150);
			GP5 = 0;
			__delay_ms(150);
		}
	}
    
	// Turn the LED on to signal that everything is good so far.
	GP5 = 1;

	while (1) {
		// If the jack was unplugged (rocket lifted off)...
		if (!GP4) {
			// ...wait 5.3 sec and then open the parachute hatch.
			__delay_ms(5300);
			setAngle(-150);
			exit(0);
		}
		__delay_ms(100);
	}
}

Finally, during the launch, the timer worked wonderfully and the parachute deployed on time, allowing a smooth and damage-free landing.