;-----------------------------------------------------------------------------
;             873RS33.ASM version <<<<V3.3>>>> du 20/02/2015 
;             INCOMPATIBLE avec la V2.0 ou V2.1 (matériel ou logiciel PC)
;
;             40 ENTREES/SORTIES SUPPLEMENTAIRES et QUARTZ à 20 Mhz en V3
;             Sorties PWM = Sens + Enable L293 !!! (Modification schéma et CI)
;
;             Utilisation de la rs232 en moniteur sous IT
;             Mise en place du module can sous IT Timer0
;             Mise en place du module pwm sous IT Timer0
;             Décalage pour les 3 groupes de sortie:
;             - out, - mat-out, - pwm
;              9 . Passage a 50 Hz
;             10 . Support du capteur de courant
;             11 . Amélioration de la liaison série
;             12 . Rajout d'un servo (pour plaque tournante)
;             13 . Modification du moniteur (maintenant adressable (8 adresses))
;             14 . Version à 8 Mhz commentée JLF, libération de 10 registres
;                  Liaison série à 19200 Bd/s
;                  Modif lecture CAN + comparaison adresse de la carte
;             30 . Nouvelle implantation des sorties
;                  Version à 20 Mhz + 40 entrées + 40 sorties supplémentaires,
;                  Liaison série à 38400 Bd/s, passage à 62 Hz pour PWM voies.
;             31 . Nouvelle implantation des sorties
;                  Nouveau circuit externe de détection d'occupation des cantons.
;                  Utilisation 1 bit de sens + 1 bit Enable L293D pour PWM,
;                  Commande de 5 servos par défaut sans perturbation.
;             33 . Lecture des entrées multiplexées avec une tempo plus grande entre deux lectures de colonne.
;                  Améliore la lecture d'un clavier multiplexé.
;
; Entrées/Sorties en V3.0 = Circuit imprimé V2.1 avec 2 coupures + 2 straps
; et câblage des trois nouveaux connecteurs d'interfaces.
; Entrées/Sorties en V3.2 = Circuit imprimé V2.1 + Modif V3.0 + recablage
; des L293D
;
; Utilisation des pattes du PIC
;  HHH = Horloge, VVV = Validation
;
;  PORTA
;    (0) Entrée analogique potentiomètre (0)
;    (1) Entrée analogique potentiomètre (1)
;    (2) Entrée analogique potentiomètre (2)
;    (3) Entrée analogique potentiomètre (3)
;    (4) Vers led jaune clignotante
;    (5) Entrée analogique potentiomètre (4)
;  PORTB
;    (0) Entrées numériques multiplexées, entrée bit (2)
;    (1) HHH**Sortie horloge vers registre 74HCT4094 voies PWM
;        HHH--Sortie horloge vers registre 74HCT4094 entrées multiplexées (ancien C(4))
;        HHH<<Sortie horloge vers registre 74HCT165 détection d'occupation des cantons
;    (2) VVV**Sortie validation vers registre 74HCT4094 voies PWM
;    (3)    <<Entrée données 74HCT165 détection d'occupation des cantons
;    (4) VVV<<Sortie validation vers registre 74HCT165 détection d'occupation des cantons
;    (5)    ++Sortie données vers registre 74HCT4094 sorties ULN2008 [1]
;    (6) VVV++Sortie validation vers registre 74HCT4094 sorties ULN2008 [1]
;        VVV//Sortie validation vers registre 74HCT4094 sorties ULN2008 [2]
;        VVV::Sortie validation vers registre CD4014 entrées numériques directes [2]
;    (7) HHH++Sortie horloge vers registre 74HCT4094 sorties ULN2008 [1]
;        HHH//Sortie horloge vers registre 74HCT4094 sorties ULN2008 [2]
;        HHH::Sortie horloge vers registre 74HCT165 entrées numériques directes [2]
;  PORTC
;    (0) Entrées numériques multiplexées, entrée bit (0)
;    (1) Entrées numériques multiplexées, entrée bit (1)
;    (2) Créneau de 1 à 2 msec vers les servos (CCP1)
;    (3) Entrées numériques multiplexées, entrée bit (3)
;    (4)    ::Entrée données 74HCT165 entrées numériques directes (2]
;    (5)    --Sortie données vers registre 74HCT4094 entrées multiplexées
;           **Sortie données vers registre 74HCT4094 voies PWM (ancien B(4))
;           //Sortie données vers registre 74HCT4094[2] sorties ULN2008 [2]
;    (6) Sortie du PIC vers RS232
;    (7) Entrée du PIC vers RS232
;
;
; Commandes depuis le PC :
;  0x00 re-synchronise la communication série avec le PC (ne fait rien)
;  0x01 ping carte et sélection de la carte, retour=  0x83, 0x93, xa3,,,
;  0x02 Met à jour le pointeur d'adresse 'FSR'
;  0x03 Ecrit dans le registre pointé par [FSR]
;  0x04 Lit dans le registre pointé par [FSR]
;  0x05 Incrémente le pointeur 'FSR' et écrit dans le registre pointé par [FSR]
;  0x06 Incrémente le pointeur 'FSR' et lit dans le registre pointé par [FSR]
;  0x07 Incrémente le pointeur 'FSR' et lit puis éfface dans le registre pointé par [FSR]
;  0x08 - 0X0F Transfère global (Ecriture + lecture)
;  0X10 - 0XFF Seul les 4 bits de poids faibles sont traités
;
; rx    0    1    2    3    4    5    6     7     8
; tx        0x83           data      +data +data
;
; rx2             adr  data      +data            data
; tx2                                             data
;
; Le ping permet également de sélectionner la carte suivant son adresse CARDADR (0 à 3)
; En fonction de la carte, il faut émettre la commande ping suivante  :
; Adresse =         0     1     2     3
; Octet   =      0x01  0x11  0x21  0x31
; Touches = ALT + 001 + 017 + 033 + 049 (sous simulateur ISIS)
;
; Avec un quart à 20 Mhz => Une instruction = 0,2 µsec
;
; A 19200 Bd, temps de transmission d'un caractère = 520 µs
; A 38400 Bd, temps de transmission d'un caractère = 260 µs doit être > TMR0 (250µs) !
;
; Transfert depuis le PC = 1 octet sélection de carte + 1 octet de cmd + 47 octets vers le PIC
;                        = 1 octet de réponse + 23 in = 71 octets
;                        = Le PIC commence à répondre à partir du deuxième octet de donnée reçu
;                        = et envoi un octet tous les 2 octets reçu.
;                          à 38400 Bd, l'échange dure = 13ms (en V3.2)
;
;
	LIST		P=PIC16F873		; Définition du processeur
	#include	<p16F873.inc>	; Définitions des variables

;	__CONFIG   _CP_OFF & _DEBUG_OFF & _WRT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
	__CONFIG   _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
;	P16F873 =  "_WRT_ENABLE_OFF",   P16F873A = "_WRT_OFF"
;
	ERRORLEVEL  -302

CARDADR EQU 0	; Adresse de la carte mère (0-7) = Adresse sur la liaison RS232
			; variable à positionner pour produire 873RS31_1.HEX, 873RS31_2.HEX...

;-----------------------------------------------------------------------------
; DEFINITIONS et MACROS
; BANK2 et BANK 3 pas utilisées, sinon modifier les macros BANK0 et BANK1

PAS_VITESSE	EQU	.64	; Nombre de pas disponibles pour la vitesse sur un canton
;				  Valeur de 'pwm_rX' = 0 à 'PAS_VITESSE'

CLKOUT  EQU     7	; de PORTB horloge    (1)et(2)  74HCT4094 vers relais et leds
LODOUT  EQU     6	; de PORTB validation (1)et(2)  74HCT4094 vers relais et leds
DATOUT  EQU     5	; de PORTB données    (1)       74HCT4094 vers relais et leds
DATOUT2 EQU     5	; de PORTC données    (2)       74HCT4094 vers relais et leds
DATIN2  EQU     4	; de PORTC données in (2)       75HCT165 depuis entrées directes

CLKPWM  EQU     1	; de PORTB horloge    74HCT4094 vers les voies
LODPWM  EQU     2	; de PORTB validation 74HCT4094 vers les voies
DATPWM  EQU     5	; de PORTC données    74HCT4094 vers les voies En V3.2 B(4) vers C(5)

DATDEC2 EQU     3	; de PORTB données    détection des cantons 75HCT165 depuis entrées directes
LODDEC2 EQU     4	; de PORTB de chargement des données

CLKMAT  EQU     1	; de PORTB horloge    74HCT4094 vers matrice des entrées. En V3.2 C(4) vers B(1)

DATMAT  EQU     5	; de PORTC données    74HCT4094 vers matrice des entrées
rs_sel  EQU     0	; indicateurs.rs_sel = bit de sélection de la carte
rs_env  EQU     1	; indicateurs.rs_env = bit d'envoi d'un caractère une fois sur deux

BANK0	macro				; passer en banque0
	bcf	STATUS,RP0
	endm

BANK1	macro				; passer en banque1
	bsf	STATUS,RP0
	endm

CK_DOWN_PWM macro
	bcf   PORTC,DATPWM
	nop
	bcf   PORTB,CLKPWM
	nop
	endm

CK_UP_PWM macro
	bsf   PORTC,DATPWM
	nop
	bsf   PORTB,CLKPWM
	nop
	endm

CK_DOWN_OUT macro
	bcf   PORTC,DATOUT2
	nop
	bcf   PORTB,CLKOUT
	endm

CK_UP_OUT macro
	bsf   PORTC,DATOUT2
	nop
	bsf   PORTB,CLKOUT
	nop
	endm

CK_UD_DAT macro
	bsf   PORTB,CLKMAT	; En V3.0 pour retrouver des sorties à 1
	nop
	bcf   PORTB,CLKMAT	; Avant de commencer.
	nop
	endm

;-----------------------------------------------------------------------------
; ADRESSES  DES  VARIABLES
;
; Registres d'échange avec le PC (ECRITURE depuis le PC)
; Registres de variables pour écriture depuis le PC
;
; Données en BANK0 de 0x20 à 0x7F (96 adresses)
;--------VARIABLES EN ECRITURES -----------
	CBLOCK	0x20	;    Début de la zone variables
pwm_r0	: 1	; Valeur de la vitesse sur le canton 0 (= 0 à 63)
pwm_r1	: 1	;     //  1
pwm_r2	: 1	;     //  2
pwm_r3	: 1	;     //  3
pwm_r4	: 1	;
pwm_r5	: 1	;
pwm_r6	: 1	;
pwm_r7	: 1	;
pwm_r8	: 1	;
pwm_r9	: 1	;
pwm_r10	: 1	;
pwm_r11	: 1	;
pwm_r12	: 1	;
pwm_r13	: 1	;
pwm_r14	: 1	;     // 14
pwm_r15	: 1	;     // 15
pwm_s0_7	: 1	; Valeur sens de déplacement 1 bit /canton 0 à 7
pwm_s8_15	: 1	; Valeur sens de déplacement 1 bit /canton 8 à 15
out_out3	: 1	; Valeur des bits des sorties   1 à  7  (IC14-ULN2008 [1])
out_out4	: 1	;   //                          8 à 15  (IC15-ULN2008 [1])
out_out5	: 1	;   //                         16 à 23  (IC16-ULN2008 [1])
out_out21	: 1	; Valeur des bits des sorties           (ULN2008 [2]) V3.0
out_out22	: 1	;   //
out_out23	: 1	;   //
out_out24	: 1	;   //
out_out25	: 1	;   //
led_on0	: 1	; Leds 00-07 allumées             (1bit = une led)
led_on1	: 1	; Leds 12-19 allumées             ( bit = 1 = on )
led_on01	: 1	; Leds 08-11 et 20-23 allumées
led_on2	: 1	; Leds 24-31 allumées
led_on3	: 1	; Leds 36-43 allumées
led_on23	: 1	; Leds 32-35 et 43-47 allumées
led_cl0	: 1	; Leds 00-07 clignotantes         (1bit = une led)
led_cl1	: 1	; Leds 12-19 clignotantes         ( bit = 1 = cli)
led_cl01	: 1	; Leds 08-11 et 20-23 clignotantes
led_cl2	: 1	; Leds 24-31 clignotantes
led_cl3	: 1	; Leds 36-43 clignotantes
led_cl23	: 1	; Leds 32-35 et 43-47 clignotantes
led_in0	: 1	; Leds 00-07 clignotant inversé    (1bit = une led)
led_in1	: 1	; Leds 12-19 clignotant inversé    ( bit = 1 = inv)
led_in01	: 1	; Leds 08-11 et 20-23 clignotant inversé
led_in2	: 1	; Leds 24-31 clignotant inversé
led_in3	: 1	; Leds 36-43 clignotant inversé
led_in23	: 1	; Leds 32-35 et 43-47 clignotant inversé
srv_0		: 1	; Valeur de consigne du servo 0
srv_1		: 1	;     //                      1
srv_2		: 1	;     //                      2
srv_3		: 1	;     //                      3
srv_4		: 1	;     //                      4
ruf1		: 1   ; LIBRE réservé utilisation future
ruf2		: 1   ; LIBRE réservé utilisation future
ruf3		: 1   ; LIBRE réservé utilisation future
;
;
; ---------VARIABLES EN LECTURE -----------
can_r0	: 1	; Valeur lue sur l'entrée analogique (0) ( = 0 à 255 )
can_r1	: 1	;   //                               (1)
can_r2	: 1	;   //                               (2)
can_r3	: 1	;   //                               (3)
can_r4	: 1	;   //                               (4)
in_in1 	: 1	; Valeurs des bits des 40 entrées (75HCT165 [2]) V3.0
in_in2 	: 1	;   //
in_in3	: 1	;   //
in_in4	: 1	;   //
in_in5	: 1	;   //
det_i1	: 1	; Un bit par canton, = 1 si le canton est occupé
det_i2	: 1	;   //
ruf11		: 1   ; LIBRE réservé utilisation future
;
;
; --------VARIABLES EN LECTURE ET EFFACEMENT -----------
det_i1m	: 1	; Un bit par canton, le passage à l'état 1 est mémorisé
det_i2m	: 1	; Tous ces Octets sont effacés par la lecture de ces registres.
mat_in0	: 1	; 4bits d'entrées colonne INA + ligne IN3 à IN0 + 4 bits mémorisation des
mat_in1	: 1	;   //  INB + ligne IN3 à IN0                       états, effacés par
mat_in2	: 1	;   //  INC + ligne IN3 à IN0                       la lecture de ces
mat_in3	: 1	;   //  IND + ligne IN3 à IN0                       registres.
mat_in4	: 1	;   //  INE + ligne IN3 à IN0
mat_in5	: 1	;   //  INF + ligne IN3 à IN0
mat_in6	: 1	;   //  ING + ligne IN3 à IN0
mat_in7	: 1	;   //  INH + ligne IN3 à IN0
mat_in8	: 1	;   //  INI + ligne IN3 à IN0
;
;
; -------VARIABLES DE CALCULS INTERNES AU PIC -----------
indicateurs	: 1	; bit(0) = selection carte après récp.code 0xC1, passe à 1 (avec C = n° de carte),
cpt		: 1	; Compteur incrémenté à chaque interruption du Timer0
cpt2		: 1	; Compteur incrémenté tous les 256 interruptions du Timer0 (cpt)
rs_adr	: 1	; Variable = adresse du registre à lire/écrire = 0x20, 0x21, 0x22,,,
rs_mode	: 1	; Type de traitement en réception d'un caractère, bit(7)= cmd / données
pwm_cpt	: 1	;
out_out1	: 1	; Valeur calculée dans le PIC des bits des leds 1 à  7 et validation des 74HCT4094
out_out2	: 1	; Valeur calculée dans le PIC des bits des leds 8 à 11 + colonnes A à D (IC13)
out_pwm1	: 1	;| Sens_Inv(3) | Enable_Alim(2) | Sens_Inv(1) | Enable_Alim(0) | Enable_Alim(3) | Sens_Normal(2) | Enable_Alim(1) | Sens_Normal(0) | IC9  Alimentation des cantons
out_pwm2	: 1	;| Sens_Inv(7) | Enable_Alim(6) | Sens_Inv(5) | Enable_Alim(4) | Enable_Alim(7) | Sens_Normal(6) | Enable_Alim(5) | Sens_Normal(4) | IC10 (x)= n° du canton
out_pwm3	: 1	;| Sens_Inv(11)| Enable_Alim(10)| Sens_Inv(9) | Enable_Alim(8) | Enable_Alim(11)| Sens_Normal(10)| Enable_Alim(9) | Sens_Normal(8) | IC11
out_pwm4	: 1	;| Sens_Inv(15)| Enable_Alim(14)| Sens_Inv(13)| Enable_Alim(12)| Enable_Alim(15)| Sens_Normal(14)| Enable_Alim(13)| Sens_Normal(12)| IC12
cpt_srv	: 1	; Numéro de servo actif bits(3,2,1) +  bit indicateur bit(0) =
var1_spg	: 1	; Variable temporaire n°1 utilisable dans tous les sous-programmes
var2_spg	: 1	; Variable temporaire n°2 utilisable dans tous les sous-programmes
it_err	: 1	; Si le Timer0 TMR0 a débordé c'est une erreur, (it_err++)
libre1	: 1	; !!!! REGISTRE LIBRE  !!!!
libre2	: 1	; !!!! REGISTRE LIBRE  !!!!
libre3	: 1	; !!!! REGISTRE LIBRE  !!!!
libre4	: 1	; !!!! REGISTRE LIBRE  !!!!
	ENDC                   ; Fin de la zone


; Données en BANK1 de 0xA0 à 0xEF (80 adresses) car plus de place en BANK0
	CBLOCK	0xA0	;    Début de la zone variables en BANK1
det_i1_1	:1	; Octet de détection des cantons 0 à 7
det_i1_2	:1	;     // coup d'avant
det_i1_3	:1	;     // coup d'avant - avant
det_i1_4	:1	;
det_i1_5	:1	;
det_i1_6	:1	;
;
det_i2_1	:1	; Octet de détection des cantons 8 à 15
det_i2_2	:1	;     // coup d'avant
det_i2_3	:1	;     // coup d'avant - avant
det_i2_4	:1	;
det_i2_5	:1	;
det_i2_6	:1	;

val_srv	: 1	; Valeur du servo (0-255) selectionné
val_srvL	: 1	; Valeur du servo converti en 16 bits sur CCP1H/L
val_srvH	: 1	;

	ENDC                   ; Fin de la zone

;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

	ORG     0		; 1 - Démarrage à la mise sous tension
	goto    init0
	ORG     4		; 2 - En cas d'interruption
	goto    it_timer
	dt "__UTS_2000_V33_ADR0__"	; Texte visible dans le .hex dans ICPROG
;
init0	bsf	PCLATH,3	; Prépare le saut en page n°0 vers n°1 (0x800 - 0xFFF)
	call	init		; Saut en page n° 1
	bcf	PCLATH,3	; On reste en page n°0 (0x000 - 0x7FF) pour les CALL !
tdf	nop
	goto	tdf		; Boucle en page n°0 en attendant les interruptions


;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; Programme de gestion des interruptions
;
; Timer0 = 250 µs (à 20 Mhz = 1250 instructions de 0,2 µs)
; Timer0 = 250 µs,(Pas du Timer0 = 20 Mhz/4 + prédiviseur à 16 = 3,2 µs)
;
; A 38400 Bd, le temps de transmission d'un caractère = 260 µs
; Le timer TMR0 doit être inférieur à ce temps. TMR0 = 250 µs.
; Initialisation du Timer0 pour 250 µs / 3,2 µs = 78,1   ===>   256 - 78 = 178
; On prend 179 pour Timer0 < 250 µs.
;
; cpt++ tous les 250 µs et cpt2++ tous les 64 ms à 20 Mhz.
;
it_timer
	bcf     INTCON,GIE	; Inhibe toutes les interruptions
;
; Pas de sauvegarde des registres, car le programme principal ne fait rien
; cela économise des variables.
;
	bcf     INTCON,T0IF	; Remise à 0 du drapeau de dépassement du Timer0 pour la prochaine interrup.
	movlw   .179		; durée = 0xB3 (255-XXXX)*temps_us du Timer0
	movwf   TMR0		; Interruption toutes les xxx instructions
	incf    cpt,f		; cpt  = Compteur incrémenté à chaque interruption du Timer0 (250 µs)
	btfsc   STATUS,Z
	incf    cpt2,f		; cpt2 = Compteur incrémenté tous les 256 interruptions du Timer0

	call    cal_pwm		; Calculs des sorties PWM
	call    maj_pwm		; Sorties PWM vers 4094
	call    maj_rs232		; Liaison RS232

	btfss   cpt,2		; répartiteur de charge suivant la valeur de cpt
	goto    cpt_0xx
cpt_1xx btfss   cpt,1
	goto    cpt_10x
cpt_11x btfss   cpt,0
	goto    cpt_6		; cpt = xxxx x110 = 6

	goto    cpt_7		; cpt = xxxx x111 = 7
cpt_10x btfss   cpt,0
	goto    cpt_4		; cpt = xxxx x100 = 4
	goto    cpt_5		; cpt = xxxx x101 = 5
cpt_0xx btfss   cpt,1
	goto    cpt_00x
cpt_01x btfss   cpt,0
	goto    cpt_2		; cpt = xxxx x010 = 2
	goto    cpt_3		; cpt = xxxx x011 = 3
cpt_00x btfss   cpt,0
	goto    cpt_0		; cpt = xxxx x000 = 0
	goto    cpt_1		; cpt = xxxx x001 = 1

cpt_0	call    maj_servo		; Calcul le prochain n° de servo
	call    maj_out6		; Envoi des bits des sorties système du PIC (servo,,,)
	goto    cpt_f

cpt_1	call    cal_led		; Calcul des octets à envoyer en sortie (leds multiplexées)
	call    maj_out5		; Envoi des bits des sorties  16 à 23  (IC16-ULN2008)
	goto    cpt_f

cpt_2	call    maj_can1		; Lecture ADRESH + choix du canal + lancement du convertisseur, bit ADCON0,ON = 1
	call    maj_out4		; Envoi des bits des sorties  8 à 15  (IC15-ULN2008)
	goto    cpt_f

cpt_3	call    maj_sig		; Clignotement de la led jaune
	call    maj_out3		; Envoi des bits des sorties  1 à 7  (IC14-ULN2008)
	goto    cpt_f

cpt_4	call    maj_can2		; Démarrage de la conversion A/N, et lecture des 5 potentiomètres
	call    maj_out2		; Envoi des bits des leds  8 à 11 et A à D (IC13-ULN2008)
	goto    cpt_f

cpt_5	call    maj_out1		; Envoi des bits des leds  1 à 7 et validation des 74HCT4094
	goto    cpt_f

cpt_6	call    maj_in		; Lecture de la matrice d'entrée des contacts
	goto    cpt_f

cpt_7	call    cal_servo		; Calcul le créneau du servo en cours 

	goto    cpt_f

cpt_f	btfsc   INTCON,T0IF	; Le timer à déjà fait un tour ?
	incf    it_err,f		; Si le Timer0 'TMR'0 a débordé, c'est une erreur, (it_err++)
;
; Pas de restauration des registres, car le programme principal ne fait rien
;
	bsf     INTCON,GIE	; Autorise toutes les interruptions
	retfie


;-----------------------------------------------------------------------------
; SSPG_TOUJOURS : Calcul des valeurs des octets 'out_pwm1' à 'out_pwm4' à envoyer
;                 directement pour commander les alimentations des cantons (L293D)
;                 Convertit les données du PC :
;                   - Vitesse = 'pwm_r0'    à  'pwm_r15'
;                   - Sens    = 'pwm_s0_7' et  'pwm_s8_15'
;
; Valeurs calculées dans le PIC pour la commande des L293D (Alimentation des cantons + Sens d'alimentation)
; Le train va dans une direction donnée pour "Sens_Normal(x)=0" ou "Sens_Inv(x)=1" 
; Le train va dans l'autre direction pour    "Sens_Normal(x)=1" ou "Sens_Inv(x)=0" (Les pistes de certains cantons sont croisées sur le circuit imprimé).
; Cette configuration bizarre permet d'avoir sur le bornier de sorties des voies = 3-,3+,  2-,2+,  1-,1+,  0-,0+
; Les L293D alimentent les voies si "Enable_Alim(x)=1".      (x)= Numéro du cantons.
; Sorties 74HC4094=Bits 7               6              5               4                3              2                  1              0
;   out_pwm1 : 1 ;| Sens_Inv(3) | Enable_Alim(2) | Sens_Inv(1) | Enable_Alim(0) | Enable_Alim(3) | Sens_Normal(2) | Enable_Alim(1) | Sens_Normal(0) | IC9 (x)= n° du canton
;   out_pwm2 : 1 ;| Sens_Inv(7) | Enable_Alim(6) | Sens_Inv(5) | Enable_Alim(4) | Enable_Alim(7) | Sens_Normal(6) | Enable_Alim(5) | Sens_Normal(4) | IC10
;   out_pwm3 : 1 ;| Sens_Inv(11)| Enable_Alim(10)| Sens_Inv(9) | Enable_Alim(8) | Enable_Alim(11)| Sens_Normal(10)| Enable_Alim(9) | Sens_Normal(8) | IC11
;   out_pwm4 : 1 ;| Sens_Inv(15)| Enable_Alim(14)| Sens_Inv(13)| Enable_Alim(12)| Enable_Alim(15)| Sens_Normal(14)| Enable_Alim(13)| Sens_Normal(12)| IC12
;
; Bits de out_pwm(x) :  7  6  5  4  3  2  1  0
;          Bits(7à0) =  S  E  S  E  E  S  E  S  (Sens et Enable)
;                       3  2  1  0  3  2  1  0  (n° de cantons)
;                       7  6  5  4  7  6  5  4  (n° de cantons)
;                      15 14 13 12 15 14 13 12  (n° de cantons)
;
; Cette configuration permet d'avoir sur le bornier de sorties des voies = 3-,3+,  2-,2+,  1-,1+,  0-,0+
;
; pwm_cpt = compteur de 0 à 65 après incrémentation au début de ce sspg
;           Les pas 0 et 65 servent au test d'occupation des cantons.  
; pwm_r0  = vitesse du canton de 0 à 64 = "PAS_VITESSE"
;
;            pwm_cpt = 01   02   03   04   05 -------- 61   62   63   64   65   00
; pwm_r0 =  0    out =  0    0    0    0    0           0    0    0    0    0    0
; pwm_r0 =  1    out =  1    0    0    0    0           0    0    0    0    0    0
; pwm_r0 =  2    out =  1    1    0    0    0           0    0    0    0    0    0
; pwm_r0 =  3    out =  1    1    1    0    0           0    0    0    0    0    0
; pwm_r0 =  4    out =  1    1    1    1    0           0    0    0    0    0    0
;...
; pwm_r0 = 62    out =  1    1    1    1    1           1    1    0    0    0    0
; pwm_r0 = 63    out =  1    1    1    1    1           1    1    1    0    0    0
; pwm_r0 = 64    out =  1    1    1    1    1           1    1    1    1    0    0
;                                                                           ^    ^      ^ = Test d'occupation des cantons.   
;
; Si pwm_cpt = 65 ou 0, test de l'occupation des 16 cantons = Sorties à haute impédance,
; pour faire fonctionner le détecteur de tension.
;
; Inverse le bit de sens des cantons 1,3,5,7,9,11,13 et 15 = bit(5) et bit(7), car les pistes se croisent sur le circuit imprimé.
; Le bit d'alimentation = bit(4), bit(1), bit(6) et bit(3) = bit 'Enable = ALIMENTATION des VOIES'.
;
cal_pwm
	incf    pwm_cpt,f
	movf    pwm_cpt,w
	sublw   PAS_VITESSE+2	; = nombre de pas de vitesse + 2 pas de test d'occupation de canton.
	btfsc   STATUS,Z
	clrf    pwm_cpt		; pwm_cpt = 0 à 65("PAS_VITESSE" + 1)
;
; Si pwm_cpt= 65 ou 0, alors on test la détection des cantons
; Deux tests à la fin de chaque créneau à T0+250 µs et T0+500µS
; pour être sûr de détecter un moteur même avec un effet inductif important.
;
;
; Vitesses des cantons de 0 à 3
; Vitesses des              cantons(0),  cantons(1),  cantons(2),  cantons(3)  se traduit par 
; les bits d'alimentation = out_pwm1(4), out_pwm1(1), out_pwm1(6), out_pwm1(3) Si bit=1 le L293D alimente les voies.
;
	clrf    out_pwm1		; out_pwm1 = B'00000000'
	movf    pwm_r0,w		; cpt-cmd  f-w  0-2>C=1, 2-0>C=0, 0-0>C=0 cmd>cpt C=1
	subwf   pwm_cpt,w		; si (pwm_cpt = pwm_rx)
	btfss   STATUS,C		; Envoie donc un créneau en sortie à 1 tant que vitesse du canton >  pwm_cpt
	bsf     out_pwm1,4	; Enable L293D = bits de sorties  =  4,  1,  6,  3

	movf    pwm_r1,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm1,1

	movf    pwm_r2,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm1,6

	movf    pwm_r3,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm1,3
;
; Vitesses des cantons de 4 à 7
; Vitesses des              cantons(4),  cantons(5),  cantons(6),  cantons(7)  se traduit par 
; les bits d'alimentation = out_pwm2(4), out_pwm2(1), out_pwm2(6), out_pwm2(3) Si bit=1 le L293D alimente les voies.
;
	clrf    out_pwm2		; out_pwm2 = B'00000000'
	movf    pwm_r4,w		; cpt-cmd  f-w  0-2>C=1, 2-0>C=0, 0-0>C=0 cmd>cpt C=1
	subwf   pwm_cpt,w		; si (pwm_cpt = pwm_rx)
	btfss   STATUS,C		; Envoie donc un créneau en sortie à 1 tant que vitesse du canton >  pwm_cpt
	bsf     out_pwm2,4	; Enable L293D = bits de sorties  =  4,  1,  6,  3

	movf    pwm_r5,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm2,1

	movf    pwm_r6,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm2,6

	movf    pwm_r7,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm2,3
;
; Vitesses des cantons de 8 à 11
; Vitesses des              cantons(8),  cantons(9),  cantons(10), cantons(11) se traduit par 
; les bits d'alimentation = out_pwm3(4), out_pwm3(1), out_pwm3(6), out_pwm3(3) Si bit=1 le L293D alimente les voies.
;
	clrf    out_pwm3		; out_pwm3 = B'00000000'
	movf    pwm_r8,w		; cpt-cmd  f-w  0-2>C=1, 2-0>C=0, 0-0>C=0 cmd>cpt C=1
	subwf   pwm_cpt,w		; si (pwm_cpt = pwm_rx)
	btfss   STATUS,C		; Envoie donc un créneau en sortie à 1 tant que vitesse du canton >  pwm_cpt
	bsf     out_pwm3,4	; Enable L293D = bits de sorties  =  4,  1,  6,  3

	movf    pwm_r9,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm3,1

	movf    pwm_r10,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm3,6

	movf    pwm_r11,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm3,3
;
; Vitesses des cantons de 12 à 15
; Vitesses des              cantons(12), cantons(13), cantons(14), cantons(15) se traduit par 
; les bits d'alimentation = out_pwm4(4), out_pwm4(1), out_pwm4(6), out_pwm4(3) Si bit=1 le L293D alimente les voies.
;
	clrf    out_pwm4		; out_pwm4 = B'00000000'
	movf    pwm_r12,w		; cpt-cmd  f-w  0-2>C=1, 2-0>C=0, 0-0>C=0 cmd>cpt C=1
	subwf   pwm_cpt,w		; si (pwm_cpt = pwm_rx)
	btfss   STATUS,C		; Envoie donc un créneau en sortie à 1 tant que vitesse du canton >  pwm_cpt
	bsf     out_pwm4,4	; Enable L293D = bits de sorties  =  4,  1,  6,  3

	movf    pwm_r13,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm4,1

	movf    pwm_r14,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm4,6

	movf    pwm_r15,w
	subwf   pwm_cpt,w
	btfss   STATUS,C
	bsf     out_pwm4,3
;
; Définit le sens d'alimentation des cantons 0 à 15.  Le bit de sens = "Sens_Inv(x)" ou "Sens_Normal(x)".
; Pour les cantons 0,2,4,6,8,10,12 et 14 la direction normale est quand le bit "Sens_Normal(x)" = 0
; Pour les cantons 1,3,5,7,9,11,13 et 15 la direction normale est quand le bit "Sens_Inverse(x)" = 1
; Inverse ou non le bit de sens de circulation reçue dans la trame série.
;
	btfsc   pwm_s0_7,0	; Bits de sens de circulation en entrée de L293D.
	bsf     out_pwm1,0	; Sens_Normal(0)  -> out_pmw1(0) 
	btfss   pwm_s0_7,1
	bsf     out_pwm1,5	; Sens_Inverse(1) -> out_pmw1(5) 
	btfsc   pwm_s0_7,2
	bsf     out_pwm1,2	; Sens_Normal(2)  -> out_pmw1(2) 
	btfss   pwm_s0_7,3
	bsf     out_pwm1,7	; Sens_Inverse(3) -> out_pmw1(7) 
;
	btfsc   pwm_s0_7,4	; Bits de sens de circulation en entrée de L293D.
	bsf     out_pwm2,0	; Sens_Normal(4)  -> out_pmw2(0)
	btfss   pwm_s0_7,5
	bsf     out_pwm2,5	; Sens_Inverse(5) -> out_pmw2(5)
	btfsc   pwm_s0_7,6
	bsf     out_pwm2,2	; Sens_Normal(6)  -> out_pmw2(2)
	btfss   pwm_s0_7,7
	bsf     out_pwm2,7	; Sens_Inverse(7) -> out_pmw2(7)
;
	btfsc   pwm_s8_15,0	; Bits de sens de circulation en entrée de L293D.
	bsf     out_pwm3,0	; Sens_Normal(8)  -> out_pmw3(0)
	btfss   pwm_s8_15,1
	bsf     out_pwm3,5	; Sens_Inverse(9) -> out_pmw3(5)
	btfsc   pwm_s8_15,2
	bsf     out_pwm3,2	; Sens_Normal(10) -> out_pmw3(2)
	btfss   pwm_s8_15,3
	bsf     out_pwm3,7	; Sens_Inverse(11)-> out_pmw3(7)
;
	btfsc   pwm_s8_15,4	; Bits de sens de circulation en entrée de L293D.
	bsf     out_pwm4,0	; Sens_Normal(12) -> out_pmw4(0)
	btfss   pwm_s8_15,5
	bsf     out_pwm4,5	; Sens_Inverse(13)-> out_pmw4(5)
	btfsc   pwm_s8_15,6
	bsf     out_pwm4,2	; Sens_Normal(14) -> out_pmw4(2)
	btfss   pwm_s8_15,7
	bsf     out_pwm4,7	; Sens_Inverse(15)-> out_pmw4(7)

	return


;-----------------------------------------------------------------------------
; SSPG_TOUJOURS : Mise à jour des sorties PMW, sortie et validation des bits
;                 dans les 74HCT4094 en fonction des octets 'out_pwm1' à 'out_pwm4'
;                 calculés précédemment
;
; Lecture simultanée des entrées de détections des cantons (74HCT165):
; on attend 2 * 250 µs avant de lire les bits d'occupation.
; Pour améliorer la fiabilité de la détection, il faudrait essayer de lire aux deux
; pas de pause et faire la moyenne de détection sur 2x3 mesures.
;
; Pour simplifier le circuit imprimé, les bits sont répartis de la manière suivante :
;
;   Bits lus        :  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
;   Cantons         :  3,  1, 15, 13, 11,  9,  7,  5,  4,  6,  8, 10, 12, 14,  0,  2
;   var1_spg/n° bit :  3   1                   7   5   4   6                   0   2
;   var2_spg/n° bit :          7   5   3   1                   0   2   4   6
; <=>
;   Cantons         :  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
;   Bits lus        : 14,  1, 15,  0,  8,  7,  9,  6, 10,  5, 11,  4, 12,  3, 13,  2;
;
maj_pwm
	bcf	PORTB,LODDEC2	; Charge les entrées à chaque fois
	clrf	var1_spg		; Valeur des bits de détection d'occupation
	clrf	var2_spg		; Valeur des bits de détection d'occupation
	nop				; mais les données ne seront traitées qu'une fois sur 65
	bsf	PORTB,LODDEC2	; Impulsion de validation de 800 ns
	nop
	nop

	btfsc PORTB,DATDEC2	; Lecture simultanée des 74HCT165 d'occupation des cantons
	bsf	var1_spg,3
	btfss out_pwm4,7
	CK_DOWN_PWM
	btfsc out_pwm4,7
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var1_spg,1
	btfss out_pwm4,6
	CK_DOWN_PWM
	btfsc out_pwm4,6
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,7
	btfss out_pwm4,5
	CK_DOWN_PWM
	btfsc out_pwm4,5
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,5
	btfss out_pwm4,4
	CK_DOWN_PWM
	btfsc out_pwm4,4
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,3
	btfss out_pwm4,3
	CK_DOWN_PWM
	btfsc out_pwm4,3
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,1
	btfss out_pwm4,2
	CK_DOWN_PWM
	btfsc out_pwm4,2
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var1_spg,7
	btfss out_pwm4,1
	CK_DOWN_PWM
	btfsc out_pwm4,1
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var1_spg,5
	btfss out_pwm4,0
	CK_DOWN_PWM
	btfsc out_pwm4,0
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var1_spg,4
	btfss out_pwm3,7
	CK_DOWN_PWM
	btfsc out_pwm3,7
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var1_spg,6
	btfss out_pwm3,6
	CK_DOWN_PWM
	btfsc out_pwm3,6
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,0
	btfss out_pwm3,5
	CK_DOWN_PWM
	btfsc out_pwm3,5
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,2
	btfss out_pwm3,4
	CK_DOWN_PWM
	btfsc out_pwm3,4
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,4
	btfss out_pwm3,3
	CK_DOWN_PWM
	btfsc out_pwm3,3
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var2_spg,6
	btfss out_pwm3,2
	CK_DOWN_PWM
	btfsc out_pwm3,2
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var1_spg,0
	btfss out_pwm3,1
	CK_DOWN_PWM
	btfsc out_pwm3,1
	CK_UP_PWM

	btfsc PORTB,DATDEC2
	bsf	var1_spg,2
	btfss out_pwm3,0
	CK_DOWN_PWM
	btfsc out_pwm3,0
	CK_UP_PWM

	btfss out_pwm2,7
	CK_DOWN_PWM
	btfsc out_pwm2,7
	CK_UP_PWM

	btfss out_pwm2,6
	CK_DOWN_PWM
	btfsc out_pwm2,6
	CK_UP_PWM

	btfss out_pwm2,5
	CK_DOWN_PWM
	btfsc out_pwm2,5
	CK_UP_PWM

	btfss out_pwm2,4
	CK_DOWN_PWM
	btfsc out_pwm2,4
	CK_UP_PWM

	btfss out_pwm2,3
	CK_DOWN_PWM
	btfsc out_pwm2,3
	CK_UP_PWM

	btfss out_pwm2,2
	CK_DOWN_PWM
	btfsc out_pwm2,2
	CK_UP_PWM

	btfss out_pwm2,1
	CK_DOWN_PWM
	btfsc out_pwm2,1
	CK_UP_PWM

	btfss out_pwm2,0
	CK_DOWN_PWM
	btfsc out_pwm2,0
	CK_UP_PWM

	btfss out_pwm1,7
	CK_DOWN_PWM
	btfsc out_pwm1,7
	CK_UP_PWM

	btfss out_pwm1,6
	CK_DOWN_PWM
	btfsc out_pwm1,6
	CK_UP_PWM

	btfss out_pwm1,5
	CK_DOWN_PWM
	btfsc out_pwm1,5
	CK_UP_PWM

	btfss out_pwm1,4
	CK_DOWN_PWM
	btfsc out_pwm1,4
	CK_UP_PWM

	btfss out_pwm1,3
	CK_DOWN_PWM
	btfsc out_pwm1,3
	CK_UP_PWM

	btfss out_pwm1,2
	CK_DOWN_PWM
	btfsc out_pwm1,2
	CK_UP_PWM

	btfss out_pwm1,1
	CK_DOWN_PWM
	btfsc out_pwm1,1
	CK_UP_PWM

	btfss out_pwm1,0
	CK_DOWN_PWM
	btfsc out_pwm1,0
	CK_UP_PWM

	nop
	nop
	bsf   PORTB,LODPWM	; Charge les données dans les 74HCT4094
	nop
	nop
	nop
	bcf   PORTB,LODPWM	; Impulsion de validation de 800 ns
;
; Traitement des bits d'occupation 'var1_spg1' et 'var1_spg2' en V3.2
; quand 'pwm_cpt' = 0 ou 'PAS_VITESSE' + 1
; Deux tests x 3 périodes = 6 variables pour l'historique.
; Si le canton est occupé alors sa valeur = 1
; Les calculs se font en BANK1, car il n'y a plus de place en BANK0
; Si le détecteur est trop sensible, il faut supprimer la détection 
; du premier pas quand pwm_cpt= "PAS_VITESSE" + 1.
;
	movf	pwm_cpt,w
	sublw	PAS_VITESSE+1
	btfsc	STATUS,Z
	goto	dect			; pwm_cpt = 65 + "PAS_VITESSE" + 1

	movf	pwm_cpt,w
	btfss	STATUS,Z
	goto	att_pwm		; pwm_cpt # 0
;
; Cela fait 1 ou 2 x TMR0 = 250 ou 500 µs que les sorties PWM sont inhibées,
; pour que la détection d'occupation des cantons soit efficace.
; Le résultat est dans 'var1_spg' et 'var2_spg'.
;
dect	BANK1
	movf	det_i1_5,w		; '00000001' = canton '1' occupé
	movwf	det_i1_6		; Décalage des historiques
	movf	det_i1_4,w
	movwf	det_i1_5
	movf	det_i1_3,w
	movwf	det_i1_4
	movf	det_i1_2,w
	movwf	det_i1_3		; 5->6,  4->3,  3->4
	movf	det_i1_1,w		; 2->3,  1->2,  nouveau->1
	movwf	det_i1_2
	BANK0
	movfw	var1_spg
	BANK1
	movwf	det_i1_1

	iorwf	det_i1_2,w		; Calcul de l'état d'occupation sur 
	iorwf	det_i1_3,w		; les 6 derniers états
	iorwf	det_i1_4,w
	iorwf	det_i1_5,w
	iorwf	det_i1_6,w
	BANK0
	movwf	det_i1		; Etat d'occupation sur les 2x3 derniers tests
	iorwf	det_i1m,f		; Etat mémorisé

	BANK1
	movf	det_i2_5,w		; '00000001' = canton '1' occupé
	movwf	det_i2_6		; Décalage des historiques
	movf	det_i2_4,w
	movwf	det_i2_5
	movf	det_i2_3,w
	movwf	det_i2_4
	movf	det_i2_2,w
	movwf	det_i2_3		; 5->6,  4->3,  3->4
	movf	det_i2_1,w		; 2->3,  1->2,  nouveau->1
	movwf	det_i2_2
	BANK0
	movfw	var2_spg
	BANK1
	movwf	det_i2_1

	iorwf	det_i2_2,w		; Calcul de l'état d'occupation
	iorwf	det_i2_3,w		; les 6 derniers états
	iorwf	det_i2_4,w
	iorwf	det_i2_5,w
	iorwf	det_i2_6,w
	BANK0
	movwf	det_i2		; Etat d'occupation sur les 2x3 derniers tests
	iorwf	det_i2m,f		; Etat mémorisé
	goto	fin_pwm
	
att_pwm				; Retard si pas de calcul de bit d'occupation pour 
	movlw	.15			; éviter un décalage à l'appel de la routine rs232
	movwf	var1_spg		; il faut perdre des instructions ici
bcl_pwm				; pour garder une temps constant dans 'dect'
	decfsz var1_spg,f		; décrémenter var1_spg
	goto	bcl_pwm		; si pas 0, boucler	
	goto	fin_pwm

fin_pwm
	return

;-----------------------------------------------------------------------------
; SSPG_TOUJOURS : Liaison série, interprétation des caractères reçus
;
; Les lignes suivantes décrivent le protocole utilisé :
; 0 : synchronisation : en envoyant la commande 0x00, le UC va se synchroniser, c'est utile lorsqu'on se perd dans le protocole.
;     Un envoie de quelques 0 devrait permettre de récupérer toutes les erreurs de protocole.
; 1 : Test : en envoyant la commande 0xy1, le UC devrait répondre 0x83 (si la carte à l'adresse = y-1).
;     Cette commande peut servir à vérifier que le moniteur est bien actif et qu'il est possible de communiquer avec le UC.
;     Si la carte répond 0x83, c'est que la carte à l'adresse 0.
;     Si la carte répond 0x83, elle est maintenant sélectionnée et les commandes suivantes lui sont destinées.
; 2 : Adresse : en envoyant la commande 0x02 puis l'adresse d'un registre.
;     On spécifie l'adresse du registre à utiliser pour les opérations suivantes de lecture et d'écriture.
;     L'adresse étant sur 8 bits, il est possible d'accéder aux banques 0 et 1.
; 3 : Commande d'écriture dans un registre
;     En envoyant la commande 0x03 puis un octet à écrire, cet octet est mis dans le registre sélectionné.
; 4 : Commande de lecture dans un registre
;     En envoyant la commande 0x04, la carte envoie au PC la valeur courante du registre sélectionné.
; 5 : Ecriture incrémentale
;     La commande 0x05 suivit d'un octet, permet de passer au registre suivant,
;     en incrémentant l'adresse courante, puis d'y écrire cet octet.
; 6 : Lecture incrémentale
;     La commande x06 permet de passer au registre suivant en incrémentant
;     l'adresse courante, puis de renvoyer la valeur de ce registre.
; 7 : Lecture puis effacement
;     En envoyant la commande 0x07, le moniteur renvoie la valeur courante
;     du registre sélectionné et le met à 0.
; 8 : Déclenche un transfert en lecture et écriture de tous les registres couramment utilisés par UTS.
;     Ce mode fait gagner beaucoup de temps car il n'y a pratiquement que de la donnée qui circule.
;     un octet [0x01], la carte répond en envoyant 0x83
;     un octet [0x08], la carte se met en attente de données.
;     un octet pour [0x20]
;     un octet pour [0x21], la carte répond en envoyant le contenu du register 0x4f (can_r0)
;     un octet pour [0x22]
;     un octet pour [0x23], la carte répond en envoyant le contenu du register 0x50 (can_r1)
;     un octet pour [0x24]
;     un octet pour [0x25], la carte répond en envoyant le contenu du register 0x4b (can_r2)
;     ...
;     un octet pour [0x4A],
;     un octet pour [0x4B],
;     un octet pour [0x4C],
;     un octet pour [0x4D],
;     un octet pour [0x53], plus de réponse et fin du transfert.
;
; 8x (hex) : sélectionne une carte. (Les cartes avec l'ancienne version 873_rs11 flashée ne tiennent
;     pas compte de cette commande. Le soft sait aussi reconnaître la version de la carte.
;     Si une ancienne carte est utilisée, elle sera considérée comme la carte 0. Rappelons qu'il n'est pas possible
;     d'utiliser des anciennes et nouvelles cartes en même temps. Soit une ancienne carte, soit de 1 à 4 nouvelles cartes.
;
; Le ping (1) permet également de sélectionner la carte suivant son adresse CARDADR (= 0,1,2 ou 3)
; En fonction de la carte, il faut émettre la commande ping suivante  :
; Adresse =         0     1     2     3
; Octet   =      0x01  0x11  0x21  0x31
; Touches = ALT + 001 + 017 + 033 + 049  (sous simulateur ISIS)
;
; rs_mode(7) : 0 = Attente d'un octet de commande / 1 = Attente d'un octet de données
;
; En V3.0 à 38400Bd, temps de réception d'un caractère = 260 µs > Timer0 = 250 µs
; Donc, on ne perd pas d'octet à la réception.
; En émission, on va envoyer un octet une fois sur deux = / 500 µs pour être sur que
; le dernier octet soit parti avant d'envoyer le prochain.
;
maj_rs232
	btfss   PIR1,RCIF		; le buffer de réception est-il plein ?
	return			; non ! = on arrête là
	movf    RCREG,w		; lire le registre de réception RCREG ce qui efface PIR1,RCIF
	movwf   var1_spg		; var1_spg = caractère reçu

	btfsc   rs_mode,7		; Octet de données attendu ?
	goto    rs_l2y		; oui! => rs_12y
;
; rs_mode = B'0xxxxxxx' => On a reçu un octet de commande
;
rs_l2n  btfsc   var1_spg,3
	goto    rs_8		; bit rs_mode(7) = 0, octet recu = "00001000" = 0x08
	btfss   var1_spg,2
	goto    rs_0xx
rs_1xx  btfss   var1_spg,1
	goto    rs_10x
rs_11x  btfss   var1_spg,0
	goto    rs_6		; bit rs_mode(7) = 0, octet recu = "00000110" = 0x06
	goto    rs_7		; bit rs_mode(7) = 0, octet recu = "00000111" = 0x07
rs_10x  btfss   var1_spg,0
	goto    rs_4		; bit rs_mode(7) = 0, octet recu = "00000100" = 0x04
	goto    rs_5		; bit rs_mode(7) = 0, octet recu = "00000101" = 0x05
rs_0xx  btfss   var1_spg,1
	goto    rs_00x
rs_01x  btfss   var1_spg,0
	goto    rs_2		; bit rs_mode(7) = 0, octet recu = "00000010" = 0x02
	goto    rs_3		; bit rs_mode(7) = 0, octet recu = "00000011" = 0x03
rs_00x  btfss   var1_spg,0
	goto    rs_0		; bit rs_mode(7) = 0, octet recu = "00000000" = 0x00
	goto    rs_1		; bit rs_mode(7) = 0, octet recu = "00000000" = 0x01
;
rs_1	bcf     indicateurs,rs_sel	; octet reçu = 0x01, 0x11, 0x21 ou 0x31 => test de ping
	swapf   var1_spg,w		; Si l'adresse de la carte est dans l'octet,
	andlw   0x07			; on sélectionne la carte
	sublw   CARDADR
	btfss   STATUS,Z		; btfss   STATUS,C modif FF
	goto    rs_fin
	bsf     indicateurs,rs_sel	; Adresse OK, => La carte est maintenant sélectionnée!
	movlw   0x83		; Octet de réponse au PC = 0x83
	call    tx
	goto    rs_fin

rs_2	movlw   0x81		; octet reçu = 0x02, => octet pour signaler que le prochain octet
	movwf   rs_mode		; est à placer dans le registre 'FSR' (pointeur)
	goto    rs_fin

rs_3	movlw   0x82		; octet reçu = 0x03, => octet pour signaler que le prochain octet
	movwf   rs_mode		; est à écrire dans [FSR] (adresse pointée par FSR)
	goto    rs_fin

rs_5	movlw   0x84		; octet reçu = 0x05, => octet pour signaler que le prochain octet
	movwf   rs_mode		; est à écrire dans [FSR] (adresse pointée par FSR) et incrémenter 'FSR'
	goto    rs_fin

rs_6	btfss   indicateurs,rs_sel	; octet reçu = 0x06, => octet pour signaler que le prochain octet
						; est à lire dans [FSR] (adresse pointée par FSR) et incrémenter 'FSR'
	goto    rs_fin		; Si la carte n'est pas sélectionnée => goto fin
	incf    rs_adr,f		; inc rs_adr = adresse du registre à lire and read

rs_4	btfss   indicateurs,rs_sel	; octet reçu = 0x04, => octet pour signaler que le prochain octet
						; est à lire dans [FSR] (adresse pointée par FSR)
	goto    rs_fin		; Si la carte n'est pas sélectionnée => goto fin
	movf    rs_adr,w
	movwf   FSR
	movf    INDF,w
	call    tx			; envoi de [FSR] au PC (contenu pointé par 'FSR')
	goto    rs_fin

rs_7	btfss   indicateurs,rs_sel	; octet reçu = 0x07, => octet pour signaler que le prochain octet
						; est à lire dans [FSR] puis on l'éfface (adresse pointée par FSR)
	goto    rs_fin		; Si la carte n'est pas sélectionnée => goto fin
	incf    rs_adr,f
	movf    rs_adr,w		; inc rs_adr = adresse du registre à lire and read + clear
	movwf   FSR
	movf    INDF,w
	clrf    INDF
	call    tx			; envoi de [FSR] au PC (contenu pointé par 'FSR')
	goto    rs_fin

rs_8	movlw   0x88		; octet reçu = 0x08, => octet pour signaler un début de transfert
	movwf   rs_mode		; automatique des données (lecture + écriture)
	movlw   0x20-1		; PREMIER_ECR - 1
	movwf   rs_adr
	bcf     indicateurs,rs_env	; V3.0 On est prêt à émettre un caractère une fois sur deux
					 ; mais il faut attendre que la réponse au 0x01 soit partie.

rs_0	goto    rs_fin		; octet reçu = 0x00, => Ne fait rien, re-synchonisation éventuelle
;
; rs_mode = B'1xxxxxxx' => On a reçu un octet de données
;
rs_l2y
	btfsc   rs_mode,3	;
	goto    rs_2_8
	bcf     rs_mode,7
	btfss   indicateurs,rs_sel	; Si la carte n'est pas sélectionnée => goto fin
	goto    rs_fin

	btfsc   rs_mode,0
	goto    rs_2_2
	btfsc   rs_mode,1
	goto    rs_2_3
	goto    rs_2_5
rs_2_2  movf    var1_spg,w		; set adr
	movwf   rs_adr
	goto    rs_fin
rs_2_5  incf    rs_adr,f	; inc adr and write
rs_2_3  movf    rs_adr,w	; write
	movwf   FSR
	movf    var1_spg,w
	movwf   INDF
	goto    rs_fin
;
; PREMIER_ECR = 0x20 = Adresse du premier octet en écriture vers le PIC
; DERNIER_ECR = 0x53 = Adresse du dernier octet en écriture vers le PIC
; PREMIER_LEC = 0x4F = Adresse du premier octet en lecture depuis le PIC
; PREMIER_LEC_EFF = 0x61 = Adresse du premier octet en lecture + éffacement depuis le PIC
; DERNIER_LEC = 0x6B = Adresse du dernier octet en lecture depuis le PIC
;
rs_2_8
	incf    rs_adr,f		; Global Transfert pointeur = rs_adr ='PREMIER_ECR' - 1 (au début)
	movlw   0x53		; 'DERNIER_ECR' = si dernière adresse d'écriture dans registre
	subwf   rs_adr,w		; W = 255 - 'DERNIER_ECR' + rs_adr
	btfsc   STATUS,Z
	bcf     rs_mode,7		; ne plus exécuter l2y, fin du mode données
	btfss   indicateurs,rs_sel	; Si la carte n'est pas sélectionnée => goto fin
	goto    rs_fin

	movf    rs_adr,w
	movwf   FSR			; Pointeur d'écriture = [FSR]
	movf    var1_spg,w	; 1 / Ecrit les données recues de 'PREMIER_ECR' à 'DERNIER_ECR'
	movwf   INDF		; Ecrit la donnée reçue à l'adresse pointée par [FSR] dans le PIC

	movlw   0x53-0x20		; 'DERNIER_ECR' - 'PREMIER_ECR'
	addwf   FSR,f		; pointeur de lecture = [FSR]
	movlw   0xFF-0x83		; 0xFF - 0x?? : car on n'envoi un octet une fois sur deux
	addwf   FSR,w
	btfsc   STATUS,C
	goto    rs_fin		; Si dernière adresse de lecture dans un registre

	btfsc   indicateurs,rs_env
	goto    c_env
;
; si  rs_env = 0  alors  rs_env = 1 + goto fin
; 'rs_env' permet d'envoyer un caractère au PC une fois sur deux, sinon on sature
; le buffer d'émission. A la premiere réception d'un caractère, on ne renvoi rien.
;
	bsf	  indicateurs,rs_env	; On n'enverra un caractère le prochain tour
	goto    rs_fin

c_env	bcf	  indicateurs,rs_env	; On n'enverra rien le prochain tour
	rrf     FSR,f		; divise par deux le pas
	movlw   0x2a		; 1er car. à envoyer = 'PREMIER_LEC'
	addwf   FSR,f
	movf    INDF,w		; 2 / Envoi les données au PC de ['PREMIER_LEC' à 'DERNIER_LEC'
	call    tx			; 3 / Efface les données envoyées au PC de 'PREMIER_LEC_EFF' à 'DERNIER_LEC'

	movlw   0xFF-0x61+1	; '0xFF' - 'PREMIER_LEC_EFF' + 1 = Derniers octets à éffacer
	addwf   FSR,w
	btfsc   STATUS,C
	clrf    INDF		; efface [FSR]
rs_fin
	return
;
; Caractère à envoyer vers le PC dans W
;
tx	BANK1				; passer en banque1
	btfss   TXSTA,TRMT	; attente que le dernier caractère soit parti
	goto    tx
	BANK0				; passer en banque0
	movwf   TXREG		; placer dans TXREG le caractère à envoyer
	return


;-----------------------------------------------------------------------------
; SSPG_CPT0 : Servos
; On calcul la valeur à envoyer sur la carte pour orienter le créneau vers le
; bon servo. L'aiguillage sera pris en compte quand cpt = 6 (validation des sorties).
; cpt_srv = B'0000XXXY' XXX = n° servo actif, si Y=1 => envoyer le créneau en sortie.
;
; cpt=0 : On incrément cpt_srv, On envoie en sortie le n° de servo actif = cpt_srv/2.
;
;             >---< = 2msec           >-------< = 4msec
; cpt =       0   0   0   0   0   0   0   0   0   0   0   0  => (sortie de cpt_srv/2)
; cpt_srv =   0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  1 
; n° servo =  0       1       2       3       4       0
; cpt =           7       7       7       7       7       7  => (sortie du créneau de cpt_srv/2)
;
maj_servo
	incf    cpt_srv,f
	movfw   cpt_srv
	sublw   .10			; .10 = 5 servos maximum.
	btfsc   STATUS,Z
	clrf    cpt_srv		; cpt_srv = 0,1,2...,8,9, 0,1,2
; Ensuite dans 'maj_out6', on envoi les bits : cpt_srv(3), cpt_srv(2) et cpt_srv(1) sur les sorties.
; Le bit : cpt_srv(0)=0 sert à connaitre le début du créneau.
	return


;-----------------------------------------------------------------------------
; SSPG_CPT1 : Calcul du multiplexage des leds
;             Calcul des octets à envoyer en sortie = out_out1 et out_out2
;             A chaque passage, change le numéro de colonne à activer = out_out2(4 à 7)
;
; LED 00-07 = led_on0  (allumée) + led_cl0 (clignotante)  + led_in0 (clignotant inversé)
; LED 08-12 = led_on01 (allumée) + led_cl01 (clignotante) + led_in01 (clignotant inversé) [QUARTE de DROITE]
; LED 13-20 = led_on1  (allumée) + led_cl1 (clignotante)  + led_in1 (clignotant inversé)
; LED 13-20 = led_on01 (allumée) + led_cl01 (clignotante) + led_in01 (clignotant inversé) [QUARTE de GAUCHE]
; ...
;
cal_led
	clrw
	btfsc		cpt2,3		; cpt2 = Compteur incrémenté tous les 256 interruptions du Timer0 (64 ms à 20Mhz)
	movlw		0xff
	movwf		var1_spg		; var1_spg passe de 00 à FF toutes les 1,6 secondes (comme la led jaune)
	btfsc		cpt,4
	goto		led_1X
led_0X  btfss	cpt,3
	goto		led_0
	goto		led_1
led_1X  btfss	cpt,3
	goto		led_2
	goto		led_3

led_0	movf    var1_spg,w		; cpt = B'---00---'
	xorwf   led_in0,w
	iorwf   led_cl0,w
	andwf   led_on0,w
	movwf   out_out1		; out_out1 = sortie leds 0 à 7

	movf    var1_spg,w
	xorwf   led_in01,w
	iorwf   led_cl01,w
	andwf   led_on01,w
	andlw   0x0f
	movwf   out_out2		; out_out2 = sortie leds 8 à 11 + sélection colonne A
	bsf     out_out2,4
	goto    led_f

led_1	movf    var1_spg,w		; cpt = B'---01---'
	xorwf   led_in1,w
	iorwf   led_cl1,w
	andwf   led_on1,w
	movwf   out_out1
	movf    var1_spg,w
	xorwf   led_in01,w
	iorwf   led_cl01,w
	andwf   led_on01,w
	movwf   out_out2
	swapf   out_out2,w
	andlw   0x0f
	movwf   out_out2
	bsf     out_out2,5	; out_out2 = sortie leds 8 à 11 + sélection colonne B
	goto    led_f

led_2	movf    var1_spg,w		; cpt = B'---10---'
	xorwf   led_in2,w
	iorwf   led_cl2,w
	andwf   led_on2,w
	movwf   out_out1
	movf    var1_spg,w
	xorwf   led_in23,w
	iorwf   led_cl23,w
	andwf   led_on23,w
	andlw   0x0f
	movwf   out_out2
	bsf     out_out2,6	; out_out2 = sortie leds 8 à 11 + sélection colonne C
	goto    led_f

led_3	movf    var1_spg,w		; cpt = B'---11---'
	xorwf   led_in3,w
	iorwf   led_cl3,w
	andwf   led_on3,w
	movwf   out_out1
	movf    var1_spg,w
	xorwf   led_in23,w
	iorwf   led_cl23,w
	andwf   led_on23,w
	movwf   out_out2
	swapf   out_out2,w
	andlw   0x0f
	movwf   out_out2
	bsf     out_out2,7	; out_out2 = sortie leds 8 à 11 + sélection colonne D
	goto    led_f
led_f	return


;-----------------------------------------------------------------------------
; SSPG_CPT2 : Lecture des 5 entrées analogiques, une à la fois (sans utiliser les interruptions CAN)
;             Résultat dans : can_r0, can_r1 ... can_r4
;             A 250 µs lecture de toutes les entrées analogiques en 16 ms = 60 Hz
;
;   maj_can1 = Lecture ADRESH + choix du canal + lancement du convertisseur, bit ADCON0,ON = 1
;              et attente de 23µs minimum à 20 Mhz
;   maj_can2 = Démarrage de la conversion + bit ADCON0,GO_DONE = 1
;              et attente de la fin de la conversion
; ADCON0 :
;   ADCS10  =  10 = F conversion = Fosc/32 si Quartz > 5 Mhz
;   CHS210  = nnn = n° du canal de conversion en cours
;   GO/DONE =   0 = à mettre à 1 après une conversion
;   nc      =   0
;   ADON    =   1 = Mise en route du convertisseur
;
maj_can1				; Lecture ADRESH + choix canal + lancement convert, bit ADCON0,ON = 1
;
	movf		cpt,w		; cpt = '--yyy---' yyy = n° de canal CAN
	andlw		B'00111000'
	sublw		B'00100000'
	btfss		STATUS,C
	return			; goto fin si yyy > 4

	rlf		cpt,w		; w   = '-yyy----' avec yyy = 0 à 4 !
	andlw		B'01110000' ; w   = '0yyy0000'
	movwf		FSR
	swapf		FSR,f		; FSR = '00000yyy'
	movlw		can_r0
	addwf		FSR,f		; FSR = adresse can_r0 + n° du canal en cours de lecture = adresse can_rX
	movf		ADRESH,w	; Lecture de la conversion A/N sur un octet
	movwf		INDF		; Ecriture dans [INDF] = can-r0 à can_r4
;
; Préparation de la prochaine conversion A/N
;
	movf		cpt,w		; w   = '--yyy---'
	andlw		B'00111000' ; w   = '00yyy000'
	xorlw		B'00100000'
	btfsc		STATUS,Z	; Si le canal = n°4, le prochain canal sera le n° 0
	movlw		B'11011000'
	xorlw		B'00100000'
	addlw		B'00001000'
	iorlw		B'10000001'
	movwf		ADCON0	; ADCON0 = '10xxx001' avec xxx = yyy + 1
	return


;-----------------------------------------------------------------------------
; SSPG_CPT3 : Clignotement de la led jaune
;
maj_sig
	btfss		cpt2,3	; clignotement de la led jaune sur (RA4) (1.92Hz)
	bcf		PORTA,4	; led jaune = on = 16 * 256 * 250 µs
	btfsc		cpt2,3
	bsf		PORTA,4	; led jaune = off
	return


;-----------------------------------------------------------------------------
; SSPG_CPT4 : Préparation à la conversion A/N
;
maj_can2				; Démarrage de la conversion, bit ADCON0,GO_DONE = 1
	bsf		ADCON0,GO_DONE
	return


;-----------------------------------------------------------------------------
; SSPG_CPT6 : Lecture de la matrice des contacts d'entrée = INA à INB x 4 bits
; Attention en V3.1, la patte PORTC(2) sert à commander les servos..
; L'entrée PORTC(2) est remplacée par l'entrée PORTB(0). = C3,B0,C1,C0
;
; Le 30/01/2015 : Nouvelle tempo en lecture du clavier. 
;
; Les 4 bits de droite sont automatiquement effacés juste après leur lecture.
; mat_in0 = 4 bits de la colonne INA + 4 bits du même état mémorisé
; mat_in1 =  // INB
; mat_in2 =  // INC
; . . . .
; mat_in8 =  // INI
;
; En V3.0 Horloge = C(4) est passée en B(1). 
; Il faut remettre toute les sorties du 74HCT4094 à '1' avant de commencer,
; car cette sortie est aussi utilisée par d'autre fonctions.
;
maj_in
	bsf   PORTC,DATMAT	; En V3.0 pour retrouver les 9 sorties à 1
	nop
	CK_UD_DAT
	CK_UD_DAT
	CK_UD_DAT

	CK_UD_DAT
	CK_UD_DAT
	CK_UD_DAT

	CK_UD_DAT
	CK_UD_DAT
	CK_UD_DAT

	bcf   PORTC,DATMAT
	nop
	bcf   PORTB,CLKMAT
	nop
	nop

	bsf   PORTB,CLKMAT	; Sortie (A) = 0 !
	nop
	nop                     ; Ajout de 10 "nop" en V3.3 le 20/02/2015 pour éviter des erreurs de lecture
	nop                     ; en double d'un clavier multiplexé.
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in0,f		; mat_in0 = "0000YYYY"  Y = ancien état mémorisé
	comf  PORTC,w		; w = inverse(PORTC), X = 1 si le contact est fermé
	bcf   PORTB,CLKMAT
	bsf   PORTC,DATMAT	; Remet la sortie à 1 (Le créneau 0 en sortie défile)
	andlw B'00001011'		; w = "0000X0XX", seul les bits C3, C1 et C0 sont utilisés. 
	btfss PORTB,0		; Le bit C2 est utilisé pour la commande des servos
	iorlw B'00000100'		; Le bit C2 est remplacé par l'entrée B0
	iorwf mat_in0,f		; 'OU' mat_in0 OU (0000XXXX", X = 1 contact fermé) => mat_in0
	movwf var1_spg		; var1_spg = "0000XXXX", X = 1 contact fermé
	swapf var1_spg,w		; var1_spg = "XXXX0000", X = 1 contact fermé
	iorwf mat_in0,f		; 'OU' mat_in0 = OU ("XXXXYYYY", X = 1 contact fermé, mat_in0)

	bsf   PORTB,CLKMAT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in1,f
	comf  PORTC,w
	bcf   PORTB,CLKMAT
	andlw B'00001011'
	btfss PORTB,0
	iorlw B'00000100'
	iorwf mat_in1,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in1,f

	bsf   PORTB,CLKMAT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in2,f
	comf  PORTC,w
	bcf   PORTB,CLKMAT
	andlw B'00001011'
	btfss PORTB,0
	iorlw B'00000100'
	iorwf mat_in2,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in2,f

	bsf   PORTB,CLKMAT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in3,f
	comf  PORTC,w
	bcf   PORTB,CLKMAT
	andlw B'00001011'
	btfss PORTB,0
	iorlw B'00000100'
	iorwf mat_in3,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in3,f

	bsf   PORTB,CLKMAT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in4,f
	comf  PORTC,w
	bcf   PORTB,CLKMAT
	andlw B'00001011'
	btfss PORTB,0
	iorlw B'00000100'
	iorwf mat_in4,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in4,f

	bsf   PORTB,CLKMAT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in5,f
	comf  PORTC,w
	bcf   PORTB,CLKMAT
	andlw B'00001011'
	btfss PORTB,0
	iorlw B'00000100'
	iorwf mat_in5,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in5,f

	bsf   PORTB,CLKMAT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in6,f
	comf  PORTC,w
	bcf   PORTB,CLKMAT
	andlw B'00001011'
	btfss PORTB,0
	iorlw B'00000100'
	iorwf mat_in6,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in6,f

	bsf   PORTB,CLKMAT
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in7,f
	comf  PORTC,w
;;;;	bcf   PORTB,CLKMAT	; reporté plus loin, car la sortie /QS
	andlw B'00001011'		; est spéciale.
	btfss PORTB,0
	iorlw B'00000100'
	bcf   PORTB,CLKMAT	; reporté ici
	iorwf mat_in7,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in7,f

	bsf   PORTB,CLKMAT	; Utilise la sortie /QS
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	movlw B'00001111'
	andwf mat_in8,f
	comf  PORTC,w
;;;	bcf   PORTB,CLKMAT	; Surtout pas sur /QS
	andlw B'00001011'
	btfss PORTB,0
	iorlw B'00000100'
	iorwf mat_in8,f
	movwf var1_spg
	swapf var1_spg,w
	iorwf mat_in8,f

	bcf   PORTB,CLKMAT	; RAZ
	return


;-----------------------------------------------------------------------------
; SSPG_CPT7 : Commande du créneau pour les servos.
; 
; Utilise le 'Timer1' en mode 'Compare' sans interruption.
; si TMR1 = CCP1 alors la sortie PORTC(2) passe à 1 (modif du CI obligatoire).
; Le signal en sortie de CD4028 est inversé par rapport au créneau en sortie du PIC
; Commande de 5 servos maximum, car 5 * 4 msec = 20 msec max par servo
;
; Si cpt_srv(0)=1, il faut positionner la sortie (créneau de 1 à 2 msec)
; Avec le prédiviseur à 8, le pas du Timer1 = 1,6 µs à 20 Mhz
; Position du servo  min,  moyen,  max :
;   srv_x   =    0       |  128       |   255
;   Créneau =  1,0 msec  |  1,5 msec  |   2,0 msec
;   Timer1  =  625 min   |  937 moyen |  1250 max
;
cal_servo
	btfsc cpt_srv,0		; cpt_srv = n°de servo en cours(7bits) + 1bit (1=activer timer1)
	return			; return si cpt_srv(0) = 1

	movf	cpt_srv,w		; cpt_srv = 2 * numéro du servo en cours.
	movwf	var1_spg
	bcf	STATUS,C		; 0 - > CARRY (décalage de 2 bits vers la droite = division par 2)
	rrf	var1_spg,w
	addlw	srv_0
	movwf	FSR			; FSR = srv_0 à srv_5.
	movf	INDF,w		; w = [srv_0] à [srv_5].
	BANK1
;
; Convertie la valeur 0-255 en 625-1250 = Valeur*2,5 + 620
;   val_srv ===> val_srvH/val_srvL
;
	movwf	val_srv		; val_srv = valeur de consigne entre 0 et 255 = valeur de servo[X].
	movwf	val_srvL
	clrf	val_srvH
	bcf	STATUS,C		; 0 - > CARRY (décalage de 1 bit vers la gauche = multiplication par 2)
	rlf	val_srvL,f
	rlf	val_srvH,f		; val_srvL/H = valeur * 2 
	bcf	STATUS,C		; 0 - > CARRY (décalage de 1 bit vers la droite = division par 2)
	rrf	val_srv,f		; val_srv = valeur / 2
	movf	val_srv,w
	addwf val_srvL,f
	btfsc	STATUS,C
	incf	val_srvH,f		; val_srvH/L = valeur * 2,5
	movlw	.113
	addwf	val_srvL,f		; +620 (= +2*256 + 113)
	movlw	.2
	btfsc	STATUS,C
	movlw	.2+.1
	addwf	val_srvH,f		; val_srvH/L = valeur * 2,5 + 620
;
; Mise à 1 de la sortie PORTC(2)  (forçage par comparaison, 0=0)
;
	BANK0
	bcf	T1CON,TMR1ON	; Arrête le timer 'TMR1' + raz
	bcf	PIR1,TMR1IF
	clrf	TMR1L
	clrf	TMR1H
	clrf	CCPR1L
	clrf	CCPR1H
	movlw	B'00001000'		; Force la sortie à 1 si égalité TMR1 = CCPR1
	movwf	CCP1CON
	bsf	T1CON,TMR1ON	; Lance le timer 'TMR1'
;
; Départ du créneau qui retombera tout seul.
;
	BANK1
	movf	val_srvH,w
	BANK0
	movwf	CCPR1H
	BANK1
	movf	val_srvL,w
	BANK0
	movwf	CCPR1L
	movlw	B'00001001'		; La sortie passera à 0 quand le compteur TMR1 = CCPR1
	movwf	CCP1CON
	return


;-----------------------------------------------------------------------------
; SSPG_CPT0 : Envoi uniquement les 8 bits des sorties système du PIC (servos,,,)
;             Lecture simultanée des entrées [2].
;
; A 20 Mhz, une instruction = 200 ns, il ne faut pas faire deux
; écritures/lecture successives sur le même port, il faut insérer un nop.
; Servos : On envoi les bits : cpt_srv(3), cpt_srv(2) et cpt_srv(1)
; + bits 'cpt' en attendant une autre utilisation
;
maj_out6
	clrf	in_in1		; Effacement de l'octet de stockage des entrées [2]

	btfss PORTC,DATIN2
	bsf	in_in1,6
	btfss	cpt,7			; 7 : 'cpt' en attendant une autre utilisation
	CK_DOWN_OUT
	btfsc	cpt,7			; 7 : 'cpt' en attendant une autre utilisation
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in1,4
	btfss	cpt,6			; 6 : 'cpt' en attendant une autre utilisation
	CK_DOWN_OUT
	btfsc	cpt,6			; 6 : 'cpt' en attendant une autre utilisation
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in1,2
	btfss	cpt_srv,2		; 5 : n° servo 0X00
	CK_DOWN_OUT
	btfsc	cpt_srv,2		; 5 : n° servo 0X00
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in1,0
	btfss	cpt_srv,3		; 4 : n° servo X000
	CK_DOWN_OUT
	btfsc	cpt_srv,3		; 4 : n° servo X000
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in1,1
	btfss	cpt,5			; 3 : 'cpt' en attendant une autre utilisation
	CK_DOWN_OUT
	btfsc cpt,5			; 3 : 
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in1,3		; 2 :
	btfss	cpt,4
	CK_DOWN_OUT
	btfsc cpt,4			; 2 :
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in1,5
	btfss	cpt,3			; 1 :
	CK_DOWN_OUT
	btfsc cpt,3			; 1 :
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in1,7
	btfss	cpt_srv,1		; 0 : n° servo 00X0
	CK_DOWN_OUT
	btfsc	cpt_srv,1		; 0 : n° servo 00X0
	CK_UP_OUT
	return


;-----------------------------------------------------------------------------
; SSPG_CPT1 : Envoi les données vers les relais et les leds multiplexées
;             Envoi des bits des sorties  16 à 23  (IC16-ULN2008)
;
maj_out5
	clrf	in_in2		; Effacement de l'octet de stockage des entrées [2]

	btfss PORTC,DATIN2
	bsf	in_in2,6
	btfss out_out5,7
	bcf   PORTB,DATOUT
	btfss out_out25,7		; (out 47)
	CK_DOWN_OUT
	btfsc out_out5,7
	bsf   PORTB,DATOUT
	btfsc out_out25,7
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in2,4
	btfss out_out5,6
	bcf   PORTB,DATOUT
	btfss out_out25,6		; (out 46)
	CK_DOWN_OUT
	btfsc out_out5,6
	bsf   PORTB,DATOUT
	btfsc out_out25,6
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in2,2
	btfss out_out5,5
	bcf   PORTB,DATOUT
	btfss out_out25,5		; (out 45)
	CK_DOWN_OUT
	btfsc out_out5,5
	bsf   PORTB,DATOUT
	btfsc out_out25,5
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in2,0
	btfss out_out5,4
	bcf   PORTB,DATOUT
	btfss	out_out25,4
	CK_DOWN_OUT
	btfsc out_out5,4
	bsf   PORTB,DATOUT
	btfsc out_out25,4
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in2,1
	btfss out_out5,3
	bcf   PORTB,DATOUT
	btfss	out_out25,3
	CK_DOWN_OUT
	btfsc out_out5,3
	bsf   PORTB,DATOUT
	btfsc out_out25,3
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in2,3
	btfss out_out5,2
	bcf   PORTB,DATOUT
	btfss	out_out25,2
	CK_DOWN_OUT
	btfsc out_out5,2
	bsf   PORTB,DATOUT
	btfsc out_out25,2
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in2,5
	btfss out_out5,1
	bcf   PORTB,DATOUT
	btfss	out_out25,1
	CK_DOWN_OUT
	btfsc out_out5,1
	bsf   PORTB,DATOUT
	btfsc out_out25,1
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in2,7
	btfss out_out5,0
	bcf   PORTB,DATOUT
	btfss	out_out25,0
	CK_DOWN_OUT
	btfsc out_out5,0
	bsf   PORTB,DATOUT
	btfsc out_out25,0
	CK_UP_OUT
	return


;-----------------------------------------------------------------------------
; SSPG_CPT2 : Envoi les données vers les relais et les leds multiplexées
;             Envoi des bits des sorties  8 à 15  (IC15-ULN2008)
maj_out4
	clrf	in_in3		; Effacement de l'octet de stockage des entrées [2]

	btfss PORTC,DATIN2
	bsf	in_in3,6
	btfss out_out4,7
	bcf   PORTB,DATOUT
	btfss	out_out24,7
	CK_DOWN_OUT
	btfsc out_out4,7
	bsf   PORTB,DATOUT
	btfsc out_out24,7
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in3,4
	btfss out_out4,6
	bcf   PORTB,DATOUT
	btfss	out_out24,6
	CK_DOWN_OUT
	btfsc out_out4,6
	bsf   PORTB,DATOUT
	btfsc out_out24,6
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in3,2
	btfss out_out4,5
	bcf   PORTB,DATOUT
	btfss	out_out24,5
	CK_DOWN_OUT
	btfsc out_out4,5
	bsf   PORTB,DATOUT
	btfsc out_out24,5
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in3,0
	btfss out_out4,4
	bcf   PORTB,DATOUT
	btfss	out_out24,4
	CK_DOWN_OUT
	btfsc out_out4,4
	bsf   PORTB,DATOUT
	btfsc out_out24,4
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in3,1
	btfss out_out4,3
	bcf   PORTB,DATOUT
	btfss	out_out24,3
	CK_DOWN_OUT
	btfsc out_out4,3
	bsf   PORTB,DATOUT
	btfsc out_out24,3
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in3,3
	btfss out_out4,2
	bcf   PORTB,DATOUT
	btfss	out_out24,2
	CK_DOWN_OUT
	btfsc out_out4,2
	bsf   PORTB,DATOUT
	btfsc out_out24,2
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in3,5
	btfss out_out4,1
	bcf   PORTB,DATOUT
	btfss	out_out24,1
	CK_DOWN_OUT
	btfsc out_out4,1
	bsf   PORTB,DATOUT
	btfsc out_out24,1
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in3,7
	btfss out_out4,0
	bcf   PORTB,DATOUT
	btfss	out_out24,0
	CK_DOWN_OUT
	btfsc out_out4,0
	bsf   PORTB,DATOUT
	btfsc out_out24,0
	CK_UP_OUT
	return

;-----------------------------------------------------------------------------
; SSPG_CPT3 : Envoi les données vers les relais et les leds multiplexées
;             Envoi des bits des sorties  1 à 7  (IC14-ULN2008)
maj_out3
	clrf	in_in4		; Effacement de l'octet de stockage des entrées [2]

	btfss PORTC,DATIN2
	bsf	in_in4,6
	btfss out_out3,7
	bcf   PORTB,DATOUT
	btfss	out_out23,7
	CK_DOWN_OUT
	btfsc out_out3,7
	bsf   PORTB,DATOUT
	btfsc out_out23,7
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in4,4
	btfss out_out3,6
	bcf   PORTB,DATOUT
	btfss	out_out23,6
	CK_DOWN_OUT
	btfsc out_out3,6
	bsf   PORTB,DATOUT
	btfsc out_out23,6
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in4,2
	btfss out_out3,5
	bcf   PORTB,DATOUT
	btfss	out_out23,5
	CK_DOWN_OUT
	btfsc out_out3,5
	bsf   PORTB,DATOUT
	btfsc out_out23,5
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in4,0
	btfss out_out3,4
	bcf   PORTB,DATOUT
	btfss	out_out23,4
	CK_DOWN_OUT
	btfsc out_out3,4
	bsf   PORTB,DATOUT
	btfsc out_out23,4
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in4,1
	btfss out_out3,3
	bcf   PORTB,DATOUT
	btfss	out_out23,3
	CK_DOWN_OUT
	btfsc out_out3,3
	bsf   PORTB,DATOUT
	btfsc out_out23,3
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in4,3
	btfss out_out3,2
	bcf   PORTB,DATOUT
	btfss	out_out23,2
	CK_DOWN_OUT
	btfsc out_out3,2
	bsf   PORTB,DATOUT
	btfsc out_out23,2
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in4,5
	btfss out_out3,1
	bcf   PORTB,DATOUT
	btfss	out_out23,1
	CK_DOWN_OUT
	btfsc out_out3,1
	bsf   PORTB,DATOUT
	btfsc out_out23,1

	CK_UP_OUT
	btfss PORTC,DATIN2
	bsf	in_in4,7
	btfss out_out3,0
	bcf   PORTB,DATOUT
	btfss	out_out23,0
	CK_DOWN_OUT
	btfsc out_out3,0
	bsf   PORTB,DATOUT
	btfsc out_out23,0
	CK_UP_OUT
	return

;-----------------------------------------------------------------------------
; SSPG_CPT4 : Envoi les données vers les relais et les leds multiplexées
;             Envoi des bits des leds  8 à 11 et A à D (IC13-ULN2008)
maj_out2
	clrf	in_in5		; Effacement de l'octet de stockage des entrées [2]

	btfss PORTC,DATIN2
	bsf	in_in5,6
	btfss out_out2,7
	bcf   PORTB,DATOUT
	btfss	out_out22,7
	CK_DOWN_OUT
	btfsc out_out2,7
	bsf   PORTB,DATOUT
	btfsc out_out22,7
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in5,4
	btfss out_out2,6
	bcf   PORTB,DATOUT
	btfss	out_out22,6
	CK_DOWN_OUT
	btfsc out_out2,6
	bsf   PORTB,DATOUT
	btfsc out_out22,6
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in5,2
	btfss out_out2,5
	bcf   PORTB,DATOUT
	btfss	out_out22,5
	CK_DOWN_OUT
	btfsc out_out2,5
	bsf   PORTB,DATOUT
	btfsc out_out22,5
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in5,0
	btfss out_out2,4
	bcf   PORTB,DATOUT
	btfss	out_out22,4
	CK_DOWN_OUT
	btfsc out_out2,4
	bsf   PORTB,DATOUT
	btfsc out_out22,4
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in5,1
	btfss out_out2,3
	bcf   PORTB,DATOUT
	btfss	out_out22,3
	CK_DOWN_OUT
	btfsc out_out2,3
	bsf   PORTB,DATOUT
	btfsc out_out22,3
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in5,3
	btfss out_out2,2
	bcf   PORTB,DATOUT
	btfss	out_out22,2
	CK_DOWN_OUT
	btfsc out_out2,2
	bsf   PORTB,DATOUT
	btfsc out_out22,2
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in5,5
	btfss out_out2,1
	bcf   PORTB,DATOUT
	btfss	out_out22,1
	CK_DOWN_OUT
	btfsc out_out2,1
	bsf   PORTB,DATOUT
	btfsc out_out22,1
	CK_UP_OUT

	btfss PORTC,DATIN2
	bsf	in_in5,7
	btfss out_out2,0
	bcf   PORTB,DATOUT
	btfss	out_out22,0
	CK_DOWN_OUT
	btfsc out_out2,0
	bsf   PORTB,DATOUT
	btfsc out_out22,0
	CK_UP_OUT

	return

;-----------------------------------------------------------------------------
; SSPG_CPT5 : Envoi les données vers les relais et les leds multiplexées
;             Envoi des bits des leds  1 à 7 et validation des 74HCT4094
maj_out1
	btfss out_out1,7
	bcf   PORTB,DATOUT
	btfss	out_out21,7
	CK_DOWN_OUT
	btfsc out_out1,7
	bsf   PORTB,DATOUT
	btfsc out_out21,7
	CK_UP_OUT

	btfss out_out1,6
	bcf   PORTB,DATOUT
	btfss	out_out21,6
	CK_DOWN_OUT
	btfsc out_out1,6
	bsf   PORTB,DATOUT
	btfsc out_out21,6
	CK_UP_OUT

	btfss out_out1,5
	bcf   PORTB,DATOUT
	btfss	out_out21,5
	CK_DOWN_OUT
	btfsc out_out1,5
	bsf   PORTB,DATOUT
	btfsc out_out21,5
	CK_UP_OUT

	btfss out_out1,4
	bcf   PORTB,DATOUT
	btfss	out_out21,4
	CK_DOWN_OUT
	btfsc out_out1,4
	bsf   PORTB,DATOUT
	btfsc out_out21,4
	CK_UP_OUT

	btfss out_out1,3
	bcf   PORTB,DATOUT
	btfss	out_out21,3
	CK_DOWN_OUT
	btfsc out_out1,3
	bsf   PORTB,DATOUT
	btfsc out_out21,3
	CK_UP_OUT

	btfss out_out1,2
	bcf   PORTB,DATOUT
	btfss	out_out21,2
	CK_DOWN_OUT
	btfsc out_out1,2
	bsf   PORTB,DATOUT
	btfsc out_out21,2
	CK_UP_OUT

	btfss out_out1,1
	bcf   PORTB,DATOUT
	btfss	out_out21,1
	CK_DOWN_OUT
	btfsc out_out1,1
	bsf   PORTB,DATOUT
	btfsc out_out21,1
	CK_UP_OUT

	btfss out_out1,0
	bcf   PORTB,DATOUT
	btfss	out_out21,0
	CK_DOWN_OUT
	btfsc out_out1,0
	bsf   PORTB,DATOUT
	btfsc out_out21,0
	CK_UP_OUT

	nop
	nop
	bsf   PORTB,LODOUT
	nop
	nop
	nop
	bcf   PORTB,LODOUT	; Impulsion de validation de 800 ns
	return



;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------

; Début du code d'initialisation en page n°1, 0x800 pour laisser de la place au programme
; principal en page n°0 0x000-0x7FF.
; Attention, ici les 'call' ne font appel qu'à des sous-programmes en page n°1
;
	ORG     0x800		; Le code débute à l'origine de la page n°1
init	call    init_port		; Initialise les ports A, B et C et les variables d'entrées/sortie
	call    init_can		; Initialise les ports CAN (conversion analogique numérique)
	call    init_pwm		; Initialise toutes les variables de la partie pwm
	call    init_led		; Initialise toutes les variables de la partie led
	call    init_srv		; Initialise CCPxCON et les variables de la partie servo
	call    init_rs232	; Initialise la liaison série
	call    init_timer	; Initialise le Timer0 (TMR0)
	call    init_det		; Initialise les variables de détection d'occupation des cantons
	call    init_it		; Initialise la gestion des interruptions
	return			; Retourne en page n° 0 (0x000 - 0x7FF)

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise les ports A, B et C et les variables d'entrées / sortie
;
init_port
	clrf    PORTB		; initialisation de toutes les sorties à 0
	clrf    PORTA
	clrf    PORTC

	BANK1				; passer en banque1
	movlw   B'00101111'	; PORTA bit4 en sortie (B4 = led clignotante)
	movwf   TRISA

	movlw   B'00001001'	; PORTB en sortie(sauf en entrée B3 = capteur de canton, B0 = in mux)
	movwf   TRISB

	movlw   B'10011011'	; PORTC en entrée, sauf C2 = Servo, C6 = rx max232 et C5 = OUT en V3.0
	movwf   TRISC
	BANK0				; passer en banque0

	clrf    out_out1		; out_out(x) = 0
	clrf    out_out2
	clrf    out_out3
	clrf    out_out4
	clrf    out_out5

	clrf    out_out21		; nouveau en V3.0
	clrf    out_out22
	clrf    out_out23
	clrf    out_out24
	clrf    out_out25

	clrf    out_pwm1		; out_pwm(x) = 0
	clrf    out_pwm2
	clrf    out_pwm3
	clrf    out_pwm4

	clrf    mat_in0		; mat_in(x) = 0
	clrf    mat_in1
	clrf    mat_in2
	clrf    mat_in3
	clrf    mat_in4
	clrf    mat_in5
	clrf    mat_in6
	clrf    mat_in7
	clrf    mat_in8

	clrf    in_in1
	clrf    in_in2
	clrf    in_in3
	clrf    in_in4
	clrf    in_in5
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise le convertisseur analogique / numérique
;
; ADCON0
;   ADCS10  =   10 = F conversion = Fosc/32 car le quartz est à 20 Mhz
;   CHS210  =  xxx = n° du canal de conversion CAN en cours
;   GO/DONE =    0 = A mettre à '1' après une conversion
;   nc      =    0
;   ADON    =    1 = Mise en route du convertisseur
;
; ADCON1
;   ADFM    =    0 = Résultat justifié à gauche
;   ADCS2   =    0 = F conversion = Fosc/32 car le quartz est à 20 Mhz
;   nc nc   =   00
;   PCFG    = 0010 = RA0 à RA4 = entrées analogiques, Vref = +5 V et +0 V,
;
init_can
	BANK0				; passer en banque0
	movlw   B'10000001'	; Fosc/32 + Convertisseur = ON
	movwf   ADCON0
	BANK1				; passer en banque1
	movlw   B'00000010'	; Résultat de conversion dans ADRESH (8bits) + ADRESL (4bits)
	movwf   ADCON1		; RESADRH 8bits toutes entrées can en mode can
	BANK0				; passer en banque0
	movlw   .128		; 128 = position médiane des potentiomètres.
	movwf   can_r0
	movwf   can_r1
	movwf   can_r2
	movwf   can_r3
	movwf   can_r4
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise les variables de la partie PWM (consignes voies)
;
init_pwm
	clrf    pwm_cpt		; pwm_cpt  = 0
	clrf    pwm_r0		; pwm_r(x) = 0 = vitesse par canton
	clrf    pwm_r1		; Rails pas alimenté au départ
	clrf    pwm_r2
	clrf    pwm_r3
	clrf    pwm_r4
	clrf    pwm_r5
	clrf    pwm_r6
	clrf    pwm_r7
	clrf    pwm_r8
	clrf    pwm_r9
	clrf    pwm_r10
	clrf    pwm_r11
	clrf    pwm_r12
	clrf    pwm_r13
	clrf    pwm_r14
	clrf    pwm_r15
	clrf    pwm_s0_7		; pwm_s(x) = 0 = sens de déplacement par canton
	clrf    pwm_s8_15
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise les variables de la partie leds multipléxées
;
init_led
	clrf  led_on0	; led_on(x) = 0
	clrf  led_on1	; Etient les leds
	clrf  led_on01
	clrf  led_on2
	clrf  led_on3
	clrf  led_on23

	movlw 0xff
	movwf led_cl0	; led_c(x) = 0xFF
	movwf led_cl1	; Pas de clignotement
	movwf led_cl01
	movwf led_cl2
	movwf led_cl3
	movwf led_cl23

	clrf  led_in0	; led_in(x) = 0
	clrf  led_in1	; Clignotement pas altérnées
	clrf  led_in01
	clrf  led_in2
	clrf  led_in3
	clrf  led_in23
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise la configuration CCP1CON et les variables de la partie servo
;
; T1CON = B'00110001'
;   nc  nc  = 00 = Pas utilisé
;   T1CKPS  = 11 = Prédiviseur du Timer1 = 8,      (un pas = 1,6 µsec à 20 Mhz)
;   T1OSCEN =  0 = Oscillateur interne à off
;   T1SYN   =  0 = Pas utile si TMR1ON = 1
;   TMR1CS  =  0 = Source prédiviseur = Fosc/4/T1CKPS
;   TMR1ON  =  1 = Autorise le timer à fonctionner (le compteur défile)
;
; CCP1CON = B'00001001'
;   nc  nc  = 00 = pas utilisé
;   CCP1X   =  0 = pas utilisé, module compare, bit x
;   CCP1Y   =  0 = pas utilisé, module compare, bit y
;   CCP1M   = 1000 = module compare => si égalité place la sortie à 1 (+ bit CCP1IF =1)
;
;   Créneau =  1,0 msec  |  1,5 msec  |   2,0 msec
;   Timer1  =  625 min   |  937 moyen |  1250 max
;
init_srv
	movlw   B'00110001'	; Pas du Timer1 = 1,6 µs à 20 Mhz
	movwf   T1CON
	movlw   B'00001001'
	movwf   CCP1CON		; Mode 'compare' place la sortie à 0 sur égalité + bit CCP1IF =1
	movlw   .128		; 128 = position centrale pour les servos = 1,5 msec.
	movwf   srv_0		; 5 servos
	movwf   srv_1
	movwf   srv_2
	movwf   srv_3
	movwf   srv_4
	clrf    cpt_srv		; raz variable n° de servo
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise la liaison série
;
; Calcul de SPBRG = (Fosc / ( 16 * Bd[liaison série])) - 1
; Vitesse baud =  9600   19200  [38400]
; Fréq = 20 Mhz    129     64     [32]
;
; TXSTA = B'00100100'
;   CSRC = 0 = pas utilisé
;   TX9  = 0 = caractère sur 8 bits
;   TXEN = 1 = transmission autorisée
;   SYNC = 0 = mode asynchrone
;   nc   = 0
;   BRGH = 1 = mode haute vitesse (Fosc / 16)
;   TRMT = 0 = registre d'envoi vide
;   TX9D = 0 = valeur du 9 eme bit
;
; RCSTA = B'10010000'
;   SPEN  = 1 = port série autorisé
;   RX9   = 0 = caractères sur 8 bits
;   SREN  = 0 pas utilisé
;   CREN  = 1 = autorise la réception en continue
;   ADDEN = 0 pas utilisé
;   FERR  = 0 = Pas d'erreur de trame
;   OERR  = 0 pas utilisé
;   RX9D  = 0 = 9émé bit ou bit de parité
;
init_rs232
	BANK1				; passer en banque1
	movlw   .32			; 32 = 38400 bauds (hight vitesse)
	movwf   SPBRG		; SPBRG = Serial Port Bit Rate Generator = (Fosc/(16*D))-1
					; (20.000.000/(16*38.400))-1 = 32
	movlw   B'00100100'	; asynchrone, tx enable, hight vit
	movwf   TXSTA
	BANK0				; passer en banque0
	movlw   B'10010000'
	movwf   RCSTA		; port série autorisé
	bcf     PIR1,RCIF		; Le flag "buffer de réception" est vidé
	clrf    indicateurs	; Carte désélectionnée
	clrf    rs_adr		; 
	clrf    rs_mode		; rs_mode = 0 = attente d'un caractère de commande
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise le timer principal = Timer0 (TMR0)
; pour avoir une interrution toutes les 250 µs.
;
; OPTION_REG = B'11000010'
;   RBPU   =   1 = Pas de résistance de rappel sur le port B
;   INTEDG =   1 = Interruption dur front montant RB0 (pas utilisé)
;   T0CS   =   0 = Source interne pour TMR0
;   TOSE   =   0 = Pas utilisé
;   PSA    =   0 = Prédiviseur pour le Timer0
;   PS     = 011 = Prédiviseur pour Timer0 = 1/16 => (4*16)/20 Mhz = 3,2 µsec
;
init_timer
	BANK1				; passer en banque1
	movlw   B'11000011'	; base de temps de TMR0 = 3,2 µsec à 20 Mhz
	movwf   OPTION_REG
	BANK0				; passer en banque0
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise les variables de détection d'occupation des cantons
;
init_det
	clrf    det_i1
	clrf    det_i2
	clrf    det_i1m
	clrf    det_i2m
	BANK1				; passer en banque1
	clrf    det_i1_1		; Partie des variables en BANK1
	clrf    det_i1_2
	clrf    det_i1_3
	clrf    det_i1_4
	clrf    det_i1_5
	clrf    det_i1_6
	clrf    det_i2_1
	clrf    det_i2_2
	clrf    det_i2_3
	clrf    det_i2_4
	clrf    det_i2_5
	clrf    det_i2_6
	BANK0				; passer en banque0
	return

;-----------------------------------------------------------------------------
; SSPG_INIT : Initialise la gestion des interruptions
;
; INTCON = B'10100000'
;   GIE    = 1 = Interruptions globalement autorisées
;   PEIE   = 0 = Pas d'interruption de périphérique
;   T0IE   = 1 = Interruption autorisées du timer TRM0
;   INTE   = 0 = Pas d'interruption du port PORTB
;   RBIE   = 0 = Pas d'interruption du port PORTB
;   T0IF   = 0 = Bit d'état (débordement TRM0)
;   INTF   = 0 = Bit d'état (RB0 a bougé)
;   RBIF   = 0 = Bit d'état (RB4-7 a bougé)
;
; PIE1  = B'00000000'
;   PSPIE  = 0 = Pas d'interruption du port //
;   ADIE   = 0 = Pas d'interruption conv A/D
;   RCIE   = 0 = Pas d'interruption UART recv
;   TXIE   = 0 = Pas d'interruption UART trans
;   SSPIE  = 0 = Pas d'interruption Serial port
;   CCP1IE = 0 = Pas d'interruption de CCP1
;   TMR2IE = 0 = Pas d'interruption TMR2-PR2
;   TMR1IE = 0 = Pas d'interruption dépassement de TMR1 

init_it
	movlw   B'10100000'	; Seule interruption autorisée = 'TMR0'
	movwf   INTCON		;
	movlw   B'00000000'
	movwf   PIE1		;
	bcf     PIR1,RCIF		; Efface le flag 'Buffer RS232 plein'
	clrf    it_err		; it_err = 0
	clrf    cpt
	clrf    cpt2
	return
	END

;=======================================================================================

; Code annexe pour débug (copier/coller)

	movlw	.0
	movwf	srv_0
	movlw	.50
	movwf	srv_1
	movlw	.100
	movwf	srv_2
	movlw	.150
	movwf	srv_3
	movlw	.200
	movwf	srv_4

	movlw	.1
	movwf	pwm_r0
	movlw	.2
	movwf	pwm_r1
	movlw	.3
	movwf	pwm_r2
	movlw	.4
	movwf	pwm_r3
	movlw	.5
	movwf	pwm_r4
	movlw	.6
	movwf	pwm_r5
	movlw	.7
	movwf	pwm_r6
	movlw	.8
	movwf	pwm_r7
	movlw	.9
	movwf	pwm_r8
	movlw	.10
	movwf	pwm_r9
	movlw	.11
	movwf	pwm_r10
	movlw	.12
	movwf	pwm_r11
	movlw	.13
	movwf	pwm_r12
	movlw	.61
	movwf	pwm_r12
	movlw	.62
	movwf	pwm_r13
	movlw	.63
	movwf	pwm_r14
	movlw	.64
	movwf	pwm_r15

	movlw	.1
	movwf	out_out3
	movlw	.2
	movwf	out_out4
	movlw	.3
	movwf	out_out5

	movlw	.4
	movwf	out_out21		; nouveau en V3.0
	movlw	.5
	movwf	out_out22
	movlw	.6
	movwf	out_out23
	movlw	.7
	movwf	out_out24
	movlw	.8
	movwf	out_out25
