Transformation vehicule

Transformation vehicule

8) Yamaha RE, la programmation

Parce qu'un engin de ce genre ne se contruit pas d'un coup de baguette magique, je vais vous donner un petit aperçu des langages utilisés

 

Rappel: ce qui est impératif est d'identifier clairement les besoins.

Ces besoins ne sont pas fixes, ils évolueront (très) largement d'autant plus si "ça marche" , c'est pourquoi il faut s'appliquer à la logique du déroulement du programme. 

 

 

 

Tout d'abord une vue sur la petite prise qui permet la programmation du boitier principal:
(notez qu'on a en réalité pas besoin d'enlever le réservoir et le siège) 

 

 

 

Une vue de côté qui montre plus précisément cette prise qui se trouve dans le carénage
 

A) préparation logicielle des composants.

Les composants (tel qu'un microprocesseur) peuvent réaliser des tâches différentes selon leur configuration. 
C'est une opération relativement délicate car il faut comprendre comment fonctionnement ces composants même si, en réalité, on ne s'interresse qu'à certaines fonctions. C'est pourquoi il faut un logiciel de simulation faute de quoi le développement risque d'être très très long ... 

La yamaha RE qui utilise entre autres un PIC 18F4523 . Ce circuit a l'avantage de disposer de pas mal de ports d'entrées/sorties et de permettre une conversion analogique digitale plus précise que les autres (sur 12 bits).

Voici une partie de la configuration (les lignes sont le plus souvent commentées ce qui permet de retrouver rapidement le "sens" du programme):

'définition du sens des ports (entrée ou sortie)
TRISA = %00101111 ' PORT A (1=entrée, 0=sortie)
TRISB = %00011111 ' PORT B
TRISC = %00011000 ' PORT C 'note: il faut mettre Sda,Scl en entrée pour le module I2C
TRISD = %00110000 ' PORT D (bit 0 à 1 en mode simulation pour tests)
TRISE = %00000000 ' PORT E

'définition des sorties
LATA=%00010000 ' EN Lcd au niveau haut car actif front descendant
LATB=%00100000 ' RS Lcd au niveau haut car actif front descendant
LATC=%00000000
LATD=%00000000
LATE=%00000000

'pour info, lecture du port: ValeurDuportX = PortX
CMCON = 0X07 ' Turn off all comparators.
INTCON=0 'pas d'interruption
INTCON2.RBPU=1 ' pas de pull-up du port B
ADCON0 = 0x01 ' choix canal convertisseur A/D (ici=1)
ADCON1 = 0X00 ' Reset registre A/D 1.
ADCON1 = %1010 ' activation AN4,AN2,AN1,AN0
ADCON1.VCFG1=0 ' référence analogique - = gnd
'ADCON1.VCFG0=1 ' référence analogique + = AN3
ADCON1.VCFG0=0 ' référence analogique + = vcc
ADCON2=%10110101 'réglage du temps d'acquisition (16TAD, 1/16 fosc), chiffre justifié à droite
'autorisations interruptions
RCON.IPEN=1
INTCON.GIE=1
INTCON3.INT1IE = 0 ' interdit interruption RFID
INTCON3.INT0IE = 0 ' interdit interruption secondes
delay_ms(500) ' attend la stabilisation "électronique"
UART1_Init(9600) ' définit la valeur de vitesse pour la transmission vers l'afficheur OLED
delay_ms(100)

I2C1_init(100000) ' définit la vitesse pour les composants I2C
 ConfigurerPCA9554(0) ' configure le PCA9554 en 8 sorties
EcrirePCA9554(0) ' met à zéro les sorties

...............

B) définir les variables dites "globales" (=utilisées dans tout le programme) . Au fur et à mesure des besoins on en rajoutera d'autres. Notez que ces définitions se trouveront en réalité avant la configuration des composants donnée ci-dessus.

 

Voici ici des définitions 

'entrées
symbol CellVoltage = PORTA.0
symbol GlobalCurrent = PORTA.1
symbol GlobalVoltage = PORTA.2
symbol ADCRef = PORTA.3 'référence + du convertisseur
symbol Clk1Seconde = PORTB.0
symbol RFID = PORTB.1
symbol Chargeur = PORTB.2
symbol Clignotant = PORTB.3
symbol Phare = PORTB.4
'symbol SimuMode = PORTD.0
symbol Brake = PORTD.4
symbol NoMove = PORTD.5

'sorties
symbol LedKb = PORTC.1
symbol CdeBallast = PORTC.5
symbol TxOled = PORTC.6
symbol BrakeOut = PORTD.2
symbol AlarmeOut = PORTD.3
symbol ForcePower = PORTD.6
symbol PowerSyst = PORTD.7
symbol MutingAudio = PORTC.2

' Lcd module connections
dim LCD_RS as sbit at RB5_bit
LCD_EN as sbit at RA4_bit
LCD_D4 as sbit at RE0_bit
LCD_D5 as sbit at RE1_bit
LCD_D6 as sbit at RE2_bit
LCD_D7 as sbit at RC0_bit

dim LCD_RS_Direction as sbit at TRISB5_bit
LCD_EN_Direction as sbit at TRISA4_bit
LCD_D4_Direction as sbit at TRISE0_bit
LCD_D5_Direction as sbit at TRISE1_bit
LCD_D6_Direction as sbit at TRISE2_bit
LCD_D7_Direction as sbit at TRISC0_bit

'définition des constantes
Const AdressePCA9554= %01110000 '0 1 1 1 A2 A1 A0 RW (R si 1,w si 0)
const AdresseDS1338= %11010000 '1 1 0 1 0 0 0 RW
const Adresse24C512= %10100000 '1 0 1 0 A2 A1 A0 RW
const AdresseAD5241= %01011000 '0 1 0 1 1 A1 A0 RW
const AdressePic16F690SpeedKeyb= %11110000
const AdressePic16F690Feux= %10110000
const AdressePic16F690Leds= %00110000
'const AdresseCapteurTemp1=%1001101 'A5
const AdresseCapteurTemp1= %10011010
'const AdresseCapteurTemp2=%1001110 'A6
const AdresseCapteurTemp2= %10011110 'A7
const AdresseDistanceTotale =12
const AdresseDistanceTotaleD =14
'const AdresseRapportVitesse =16 '(et 17) rapport de conversion Vitesse (6.25 au départ)
'const AdresseRapportTension50V =18 '(et 19) rapport de conversion Tension (52 au départ)
'const AdresseRapportTension3V7 =20 '(et 21) rapport de conversion Tension (4.85 au départ)
'const AdresseRapportCourant =22 '(et 23) rapport de conversion courant (11.6 au départ)
'const AdressePointZeroCourant = 24 '(et 25) point de référence négatif/positif (1182 au départ)
const AdresseAmperesHeure =26 '(et 27)
const AdresseTempsCharge =28 '(et 29)
const AdresseCourbeCharge=200 '(500 points possibles, enregistrés en word)
'const AdresseCourbeCharge1 =700 '(500 points possibles, enregistrés en word)
const AdresseMinutesUtilisation=702
const AdresseSecondesUtilisation=704
const AdresseMinutesCharge=706
const RapportImpulsions=28

const Decalage=10
const delaiMinimumOLED=20

'définition des variables
dim ExValeur,EcartMax as longword 'pour test
dim FirstAllumage,FirstExtinction as boolean
dim MemoLastMode,comptdemo1,comptdemo2,comptdemo3,TempsCharge as word
dim OLEDstate,CodePerteClef as byte
dim ExHMinute,MinutesUtilisation,MinutesCharge,ExMinAff as word
dim NbreImpulsions,SecondeCourbeUtilisation as word
dim Puissance as word
dim bascule,StopTempsCharge,ResetMaxMemo,FlagDecalageCourbe as boolean
dim ModeVeille,DetectRFID,Firstprint,ResetSystem,Modedemo as boolean
dim ExPhare,OLEDeteint,FeuxBleusActifs,ResetCompt as boolean
dim Fonctions1,Fonctions2,FuturMode,SecondeRFID as byte
dim MemoSensCourant as byte
dim NumBat,Vitesse,NiveauPot,MemoVitesse,MemoTension,MemoCourant as byte
dim ExSecondeModeVeille,ExSecondeModeAttenteClef,ExSecondeModeRoute as byte
dim x1,y1,z1 as byte ' valeurs byte TRES LOCALES utilisées couramment
dim x2,y2,z2 as word ' valeurs word TRES LOCALES utilisées couramment
dim ExTension,ExAmperes as word
dim ValeurClavier as byte
dim RefSeconde as byte
dim HSeconde,HMinute,HHeure,HJourDeLaSemaine,HDate,HMois,HAnnee as byte
dim ExSeconde,ExMinutes as byte
dim CompteurSecondes,CompteurMinutes as word
dim RapportVitesse,RapportTension50V,RapportTension3V7,RapportCourant,PointZeroCourant as word
dim ValeurFloat,DistanceTotaleF as float ' nombre a virgule
dim TotalAmperes,DistanceTotale,DistanceTotaleD,x3,y3,z3 as longword
dim CompteurSecondesUtilisation as longword
dim TotalAHseconde as float
dim NiveauFeux as byte
dim SonsActifs,Regeneration,AffichageMini,IndicRecept,DelaiAlarmeCourt as boolean
dim XenonAbsent, LedsAux, VitesseLimitee as boolean
dim NumeroSelection8,NumeroParametre1,ModePrincipal as byte
dim NbreDistance as word

Dim DonneeCodee as byte[20] 'contient la donnée série à envoyer à l'afficheur OLED
'dim ExCel as byte[16] 'stockage ancienne Valeur cellule
Dim TPuissance as byte[300] ' courbe sur les 5 dernières minutes
Dim TVitesse as byte[300] ' courbe sur les 5 dernières minutes
................

C) la "colonne vertébrale" du programme 

Le principe de base est simple: il suffit de savoir ce qu'on veut faire ;-)

 

En gros: attendre qu'on allume la machine (en fait ce n'est pas le programme qui s'en chargera mais une bête clef et/ou des détecteurs), attendre qu'on présente la carte codée, autoriser le démarrage si c'est OK , éteindre la machine.

 

Au début on commence donc très simplement . Il ne faut donc pas croire que ce que vous voyez au final est l'oeuvre d'un génie ! 

Quand la base marche on rajoute simplement des gadgets. Le bricoleur pense (il pense beaucoup le bricoleur !) : "pourquoi ne pas ajouter un délai avant alarme ? un afficheur couleur ? une synthèse vocale ? un capteur RFID ? ......."


Ce qu'on voit au final n'est donc qu'un assemblage d'idées qui se sont ajoutées au fil du temps.

Mais il faut impérativement structurer faute de quoi les idées ne donneront absolument rien de concret.

On utilise notamment des "sous programmes", c'est à dire des instructions visant à utiliser chaque idée, chaque "façon de faire".

Par exemple voici comment on doit régler l'horloge pour qu'elle envoie une impulsion au microcontroleur principal toutes les secondes (les informations de vitesse, consommation... ne sont envoyées à l'afficheur que toutes les secondes)

 I2C1_start
I2C1_Wr(AdresseDS1338)
I2C1_Wr($07)
I2C1_Wr(%10010000)
I2C1_stop

 

Certes cela peut paraître court mais il faut imaginer que dans un programme qui va contenir quelques deux mille lignes ça ne va pas forcément être très clair. Par exemple c'est quoi le DS1338 ? pourquoi on y écrit $07 ? ... quand on écrit les lignes c'est qu'on vient de voir le fonctionnement du circuit en question mais, dix jours ou deux mois après, on risque d'avoir à se pencher à nouveau dessus pour comprendre ce qu'on avait fait.

Alors on ne fait pas tout à fait cela: ce même code va être déplacé dans un sous programme qui va faire exactement la même chose sauf qu'on ne la verra pas dans le code "principal" mais qu'on l'appelera en focntion de son utilité

sub procedure Configurer1hzHorloge
'configure le DS1338 pour avoir 1 hertz en sortie
I2C1_start
I2C1_Wr(AdresseDS1338)
I2C1_Wr($07)
I2C1_Wr(%10010000)
I2C1_stop
end sub

Le code "principal" va simplement faire un appel à cette procédure ainsi:
Configurer1hzHorloge

Plus clair y'a pas ;-) 

 

Bien sur, ceux qui ont une petite expérience savent que ce n'était pas crucial puisque'on ne s'amuse pas à configurer plusieurs fois l'horloge. Ce qui est crucial est d'utiliser des procédures pour tout ce qui est répétitif. Cependant, même dans le cas du non-répétitif, il peut être beaucoup plus intéressant d'agir ainsi parce que le code devient plus rapidement lisible.

 

Ci-dessous, une véritable procédure qui sera répétée chaque seconde et qui consiste à envoyer les données à l'afficheur OLED

 

sub procedure EcrireDonneeCodee
dim Cpt,xT as byte

UART1_Write (1)
UART1_Write (Fonctions1+Decalage)
UART1_Write (Fonctions2+Decalage)
if (ModePrincipal=5) then
UART1_Write (DonneeCodee[6]+Decalage) 'puissance
UART1_Write (DonneeCodee[8]+Decalage) 'vitesse
else
for Cpt=4 to 19
xT=DonneeCodee[Cpt]+Decalage
UART1_Write (xT)
next Cpt
LedKb=0
DonneeCodee[17]=0 'code vocal effacé
end if
Fonctions2= Fonctions2 and %11110111 ' stoppe le reset éventuel
LedKb=0
UART1_Write (2)
end sub

 

Revenons maintenant à nos moutons: de quoi est fait le programme principal ?

Pour essayer de ne pas trop alourdir, ne ne mets que le début et marque, en rouge, les éléments importants.

 

Pour les curieux qui se demandent pourquoi j'éteins l'afficheur OLED c'est fort simple: un afficheur OLED n'aime pas les états indéterminés, à savoir quand on ne le prévient pas et qu'on coupe le courant.  

while true 'boucle sans fin
ModePrincipal=0
FirstPrint=false
FirstAllumage=true
FirstExtinction=true
ParametrageOledEteindre
EcrireDonneecodee
delay_ms(1000)
ForcePower=1 'forcage alimentation
PowerSyst=0 'on coupe l'alim système
BrakeOut=0 'frein activé
ExAmperes=0
' Note: le ResetSystem n'est activé que dans le cas de la fin de veille (->arret) ou fin de charge (->éviter la triche)
ResetSystem=false
LireInfosEeprom
ExTension=0
ExPhare=0
StopTempsCharge=false
SecondeCourbeUtilisation=0
FlagDecalageCourbe=false

while ResetSystem=false
INTCON3.INT1IE = 1 ' autorisation interruption RFID
INTCON.INT0IE = 1 ' autorisation interruption secondes
ForcePower=1 'forcage alimentation
' controles hors boucle pour déclenchement immédiat
' code/phares
if (ModePrincipal>2) and (Phare<>ExPhare) then
if Phare then PassagePhare else PassageCode end if
ExPhare=Phare
end if

'opérations à chaque seconde
if CompteurSecondes<>ExSeconde then
INTCON3.INT1IE = 0 ' interdiction interruption RFID
INTCON.INT0IE = 0 ' interdiction interruption secondes
FuturMode=0 'indicateur pour changement de mode
ExSeconde=CompteurSecondes
LireDateHeure
LirePic16F690SpeedKeyb 'lit la Vitesse et donne l'état du clavier (ValeurClavier)
ExtraireValeursAnalyse
AfficherHeure
TraiterFonctionsClavier

'contrôle charge/arret charge
if Modeprincipal<>1 then
if Chargeur then
ModePrincipal=1
ForcePower=1 'forcage alimentation
delay_ms(500)
FirstPrint=false
end if
else 'mode charge
Lcd_Chiffre(4,1,2,NbreImpulsions)
if NbreImpulsions>0 then 'tentative pour vol en simulant charge
AlarmeOut=1
delay_ms(200)
AlarmeOut=0
end if
if not Chargeur then ' suite à charge, si chargeur n'est plus présent on arrête
EteindreMoto
end if
end if

'traitement selon le ModePrincipal
Select case ModePrincipal
case 0 'mode=attente clef
TraitementModeAttenteClef

case 1 'mode=charge
TraitementModeCharge

case 2 'mode=veille
TraitementModeVeille

case 3 'mode=route
TraitementModeRoute

case 4 ' mode affichage par cellules
if Vitesse>1 then FuturMode=3 end if ' retour affichage normal si vitesse
TraitementAffichageCellules

case 5 ' mode courbe de décharge
if Vitesse>1 then FuturMode=3 end if ' retour affichage normal si vitesse
TraitementAffichageCourbeUtilisation

end select

'mise à jour éventuelle des informations à transmettre toutes les minutes
Fonctions2=Fonctions2 and %10011111 'interdit l'affichage et l'avancée du temps
if ExMinutes<>CompteurMinutes then
if ModePrincipal=1 then 'mode charge
if not StopTempsCharge then
' si >57.6V on arrête le comptage de temps + éteindre ecran en attendant touche
if (DonneeCodee[6]=58) then 'and (DonneeCodee[7]>50)
indiquerFinCharge
else
if (MinutesCharge< 250) then
inc(MinutesCharge)
end if
Fonctions2=Fonctions2 or %01100000 'met bit affichage et incrémentation temps
end if
end if
else ' temps de décharge
inc(MinutesUtilisation)
if MinutesUtilisation> 250 then
MinutesUtilisation=0
end if
end if
ExMinutes=CompteurMinutes
end if 'fin de traitement à la minute

'mise à jour de l'information Puissance consommée (toutes les secondes)
if ModePrincipal>1 then
EnregistrerInformationsPuissanceVitesse
end if

EcrireDonneeCodee

'contrôle de changement de mode
if FuturMode>0 then
if ModePrincipal<>FuturMode then
delay_ms(500)
ModePrincipal=FuturMode
DetectRFID=false 'permet une nouvelle interruption
end if
FirstPrint=false 'on indique qu'il faudra recharger la page
end if

end if
wend

wend

Vous avez remarqué que les lignes sont en français-anglais.
J'utilise toujours cette façon de procéder pour des raisons simples: on voit rapidement ce qui a été mis par le programmeur par rapport au langage lui-même.

Voici le résumé de ce que fait le programme du PIC 18F4523 :
- se met en route dès qu'on alimente via un capteur de béquille et de mouvement 
- bloque l'alimentation en marche, même s'il n'y a plus de capteur activé, pendant un cycle d'alarme ou pendant la durée d'utilisation "légale" de la machine (si présentation de la "clef")
- gère l'affichage de l'information envoyée à l'afficheur OLED (programmé, lui, dans un autre langage proche du "C") 
- gère l'affichage de l'écran LCD  
- gère la présentation de la carte RFID (mise en route et veille seulement)
- gère l'extinction automatique de la machine, l'alarme ...
 
En fait il y également plusieurs options qui ne sont pas utilisées "pour le cas où " : on peut par exemple brancher un capteur de température externe, gérer des "cases à cocher" dans la partie OLED ...
 
Il est à noter que les messages vocaux ne sont pas gérés par ce circuit mais par l'afficheur OLED, le PIC18F4523 ne fait qu'envoyer des codes qui au circuit de l'OLED qui seront alors convertis en messages plus ou moins pré-enregistrés 

 

Mais il n'y a donc pas que ce PIC ! 

Le PIC 18F4523 est le microprocesseur principal, ou "maître"

En parallèle travaillent trois autres circuits:

 

- celui situé dans l'afficheur OLED

Programmé dans un langage proche du "C" il s'occupe de gérer l'affichage et générer des "messages" sonores. 

Son rôle est double: il est, disons, autonome dans le sens ou il est capable de certaines fonctions tout seul comme demander qu'on présente la carte en affichant une image mais, et c,est là le gros intérêt, il passe le plus clair de son temps à attendre un code qui lui dira quoi faire.

Ce code est normalement envoyé toutes les secondes.

Pourquoi pas dix fois par secondes ? c'est simple. On pourrait effectivement raccourcir cet espacement mais le problème double: d'abord il faut envoyer une ligne de données sur un port "série" ce qui est relativement long. Ensuite et surtout, il faut entre deux envois de lignes de données pouvoir faire tout ce qu'on a demandé ! si, par exemple, on fait du graphisme on n'aura absolument pas le temps de faire autre chose et on va se retrouver avec une moitié de travail ou, pire, avec un écran "bloqué".

Voici un extrait du code qui détaille les variables. Ceux qui connaissent remarqueront que le type de variable n'est pas identifié. La raison est fort simple: il n'y a qu'un seul type possible ici, l'octet.

 

#constant IndexChiffreJauneGros 53
#constant IndexChiffreJaunePetit 63
#constant IndexChiffreBleuGros 73
#constant IndexChiffreBleuPetit 83
#constant IndexChiffreViolet 93
#constant IndexChiffre3D 103
#constant PositionZoneSonX 50
#constant PositionZoneSonY 3
#constant IndexFinCharge 113
#constant IndexEtatCellules 114
#constant PositionXEtatfeux 205
#constant PositionYEtatfeux 20

#constant IndexDemo 115


//Fonctions1 . Utilisation: if ((Fonctions1 & Alim)>0) ...
#constant Alim 0b00000001
#constant Carte 0b00000010
#constant Alarme 0b00000100
#constant bit3 0b00001000
#constant Frein 0b00010000
#constant Clignot 0b00100000
#constant Phare 0b01000000
#constant CodePageAffichee 0b00001111
//Fonctions2
#constant FeuxBleus 0b00000001
#constant RecupCourbe 0b00000010
#constant ResetCourbe 0b00000100
#constant ResetOled 0b00001000
#constant Code7b 0b00010000 //bit code vocal
#constant Bit5 0b00100000 //divers
#constant Bit6 0b01000000 //divers

//index d'images

//variables

var DonneeSerie[20];
var PositionCarSerie,NotEnd;
var CompteurSecondesDecharge; //a effacer (pour test)
var TempsStartCourbe;
var c13,c14; //codes pour l'extraction série de valeurs numériques 16 bits ou plus
var options1,options2,ExOptions1,ExOptions2;
var Fonctions1,Fonctions2,CodeAux1;
var ModeAffichage,ExModeAffichage;
var ImgADR,ExAmperes;
var xG,yG,zG,PosCellV,EcartCell;
var exX,exY;
var Aheure,AheureD,MemAh,MemAhD;
var HeureCourbe,MinuteCourbe,SecondeCourbe; //,ClkSecondes;
var Tension,TensionD,MemTension,MemTensionD,TensionMin;
var TensionMinD,TensionMax,TensionMaxD,TotalMemTensionMax,TotalMemTensionMin;
var FlagPremiereTension,FlagTestModes;
var ExFeuxBleus;

var Vitesse,VitesseD,MemVitesse,VitesseMax,VitesseMaxD,TotalVitesseMax;


var Distance,DistanceD,MemDistance,MemDistanceD,FlagDistance,DistanceRef,DistanceRefD;

var Amperes,AmperesD,Signe,MemAmperes,MemAmperesD,TotalMemAmperes; //signe=-1 si nbre negatif
var CompteurSecondesCharge;

var MemBallast,MemPhare,MemFrein,MemClignot;
var MemoirePompeRouge,PositionBatterie,xBatterie,xdec,CompteurMinutes,ExTensionCharge,RefExTensionCharge;
var CompteurAlerteBatterie,MemChargeTerminee;
var TempoCourbeCharge;
var FlagInvalide;
var CellMin,CellMax;
var FlagDeconnecte;
var ExNumeroSelection;
var Puissance;

 

 Comme pour le cas du PIC "maître" , on utilise des sous programmes. Voilà celui qui se charge de dire des valeurs:

 

//--------------------------------------------------------------------
func DireValeur(var Chiffre,var Decimal)
// si Decimal=1 on dit le zéro éventuel des dizaines
var ExtraitChiffre,Reste,Nom,FlagSansUnite,FlagEt,TempoVar;

pin_LO(IO1_PIN); //priorité son OLED
pause(150);
ExtraitChiffre:=0;
Reste:=0;
FlagSansUnite:=0;
FlagEt:=1;
TempoVar:=900; // temporisation par défaut

if (Chiffre>-1)
if (Chiffre<32000) //sécurité: on ne peut pas avoir plus de 32000
if (Chiffre>999 ) //milliers
FlagEt:=0;
ExtraitChiffre:=Chiffre/1000; //chiffre des milliers

if (ExtraitChiffre==1) //cas où l'on doit raccourcir
TempoVar:=600;
else
if (ExtraitChiffre==14) //cas où l'on doit rallonger le délai
TempoVar:=1100;
else
if (ExtraitChiffre>16) //cas où l'on doit rallonger le délai
TempoVar:=1100;
endif
endif
endif
//
to (Nom),print(ExtraitChiffre,"000.wav");
file_PlayWAV(Nom);
pause (TempoVar);
Chiffre:=Chiffre-ExtraitChiffre*1000;
if (Chiffre==0)
FlagSansUnite:=1;
endif
endif

TempoVar:=600; // temporisation par défaut
if (Chiffre>99 ) //centaines
FlagEt:=0;
ExtraitChiffre:=Chiffre/100; //chiffre des centaines
if (ExtraitChiffre==1) //cas où l'on doit raccourcir le délai
TempoVar:=500;
endif
to (Nom),print(ExtraitChiffre,"00.wav");
file_PlayWAV(Nom);
pause (TempoVar);
Chiffre:=Chiffre-ExtraitChiffre*100;
if (Chiffre==0)
FlagSansUnite:=1;
endif
endif

TempoVar:=600; // temporisation par défaut
if (Chiffre>9 ) //dizaines
FlagEt:=0;
if (Chiffre<20 )
to (Nom),print(Chiffre,".wav");
file_PlayWAV(Nom);
pause (TempoVar);
FlagSansUnite:=1; // on interdit les unités
else
ExtraitChiffre:=Chiffre/10; //chiffre des dizaines
Chiffre:=Chiffre-ExtraitChiffre*10; // chiffre des unités
if (Chiffre==0)
FlagSansUnite:=1;
else
if (Chiffre==2)
TempoVar:=300; // on diminue le temps pour 20
endif
endif

if (ExtraitChiffre==7)
TempoVar:=730;
file_PlayWAV("60.wav");
pause (TempoVar);
Chiffre:=Chiffre+10;
if (Chiffre==11) //dire soixante ET onze
file_PlayWAV("et.wav");
pause(300);
endif
to (Nom),print(Chiffre,".wav");
file_PlayWAV(Nom);
pause (TempoVar);
FlagSansUnite:=1;
else
if (ExtraitChiffre==9)
file_PlayWAV("80.wav");
pause (TempoVar);
Chiffre:=Chiffre+10;
to (Nom),print(Chiffre,".wav");
file_PlayWAV(Nom);
pause (TempoVar);
FlagSansUnite:=1;
else
if ((ExtraitChiffre==6)||(ExtraitChiffre==5))
TempoVar:=730; // on augmente la tempo pour 50
endif

to (Nom),print(ExtraitChiffre,"0.wav");
file_PlayWAV(Nom);
pause (TempoVar);
endif
endif
endif
else //le chiffre est inferieur à 10
if (Decimal==1)
file_PlayWAV("0.wav");
pause(600);
endif
endif

if (FlagSansUnite==0)
if (Chiffre==1)
if (FlagEt==0)
file_PlayWAV("et.wav");
pause(300);
endif
endif
to (Nom),print(Chiffre,".wav");
file_PlayWAV(Nom);
pause (600);

endif
endif
//si chiffre négatif -> on n'affiche pas
endif

endfunc

 

- un PIC 16F690 qui va calculer la vitesse et regarder le clavier

 

Pourquoi ?

parce que l'interprétation de la vitesse se fait à partir du nombre d'implusions renvoyées par le moteur (cela pourrait aussi être un capteur au niveau de la roue) et que la gestion d'un clavier est très couteuse en termes de temps. Ici c'est un circuit qui sera spécialisé pour ce type de fonction et soulagera en conséquence le PIC maître.

Le PIC 16F690 est en version boitier miniature, il prend donc très peu de place.

Son rôle est de compter les impulsions et d'envoyer certains signaux puis de lire le résultat pour repérer si on a appuyé sur une touche ( et laquelle  ! )

Il est en quelque sorte autonome sauf que ... c'est un esclave : si on l'appelle il répond immédiatement et envoie les données qu'il a puis remet à vide ses propres données.

L'intérêt est donc le suivant: le PIC principal (dit "maître") ne s'occupe que de ses affaires et, quand il en a envie, va interroger le PIC esclave pour savoir s'il y a du nouveau.

 

- un  PIC 16F690 qu'on pourrait qualifier de spécialisé

Il est, lui aussi, un esclave mais son rôle est différent, c'est en quelque sorte une extension.

Pour ce qui est de son côté le plus indispensable, son rôle est de gérer la position code/phare.

Pour le reste il gère le côté gadgets: l'allumage des LEDs de contrôle (les LEDs clignotent en attendant la présentation de la clef), il gère aussi l'appel de phare, l'allumage des feux bleus ou encore le bouton d'appel de phares qui envoie une série de flashs.  

 

 

Les deux derniers PIC utilisent le même langage que le PIC maître.

 



20/06/2012
0 Poster un commentaire

Inscrivez-vous au blog

Soyez prévenu par email des prochaines mises à jour

Rejoignez les 6 autres membres