Guirlande à microprocesseurs

( link to english version )

 

. 1

1.     Présentation. 1

2.     Modules LED.. 1

a.     Electronique. 1

b.     Protocole série. 3

c.     Logiciel 4

3.     Module maitre. 4

a.     Electronique. 4

b.     Logiciel 4

4.     Documentation. 5

a.     Datasheets. 5

b.     Sources du module esclave. 5

c.     Source du module maitre. 8

d.          Photos et vidéo. 10

 

1.   Présentation

 

Depuis quelques temps, déjà, je trouve les guirlandes disponibles dans le commerce, trop ennuyeuse, trop répétitive avec leurs deux ou trois alternances d’ampoules colorées.

J’ai eu envie de créer une guirlande réellement personnalisable, sans me ruiner non plus. Tout de suite deux idées sont arrivées :

-         un microprocesseur pour piloter toutes les lampes,  mais au prix d’un relativement gros toron de fils, même si l’utilisation de croisement de fils et de diodes, permet de diminuer le nombre de fils, cela n’est pas très satisfaisant,

-         placer un microprocesseur par lampe,  mais jusqu’alors le prix de chaque processeur faisait exploser le tarif de la plus basique des guirlandes.

 

Depuis peu de temps, Microchip vend de tout petits processeurs, a quelque dizaines de centimes d’euro l’unité,  en CMS et a faible nombre de pattes.  Financièrement le projet devient alors réalisable.

 

Le schéma de principe est le suivant :

 

 

Un processeur maitre envoie des ordres de pilotage sur un bus série mono-fils. Ces ordres sont interprétés et retransmis par chaque unité esclave.

 

2.   Modules LED

a.     Electronique

 

Le processeur retenu est le PIC12F609-I/SN  pour plusieurs raisons :

-         son prix   0.56 € TTC par lot de 100 sur le site MicrochipDirect

-         son boitier : 8 broches SOIC

-         la présence d’une broche externe d’interruption et d’un timer hardware

 

Le bus en série, par opposition avec un branchement en parallèle de tous les processeurs, a été choisi pour deux raisons :

 

Ceci permet l’auto-énumération des unités esclaves : au démarrage le maitre envoie un octet ayant pour valeur zéro. Cette valeur est mémorisée par la première unité, puis la valeur « 1 » est envoyée à la suivant. Et ainsi de suite : chaque unité prend pour son adresse, la valeur reçue, et envoie cette valeur incrémentée à l’unité suivante. Ceci évite de devoir programmer chaque unité spécifiquement avec une adresse différente.

 

Sur un câble de grande longueur,  la résistance du cuivre devient significative.  Même si chaque unité consomme environ 50mA  (la diode surtout),  au bout de 50 diodes, la consommation totale approche les 2.5A.  Dans ce cas, la référence de tension à la masse change,  et le processeur ne sait plus interpréter correctement les valeurs 1 ou 0.  Avec le chainage,  le signal est régénéré à chaque saut d’unité.

 

Toujours pour le problème du courant tiré sur un fil relativement long,  il n’est pas garanti d’avoir la même tension au début et à la fin de la guirlande.  Le principe est donc d’alimenter l’ensemble de la guirlande avec 7V, et un régulateur stabilise à 5V la tension interne de chaque unité.

 

La diode, en fait constitué de trois diodes (rouge, vert, bleu), permet de créer toutes les couleurs de l’arc en ciel. Celle-ci est alimentée en anode commune, car le microprocesseur a une capacité de drainage vers la masse supérieure à celle de sa capacité à fournir du +5V sur chaque bit en sortie.

 

Le contrôle de l’intensité se fait logiciellement (modulation en largeur d’impulsion).  Chaque couleur est pilotée en interne sur 64 niveaux, le tout rafraichi environ 100 fois par secondes.

 

Après routage du circuit nous avons :

-         A gauche les deux connecteurs d’alimentation et bus série, autour du régulateur 5V,

-         Le processeur,

-         Les résistances pour la LED,

-         Le connecteur de la LED.

 

 

 

(dimensions en mm )

b.    Protocole série

 

Les trames transmises sont constituées de 25 bits : 7 bits d’adresse + 6 bits pour le couleur rouge + 6 bits pour le couleur verte + 6 bits pour la couleur bleue.

Contrairement à une communication série classique,  les bits sont codés en largeur d’impulsion, et non par des états de tension. L’objectif est de faire travailler le pic sur interruption et non en pooling. Ceci allège la charge du logiciel dans le pic12F609.

 

Le logiciel configure le déclenchement d’interruption sur flanc montant. Lorsque ce changement survient, un timer hardware est lancé, ainsi que la configuration pour une interruption sur flanc descendant.  Quand ce nouvel événement arrive, la valeur du timer est testée pour déterminer la valeur du bit ainsi codé.  (60µS pour « 0 »,  30µS pour « 1 »).  A chaque interruption, l’état adéquat est reporté en sortie, pour l’unité suivante, avec une latence de 7µS.

 

Un bit dure 100µS au total, avec une pause de quelque centaines de microsecondes entre chaque commande.  On atteint 300 commandes par seconde.

 

c.     Logiciel

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


3.   Module maitre

a.     Electronique

 

Extrêmement simple :

-         un pic 18F252 I/SP avec son quartz à 20MHz,

-         une résistance sur la broche MCLR,

-         un connecteur pour sa programmation,

-         un fil de sortie série sur le PORTBbits.RB1,

-         un régulateur 7805 et son condensateur de stabilisation,

 

Tellement simple que je n’ai pas pris la peine de faire un circuit imprimé.  Une plaque d’expérimentation à pastille est suffisante.

b.    Logiciel

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


4.   Documentation

a.     Datasheets

 

Processeur maitre  PIC18F252

Processeur des modules à LED  PIC12F609

Régulateur 5V cms  MCP1702

 

b.    Sources du module esclave

 

; *****************************************************************************

; ** Module LED pour guirlande

; **

; ** CPU @8MHz : 0.5µS/instruction

; ** message : 7 adr + 6 rouge + 6 vert + 6 bleu  @  10Kbps -> 400 ordres/s

; ** le bits sont codés par des largeurs d'impulsions :  1 = 30µS ,  0 = 60µS

; *****************************************************************************

 

processor  12F609

#include   <p12F609.INC>

 

radix  DEC

__CONFIG _BOD_OFF & _IOSCFS_8MHZ & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT

 

#define     inW         0

#define     inF         1

 

#define     led_verte    GP0

#define     led_bleue    GP1

#define     bus_in       GP2

#define     mclr         GP3

#define     bus_out      GP4

#define     led_rouge    GP5

 

serbuf1     EQU  .64

serbuf2     EQU  .65

serbuf3     EQU  .66

serbuf4     EQU  .67

replica     EQU  .68

own_adr     EQU  .69

rougeB      EQU  .70

vertB       EQU  .71

bleuB       EQU  .72

rouge       EQU  .73

vert        EQU  .74

bleu        EQU  .75

adr         EQU  .76

stack_w     EQU  .77

stack_s     EQU  .78

pwm         EQU  .79

tmp1        EQU  .80

tmp2        EQU  .81

 

  ORG  0x0000                    ; Reset

       NOP

       NOP

       GOTO   Start

 

;-------Routine d'interruption exterieur-----

 

   ORG 0x0004

INT:   MOVWF  stack_w            ; push w & status

       SWAPF  STATUS,w

       MOVWF  stack_s

 

       BCF    INTCON,INTF

       BSF    STATUS,RP0         ; BANK1

       BTFSS  OPTION_REG,INTEDG  ; si flanc montant de l'IT

       GOTO   fld

 

       NOP                       ; pour corriger le délai de montée par rapport à la descente

       BCF    OPTION_REG,INTEDG  ; config pour attente flanc descendant

       BCF    STATUS,RP0         ; BANK0

       BSF    GPIO,bus_out

       GOTO   sorti

 

fld:   BSF    OPTION_REG,INTEDG  ; config pour attente flanc ascendant

       BCF    STATUS,RP0         ; BANK0

       BCF    GPIO,bus_out

 

       BTFSS  INTCON,T0IF        ; si overflow du timer (au delà de 128µS)

       GOTO   fle

       BCF    INTCON,T0IF

       CLRF   serbuf1            ; reset buffer d'entrée

       INCF   serbuf1,inF        ; bit indicateur en début de chaine

       CLRF   serbuf2

       CLRF   serbuf3

       CLRF   serbuf4

 

fle:   MOVF   TMR0,inW           ; detecte le temps passé depuis flanc montant (mesuré 60µS=110 / 30µS=56 )

       SUBLW  .85

       RLF    serbuf1,inF        ; utilise la retenue pour injecter nouveau bit

       RLF    serbuf2,inF

       RLF    serbuf3,inF

       RLF    serbuf4,inF

 

sorti: MOVLW  .0                 ; lancer le timer 0

       MOVWF  TMR0

       SWAPF  stack_s,w          ; pop w & status

       SWAPF  stack_w,f

       SWAPF  stack_w,w

       RETFIE

 

;----------------------------------DEMARRAGE

 

Start  CLRF   rouge              ; init des variables

       CLRF   vert

       CLRF   bleu

       CLRF   serbuf1            ; reset buffer d'entrée

       INCF   serbuf1,inF        ; bit indicateur en début de chaine

       CLRF   serbuf2

       CLRF   serbuf3

       CLRF   serbuf4

       MOVLW  0xff               ; init replica port

       MOVWF  replica

       BCF    replica,bus_out    ; bus de sortie a zero

       MOVWF  GPIO

 

       BSF    STATUS,RP0         ; BANK1

       CLRF   ANSEL

       MOVLW  b'00001100'        ; port en entrée pour MCLR et INT, le reste en sortie

       MOVWF  TRISIO

       MOVLW  0x3f               ; init pull-up des ports

       MOVWF  WPU

       MOVLW  0x48               ; init pull-up + div sur wdt

       MOVWF  OPTION_REG

       BCF    STATUS,RP0         ; BANK0

 

       MOVLW  0xd0               ; init gie peie inte

       MOVWF  INTCON

 

       MOVLW  49                 ; config adresse en attendant autoénumération

       MOVWF  own_adr

 

;----------------------------------BOUCLE PRINCIPALE

main:  BTFSS  serbuf4,1          ; test le 25 ème bit pour savoir si on a tt récupéré en entrée série

       GOTO   atten

;----------------------------------TRAITE DONNEES REçUES  20µS

 

       MOVF   serbuf1, inW       ; récupère bleu

       ANDLW  b'00111111'

       MOVWF  bleuB

 

       RLF    serbuf1,inF        ; récupère vert avec 2 shift gauche d'abord

       RLF    serbuf2,inF

       RLF    serbuf3,inF

       RLF    serbuf4,inF

       RLF    serbuf1,inF

       RLF    serbuf2,inF

       RLF    serbuf3,inF

       RLF    serbuf4,inF

       MOVF   serbuf2, inW

       ANDLW  b'00111111'

       MOVWF  vertB

 

       RLF    serbuf1,inF        ; récupère rouge avec 2 shift gauche d'abord

       RLF    serbuf2,inF

       RLF    serbuf3,inF

       RLF    serbuf4,inF

       RLF    serbuf1,inF

       RLF    serbuf2,inF

       RLF    serbuf3,inF

       RLF    serbuf4,inF

       MOVF   serbuf3, inW

       ANDLW  b'00111111'

       MOVWF  rougeB

 

       RLF    serbuf1,inF        ; récupère adr avec 2 shift gauche d'abord

       RLF    serbuf2,inF

       RLF    serbuf3,inF

       RLF    serbuf4,inF

       RLF    serbuf1,inF

       RLF    serbuf2,inF

       RLF    serbuf3,inF

       RLF    serbuf4,inF

       MOVF   serbuf4, inW

       ANDLW  b'01111111'

       MOVWF  adr

 

       CLRF   serbuf1            ; reset buffer d'entrée

       INCF   serbuf1,inF        ; bit indicateur en début de chaine

       CLRF   serbuf2

       CLRF   serbuf3

       CLRF   serbuf4

 

;----------------------------------APPLICATION DES DONNEES 5µS

 

       MOVF   own_adr,inW        ; si adr=adresse

       SUBWF  adr,inW

       BTFSC  STATUS,Z

       GOTO   main3

       MOVLW  .127               ; si adr=broadcast

       SUBWF  adr,inW

       BTFSS  STATUS,Z

       GOTO   atten   

main3: MOVF   rougeB,inW

       MOVWF  rouge

       MOVF   vertB,inW

       MOVWF  vert

       MOVF   bleuB,inW

       MOVWF  bleu

 

;----------------------------------TRAITEMENT PWM LED    #9µS/11µS

 

atten  MOVLW  .63

       MOVWF  pwm

Lred   MOVF   rouge,inW          ; si pwm=rouge

       SUBWF  pwm,inW

       BTFSS  STATUS,Z

       GOTO   Lvert

       BCF    GPIO,led_rouge

Lvert  MOVF   vert,inW           ; si pwm=vert

       SUBWF  pwm,inW

       BTFSS  STATUS,Z

       GOTO   Lbleu

       BCF    GPIO,led_verte

Lbleu  MOVF   bleu,inW           ; si pwm=bleu

       SUBWF  pwm,inW

       BTFSS  STATUS,Z

       GOTO   Lred2

       BCF    GPIO,led_bleue

Lred2  DECFSZ pwm,inF

       GOTO   Lred

       BSF    GPIO,led_rouge

       BSF    GPIO,led_verte

       BSF    GPIO,led_bleue

       GOTO   main

  END

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

c.    Source du module maitre

 

Le protocole série utilisé n’est pas compatible avec l’UART du PIC18F252.

Il est donc nécessaire de coder logiciellement ce protocole.

 

void setled( unsigned char led, unsigned char tx_rouge, unsigned char tx_vert, unsigned char tx_bleu )

{

  unsigned char  d,i;

  int j;

 

  for(d=0; d<=6; d++)      // Address (7bits)

    if (led & (0x40>>d))

    {

      PORTBbits.RB1=1;

      for (i=0; i<12; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<25; i++){}

    }

    else

    {

      PORTBbits.RB1=1;

      for (i=0; i<24; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<14; i++){}

    }

  for(d=0; d<=5; d++)      // Rouge (6bits)

    if (tx_rouge & (0x20>>d))

    {

      PORTBbits.RB1=1;

      for (i=0; i<12; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<25; i++){}

    }

    else

    {

      PORTBbits.RB1=1;

      for (i=0; i<24; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<14; i++){}

    }

  for(d=0; d<=5; d++)      // Vert (6bits)

    if (tx_vert & (0x20>>d))

    {

      PORTBbits.RB1=1;

      for (i=0; i<12; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<25; i++){}

    }

    else

    {

      PORTBbits.RB1=1;

      for (i=0; i<24; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<14; i++){}

    }

 

  for(d=0; d<=5; d++)      // Bleu (6bits)

    if (tx_bleu & (0x20>>d))

    {

      PORTBbits.RB1=1;

      for (i=0; i<12; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<25; i++){}

    }

    else

    {

      PORTBbits.RB1=1;

      for (i=0; i<24; i++){}

      PORTBbits.RB1=0;

      for (i=0; i<14; i++){}

    }

  for (j=0; j<180; j++){}   // Petite pause entre chaque commande

}

//************************************

 

 

Ensuite il faut coder les séquences de couleurs.

Deux exemples : couleurs aléatoires sur toutes les LED  et  alternance rouge vert bleu sur toute la guirlande.

 

 

//************************************

void fete_foraine()

{

  int i;

  long j;

 

  while(counter)

  {

    for (i=1; i<nbled; i+=2 )

       setled ( i , rand()&0x7, rand()&0x7, rand()&0x7 );

    for (i=2; i<nbled; i+=2 )

       setled ( i , rand()&0x7, rand()&0x7, rand()&0x7 );

 

   for (j=0; j<35000; j++){}

  }

}

 

//************************************

void alternance_rouge_vert_bleu()

{

  int i;

  long j;

 

  while(counter)

  {   

    for (i=1; i<nbled; i+=3 )

    {

       setled( i,   4,0,0 );

       setled( i+1, 0,4,0 );

       setled( i+2, 0,0,4 );

    } 

    for (j=0; j<32700; j++){}

    for (j=0; j<32000; j++){}

 

    for (i=1; i<nbled; i+=3 )

    {

       setled( i,   0,0,4 );

       setled( i+1, 4,0,0 );

       setled( i+2, 0,4,0 );

    }

    for (j=0; j<32700; j++){}

    for (j=0; j<32000; j++){}

 

    for (i=1; i<nbled; i+=3 )

    {

       setled( i,   0,4,0 );

       setled( i+1, 0,0,4 );

       setled( i+2, 4,0,0 );

    }

    for (j=0; j<32700; j++){}

    for (j=0; j<32000; j++){}

 

  }

}

//************************************

d.    Photos et vidéo

 

Les composants avant soudure

       

 

La fabrication des circuits

                

 

Aspect final

       

 

Chrono diagrammes

     

 

 

Vidéo

 

 

Si vous avez des questions ou des suggestions :    hamatum.lcdfree.fr

 

 

 

 


Free Visitor Counter