Timer

article publié le 28 octobre 2019

Pendant la construction d'une fusée avec le club SpaceCampus de l'Université de Bordeaux, j'ai été amené à concevoir et assembler un petit circuit gérant l'ouverture de la trappe à parachute.

Le but de ce circuit est de déployer le parachute au bon moment, c'est-à-dire quand la fusée atteint l'apogée.
Pour ce faire, j'ai choisi d'utiliser un petit micro-contrôleur appelé PIC12F683. Il détecte quand la fusée décolle grâce à un câble jack attaché au pas-de-tir qui se déconnecte de la carte à ce moment-là. Ensuite, la puce lance un compte à rebours de 5.3 secondes avant de commander l'ouverture de la trappe à parachute. Cette durée de 5.3 secondes a été calculée à l'aide d'une simulation (Stabtraj).

Voici à quoi ressemble la carte une fois imprimée et une fois les composants soudés :

timer

Vous aurez remarqué plusieurs connecteurs. Comme vous pouvez le voir sur le schéma ci-dessous, chacun est labellisé d'une lettre :

schéma

Voici la signification des lettres :

Quant au code, le voici ci-dessous. Il est assez court, mais pas pour autant inintéressant. En effet, il manipule directement certains registres bas niveau de la puce.

#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);
	}
}

Enfin, lors du lancement, le circuit a fonctionné à merveille et le parachute s'est déployé à temps, permettant un atterrissage en douceur et sans dégât.