Ce site contient essentiellement des notes de travail. Le contenu est en constante évolution, et loin d'être achevé. (+ d'infos)
La plupart des documentations informatiques sont orientées Debian / Ubuntu.

Electronique/Projets/RC-LedLights - Jeu de LEDs pour modèle réduit (PIC)

De Ordinoscope.net
Sauter à la navigation Sauter à la recherche

Introduction

RC-LedLights.jpg

Ce projet consiste à commander 4 voies de LED depuis une voie du récepteur d'un modèle réduit. Les voies de LEDs sont les suivantes:

  • GLOW (s'allume et s'éteint gentiment)
  • FLASH
  • PLAIN1 (ON/OFF)
  • PLAIN2 (ON/OFF)

Chaque voie de LED peut être réglée pour s'allumer à une position différente de la voie du récepteur.

Schéma

RC-LedLights-3D.png

RC-LedLights-schema.png

Code

/*
 * Filename:	lights1.c
 * Language:	C (CCS PCWHD 4.x)
 * Date:	2010-02-28
 * Version:	1.0
 * Author:	Jean-Christophe Heger <jcheger*at*ordinoscope*net>
 * License:	GPLv3 (http://www.gnu.org/copyleft/gpl.html)
 *
 * GPL means:
 * - share it
 * - modify it and share your updates
 * - keep the names of authors in the header
 *
 * ... just in case you've forgot to read the GPL license.
 *
 *
 * ==================
 * Projet description
 * ==================
 * This is designed for RC models using receiver channel. Depending on the pulse width, it will
 * light up 4 LED channels: GLOW (slowly ~4s), FLASH, PLAIN1 and PLAIN2 (ON/OFF).
 *
 *
 *           (-) ----------------o-----o--------------------------------o--------------\
 * Receiver  (+) ---o------------|-----|------\                         |              |
 *           (S) ---|-------\  ##### #####    |                         |              |
 *                  |       |  # R # # R #    |  #####################  |              |
 *                  |       |  # 1 # # 2 #    \--# Vdd (+)   Vss (-) #--/              |
 *                  |       |  ##### #####  /----# RA5           RA0 #-----------------|-- (GLOW)
 *                  |  ===  \----|-----o----|----# RA4    U1     RA1 #-----\           o-- (-)
 *                  \--o o-------o----------|----# RA3           RA2 #--\  |           |
 *                     SW1                  |    #####################  |  \-----------|-- (FLASH)
 *                                          |                           |              o-- (-)
 *                                          |                           |              |
 *                                          |                           \--------------|-- (PLAIN1)
 * R1,R2 - 100 kOhms (pull-down)            |                                          o-- (-)
 * SW1 - press button                       |                                          |
 * U1 - PIC 12F629                          \------------------------------------------|-- (PLAIN2)
 *                                                                                     o-- (-)
 *
 * ======
 * Manual
 * ======
 * By default all LED channels will be up at 1400us. Each can be setup separately.
 * 
 * Press the button for about 2 seconds, and release it. The GLOW LED will light on. Set
 * your transmitter at the desired position and press the button. The FLASH LED will light
 * on. Do the same and so on. After PLAIN2, it will return at a usual cycle.
 *
 */

#include <12f629.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, NOBROWNOUT, PUT, NOMCLR
#use delay(clock=4000000)

#define PIN_GLOW   PIN_A0
#define PIN_FLASH  PIN_A1
#define PIN_PLAIN1 PIN_A2
#define PIN_PLAIN2 PIN_A5
#define PIN_BTN    PIN_A3
#define INT_BTN    INT_RA3
#define PIN_PWM    PIN_A4
#define INT_PWM    INT_RA4

#define GLOW_ADDR   0
#define FLASH_ADDR  2
#define PLAIN1_ADDR 4
#define PLAIN2_ADDR 6


// --------------------
// Variable declaration
// --------------------
short btn_state     = 0;
long  btn_counter   = 0;

short glow_state    = 0;
long  glow_min      = -1;

short flash_state   = 0;
long  flash_counter = 0;
long  flash_min     = -1;

short plain1_state  = 0;
long  plain1_min    = -1;

short plain2_state  = 0;
long  plain2_min    = -1;

int   menu_stage    = 0;
long  width         = 1500;		// default width
int   offset        = 100;		// default width offset (anti-glitch)

// --------------------
// Function declaration
// --------------------
void flash ();
void glow ();
void menu ();
void on_off ();
long read16 (int addr);
void read_min ();
void set_state ();
void write16 (int addr, long dbl);


// ---------
// Functions
// ---------

/*
 * LED flash function
 * @return void
 */
void flash () {
	if (flash_state == 0) return;
	if (flash_counter == 0) output_low (PIN_FLASH);
	flash_counter++;
	if (flash_counter > 30) {
		output_high (PIN_FLASH);
		flash_counter = 0;
	}
}

/*
 * LED glow function
 * @return void
 */
void glow () {
	if (glow_state == 0) return;
	long i = 0;
	while (i < 1000) {
		if (glow_state == 1) output_low (PIN_GLOW);
		if (glow_state == 1) delay_us (1000-i);
		if (glow_state == 1) output_high (PIN_GLOW);
		if (glow_state == 1) delay_us (i);
		i++;
	}

	delay_ms (200);

	while (i > 0) {
		if (glow_state == 1) output_high (PIN_GLOW);
		if (glow_state == 1) delay_us (i);
		if (glow_state == 1) output_low (PIN_GLOW);
		if (glow_state == 1) delay_us (1000-i);
		i--;
	}
}

/*
 * Button menu
 * @return void
 */
void menu () {
	menu_stage++;

	if (menu_stage == 1) {				// Menu start
		glow_state   = 0;
		flash_state  = 0;
		plain1_state = 0;
		plain2_state = 0;

		output_high (PIN_GLOW);
		output_low  (PIN_FLASH);
		output_low  (PIN_PLAIN1);
		output_low  (PIN_PLAIN2);
	}

	if (menu_stage == 2) {
		glow_min = width - offset;
		write16 (GLOW_ADDR, glow_min);		// Set glow minimum width
		output_low  (PIN_GLOW);
		output_high (PIN_FLASH);
	}

	if (menu_stage == 3) {
		flash_min = width - offset;
		write16 (FLASH_ADDR, flash_min);	// Set flash minimum width
		output_low  (PIN_FLASH);
		output_high (PIN_PLAIN1);
	}

	if (menu_stage == 4) {
		plain1_min = width - offset;
		write16 (PLAIN1_ADDR, plain1_min);	// Set plain1 minimum width
		output_low  (PIN_PLAIN1);
		output_high (PIN_PLAIN2);
	}

	if (menu_stage == 5) {
		plain2_min = width - offset;
		write16 (PLAIN2_ADDR, plain2_min);	// Set plain2 minimum width
		output_low (PIN_PLAIN2);
		menu_stage = 0;
	}
}

/*
 * Activate LED functions if width is above minimum
 * @return void
 */
void on_off () {
	if (menu_stage > 0) return;

	if (width > glow_min) {
		glow_state = 1;
	} else {
		glow_state = 0;
		output_low (PIN_GLOW);
	}

	if (width > flash_min) {
		flash_state = 1;
	} else {
		flash_state = 0;
		output_low (PIN_FLASH);
	}

	if (width > plain1_min) {
		plain1_state = 1;
		output_high (PIN_PLAIN1);
	} else {
		plain1_state = 0;
		output_low (PIN_PLAIN1);
	}

	if (width > plain2_min) {
		plain2_state = 1;
		output_high (PIN_PLAIN2);
	} else {
		plain2_state = 0;
		output_low (PIN_PLAIN2);
	}
}

/*
 * Read double from EEPROM
 * @param  int  EEPROM base address
 * @return long
 */
long read16 (int addr) {
	int maj = read_eeprom (addr);
	int min = read_eeprom (addr+1);
	long dbl = maj * 256 + min;
	return dbl;
}

/*
 * Read the minimum values from EEPROM and set static variables
 * @return void
 */
void read_min () {
	glow_min   = read16 (GLOW_ADDR);
	flash_min  = read16 (FLASH_ADDR);
	plain1_min = read16 (PLAIN1_ADDR);
	plain2_min = read16 (PLAIN2_ADDR);

	if (glow_min == -1) {				// Set default values on a fresh install
		write16 (GLOW_ADDR, 1500 - offset);
		glow_min = 1500 - offset;
	}

	if (flash_min == -1) {
		write16 (FLASH_ADDR, 1500 - offset);
		flash_min = 1500 - offset;
	}

	if (plain1_min == -1) {
		write16 (PLAIN1_ADDR, 1500 - offset);
		plain1_min = 1500 - offset;
	}

	if (plain2_min == -1) {
		write16 (PLAIN2_ADDR, 1500 - offset);
		plain2_min = 1500 - offset;
	}
}

/*
 * Write a double in EEPROM
 * @param  int    EEPROM base address
 * @param  double Value to write
 * @return void
 */
void write16 (int addr, long dbl) {
	int maj = dbl / 256;
	int min = dbl % 256;
	write_eeprom (addr,   maj);
	write_eeprom (addr+1, min);
}


#INT_RA
/*
 * PORTA interrupt
 * Read button state and PWM width
 * @return void
 */
void ra_isr () {

	if (btn_state == 0 && input (PIN_BTN)) {			// Button pressed
		btn_state = 1;
		enable_interrupts (INT_TIMER0);
	}

	if (input (PIN_PWM)) {						// Pulse up
		set_timer1(0);
		setup_timer_1 (T1_INTERNAL|T1_DIV_BY_1);
	}

	if (!input (PIN_PWM) && !input (PIN_BTN)) {			// Pulse down
		long pulse = get_timer1 () - 15;
		setup_timer_1 (T1_DISABLED);
		if (pulse > 767 && pulse < 2305) {
			width = pulse;
			on_off ();
		}
	}

	if (btn_state == 1 && !input (PIN_BTN)) {			// Button released
		btn_state = 0;
		if (menu_stage == 0) {
			if (btn_counter > 10) menu ();			// Menu start
		} else {
			if (btn_counter >= 1) menu ();			// Menu walk
		}
		btn_counter = 0;
	}
}

#INT_TIMER0
/*
 * Count how long the button is pressed down and timer for the LED flash function
 * @return void
 */
void timer0_isr () {
	if (btn_state == 1) btn_counter++;
	flash ();
}

void main () {
	setup_timer_0 (T0_INTERNAL | T0_DIV_256);
	set_timer0 (0);
	enable_interrupts (INT_TIMER0);
	enable_interrupts (INT_BTN);
	enable_interrupts (INT_PWM);
	enable_interrupts (GLOBAL);
	read_min ();
	on_off ();

	while (TRUE) {
		glow ();
		delay_ms (1000);
	}	
}