//
// PassageNiveau.c
//
// Programme de contrôle du passage à niveau.
//
// 2010.06.12 MHP Création.
// 2011.06.14 MHP Premiers tests concluants de commande du servo-moteur.
// 2011.06.20 MHP Utilisation des protothreads PC (Adam Dunkels,
adam@sics.se).
// 2011.06.22 MHP Premier essai des prothothreads AVR.
// 2011.06.24 MHP Correction des timings ville et prise en compte du transistor de sortie (inverser PWM).
// 2011.07.06 MHP Configuration des entrées/sorties définitive!
// 2011.07.07 MHP Réglage des délais pour la ville.
// 2011.09.10 MHP Raccourcissement de la période et attente avant de redécter le train au PN ville.
// 2011.12.20 MHP Suppression de l'anti-rebond pour la détection des trains et ralentissement des mouvements
// des barrières.
// 2012.04.01 MHP Suppression du délai entre 2 détections PN ville car nouveaux circuits de détection unidirectionnels.
//
// Directives de compilation: PC ou AVR.
//
// Includes standard: types, IO.
#ifdef PC
#include <stdint.h>
#include <stdio.h>
#endif
#ifdef AVR
#include <inttypes.h>
#include <avr/io.h>
#endif
// Protothreads.
#include "pt.h"
static struct pt ptGererSignalVille, ptGererBarrieresVille, ptGererSignalGare;
// Timers.
typedef uint16_t tTimer;
static tTimer tmrBaisserBarrieresVille, tmrBarrieresVille, tmrClignSignalVille, tmrMvtBarrieresVille;
static tTimer tmrGareA, tmrGareB, tmrClignSignalGare;
// Tous les délais sont exprimés nombres de périodes de PERIODE millisecondes.
// Période en ms.
#define PERIODE 10
// La durée durant laquelle le signal fonctionne est exprimée en nombre d'itérations
// plutôt qu'à l'aide d'un timer.
#define DELAI_CLIGN_VILLE (300/PERIODE)
#define DUREE_SIGNAL_VILLE (14000/PERIODE)
#define NB_ITER_SIGNAL_VILLE (DUREE_SIGNAL_VILLE/(2*DELAI_CLIGN_VILLE)+1)
#define DELAI_BAISSER_BARRIERES_VILLE (400/PERIODE)
// La durée durant laquelle le signal fonctionne est exprimée en nombre d'itérations
// plutôt qu'à l'aide d'un timer.
#define DELAI_CLIGN_GARE (300/PERIODE)
#define DUREE_SIGNAL_GARE (8000/PERIODE)
#define NB_ITER_SIGNAL_GARE (DUREE_SIGNAL_GARE/(2*DELAI_CLIGN_GARE))
// Le délai lorsque les barrières sont à nouveau levées est plus grand que le délai entre
// le début du signal de ville et la descente des barrières.
#define DELAI_BARRIERES_VILLE (DUREE_SIGNAL_VILLE - 5*DELAI_BAISSER_BARRIERES_VILLE)
#define DELAI_SERVO (60/PERIODE)
// Constantes communes PC et AVR
// Spécifique AVR.
#ifdef AVR
#define F_CPU 1000000UL
#include <util/delay.h>
// Configuration des ports
#define INPUT_VILLE PD1
#define INPUT_GARE_A PD2
#define INPUT_GARE_B PD3
#define INPUT_ATTENTE_A PD4
#define INPUT_ATTENTE_B PD5
#define OUTPUT_SERVO PB3
#define OUTPUT_SIGNAL_VILLE PB1
#define OUTPUT_SIGNAL_GARE PB0
#define CONFIG_DDRB (_BV(OUTPUT_SERVO)|_BV(OUTPUT_SIGNAL_VILLE)|_BV(OUTPUT_SIGNAL_GARE))
#define PASSAGE_VILLE (!(PIND & _BV(INPUT_VILLE)))
#define PASSAGE_GARE_A (!(PIND & _BV(INPUT_GARE_A)))
#define PASSAGE_GARE_B (!(PIND & _BV(INPUT_GARE_B)))
#define CONFIG_PULLUPD (_BV(INPUT_VILLE)|_BV(INPUT_GARE_A)|_BV(INPUT_GARE_B)|_BV(INPUT_ATTENTE_A)|_BV(INPUT_ATTENTE_B))
#define CONFIG_DDRD ~CONFIG_PULLUPD
#define ATTENTE_A (!(PIND & _BV(INPUT_ATTENTE_A)))
#define ATTENTE_B (!(PIND & _BV(INPUT_ATTENTE_B)))
#define SetClignVille (PORTB |= _BV(OUTPUT_SIGNAL_VILLE))
#define ClrClignVille (PORTB &= ~_BV(OUTPUT_SIGNAL_VILLE))
#define SetClignGare (PORTB |= _BV(OUTPUT_SIGNAL_GARE))
#define ClrClignGare (PORTB &= ~_BV(OUTPUT_SIGNAL_GARE))
#endif
#ifdef PC
// Pour simuler le passage des trains.
static uint8_t PASSAGE_VILLE, PASSAGE_GARE_A, PASSAGE_GARE_B, ATTENTE_A, ATTENTE_B;
#endif
#define MIN_SERVO 1000
#define MAX_SERVO 1900
#define PAS_SERVO 20
#ifdef AVR
#define CONFIG_TCCR1A (_BV(COM1A1)|_BV(WGM11))
// Pour le test, prescaler sur 1024.
#if 0
#define CONFIG_TCCR1B (_BV(CS12)|_BV(CS10)|_BV(WGM12)|_BV(WGM13))
#endif
// Fonctionnement normal, prescaler sur 1.
#define CONFIG_TCCR1B (_BV(CS10)|_BV(WGM12)|_BV(WGM13))
#define PERIODE_SERVO 20000
#endif
static PT_THREAD(GererSignalGare(struct pt *pt))
{
// On doit pouvoir traiter ces événements quelque soit l'endroit où
// on se trouve dans le protothread.
if (ATTENTE_A && (tmrGareA > 0))
{
#ifdef PC
printf("Train en attente gare A\n");
#endif
tmrGareA = DUREE_SIGNAL_GARE;
} // if
if (ATTENTE_B && (tmrGareB > 0))
{
#ifdef PC
printf("Train en attente gare B\n");
#endif
tmrGareB = DUREE_SIGNAL_GARE;
} // if
PT_BEGIN(pt);
while (1)
{
PT_WAIT_UNTIL(pt, PASSAGE_GARE_A || PASSAGE_GARE_B);
if (PASSAGE_GARE_A && (tmrGareA == 0))
{
#ifdef PC
printf("Passage gare A\n");
#endif
tmrGareA = DUREE_SIGNAL_GARE;
} // if
if (PASSAGE_GARE_B && (tmrGareB == 0))
{
#ifdef PC
printf("Passage gare B\n");
#endif
tmrGareB = DUREE_SIGNAL_GARE;
} // if
while ((tmrGareA > 0) || (tmrGareB > 0))
{
#ifdef PC
printf("Signal gare ON\n");
#endif
#ifdef AVR
SetClignGare;
#endif
tmrClignSignalGare = DELAI_CLIGN_GARE;
PT_WAIT_UNTIL(pt, tmrClignSignalGare == 0);
#ifdef PC
printf("Signal gare OFF\n");
#endif
#ifdef AVR
ClrClignGare;
#endif
tmrClignSignalGare = DELAI_CLIGN_GARE;
PT_WAIT_UNTIL(pt, tmrClignSignalGare == 0);
} // while
} // while
PT_END(pt);
} // GererSignalGare
static PT_THREAD(GererSignalVille(struct pt *pt))
{
static uint16_t nIter;
PT_BEGIN(pt);
while (1)
{
PT_WAIT_UNTIL(pt, PASSAGE_VILLE);
for (nIter = 0; nIter < NB_ITER_SIGNAL_VILLE; nIter++)
{
#ifdef PC
printf("Signal ville ON\n");
#endif
#ifdef AVR
SetClignVille;
#endif
tmrClignSignalVille = DELAI_CLIGN_VILLE;
PT_WAIT_UNTIL(pt, tmrClignSignalVille == 0);
#ifdef PC
printf("Signal ville OFF\n");
#endif
#ifdef AVR
ClrClignVille;
#endif
tmrClignSignalVille = DELAI_CLIGN_VILLE;
PT_WAIT_UNTIL(pt, tmrClignSignalVille == 0);
} // for
#ifdef PC
printf("Fin signal ville\n");
#endif
} // while
PT_END(pt);
} // GererSignalVille
static PT_THREAD(GererBarrieresVille(struct pt *pt))
{
static uint16_t nLen; // Longueur de l'impulsion des servos.
PT_BEGIN(pt);
while (1)
{
PT_WAIT_UNTIL(pt, PASSAGE_VILLE);
#ifdef PC
printf("Attendre pour baisser les barrières\n");
#endif
tmrBaisserBarrieresVille = DELAI_BAISSER_BARRIERES_VILLE;
PT_WAIT_UNTIL(pt, tmrBaisserBarrieresVille == 0);
#ifdef PC
printf("Début baisser les barrières\n");
#endif
tmrBarrieresVille = DELAI_BARRIERES_VILLE;
nLen = MIN_SERVO;
while (nLen <= MAX_SERVO)
{
#ifdef PC
printf("Baisser barrières, servo: %0d\n", nLen);
#endif
#ifdef AVR
OCR1A = nLen;
#endif
nLen += PAS_SERVO;
tmrMvtBarrieresVille = DELAI_SERVO;
PT_WAIT_UNTIL(pt, tmrMvtBarrieresVille == 0);
} // while
#ifdef PC
printf("Barrières baissées\n");
#endif
PT_WAIT_UNTIL(pt, tmrBarrieresVille == 0);
nLen -= PAS_SERVO;
while (nLen >= MIN_SERVO)
{
#ifdef PC
printf("Lever barrières, servo: %0d\n", nLen);
#endif
#ifdef AVR
OCR1A = nLen;
#endif
nLen -= PAS_SERVO;
tmrMvtBarrieresVille = DELAI_SERVO;
PT_WAIT_UNTIL(pt, tmrMvtBarrieresVille == 0);
} // while
#ifdef PC
printf("Barrières levées\n");
#endif
} // while
PT_END(pt);
} // GererBarrieresVille
void main(void)
{
// Initialiser les protothreads.
PT_INIT(&ptGererSignalVille);
PT_INIT(&ptGererBarrieresVille);
PT_INIT(&ptGererSignalGare);
// Configuration spécifique AVR.
#ifdef AVR
DDRD = CONFIG_DDRD;
PORTD = CONFIG_PULLUPD;
DDRB = CONFIG_DDRB;
ICR1 = PERIODE_SERVO;
OCR1A = MIN_SERVO;
TCCR1A = CONFIG_TCCR1A;
TCCR1B = CONFIG_TCCR1B;
#endif
#ifdef PC
uint16_t nIter;
//PASSAGE_VILLE = 1;
PASSAGE_GARE_A = 1;
for (nIter = 0; nIter <= 1000; nIter++)
{
printf("Temps: %0000d\n", nIter * PERIODE);
if (nIter == 2)
PASSAGE_GARE_A = 0;
if (nIter == 40)
{
printf("ATTENTE_A = 1\n");
ATTENTE_A = 1;
}
if (nIter > 45)
ATTENTE_A = 0;
if (nIter == 50)
{
printf("PASSAGE_GARE = 1\n");
PASSAGE_GARE_B = 1;
}
if (nIter > 50)
PASSAGE_GARE_B = 0;
#endif
#ifdef AVR
while (1)
{
#endif
// Mettre à jour tous les timers.
if (tmrBaisserBarrieresVille > 0) tmrBaisserBarrieresVille--;
if (tmrBarrieresVille > 0) tmrBarrieresVille--;
if (tmrClignSignalVille > 0) tmrClignSignalVille--;
if (tmrMvtBarrieresVille > 0) tmrMvtBarrieresVille--;
if (tmrGareA > 0) tmrGareA--;
if (tmrGareB > 0) tmrGareB--;
if (tmrClignSignalGare > 0) tmrClignSignalGare--;
// Traiter les événements.
GererSignalVille(&ptGererSignalVille);
GererBarrieresVille(&ptGererBarrieresVille);
GererSignalGare(&ptGererSignalGare);
#ifdef AVR
_delay_ms(PERIODE);
#endif
} // while, for
} // main