Le Charlieplexing est une technique qui permet de contrôler un grand nombre de DELs sur à petit nombre d'entrée/sortie binaires d'un MCU. Pour utiliser cette technique il faut que chaque E/S utilisée soit configurable selon 3 états.
- En mode entrée haute impédance. C'est à dire sans résistance pull up.
- En mode sortie haute. C'est à dire à Vdd.
- En mode sortie basse. C'est à dire à Vss
- Dans ce circuit si PB3 et PB6 sont en mode entrée haute impédance les 2 DELs sont éteintes.
- Si PB6 est en mode sortie haute et PB3 en mode sortie basse alors D26 est allumée.
- Si PB6 est en mode sortie basse et PB3 en mode sortie haute alors D25 est allumée.
Notez que les broches 7 et 8 du MCU ne sont pas utilisées pour le multiplexeur. La raison en est qu'elles ne sont pas configurable en mode sortie push-pull. Ce sont des broche open drain conçues pour les bus I2C.
À un instant donné une seule DEL peut-être allumée mais en faisant fonctionner le multiplexeur rapidement avec la persistance de la vision on peut créer l'illusion qu'elles sont toutes allumées en même temps.
Circuit de démonstration
interconnection des DELs
Dans la table suivante C est pour cathode et A pour anode.
| PA0 | PA2 | PB5 | PB6 |
|---|---|---|---|
| D1C | D1A | ||
| D2A | D2C | ||
| D3A | D3C | ||
| D4A | D4C | ||
| D5A | D5C | ||
| D6A | D6C | ||
| D7C | D7A | ||
| D8C | D8A | ||
| D9C | D9A | ||
| D10C | D10A | ||
| D11C | D11A | ||
| D12A | D12C |
vidéo de démonstration
Circuit version 2
J'ai fait un montage permanent avec des DELs bleus montées en cercle. Le Firware contient un engin d'animation avec un jeu de commandes simple pour créer différentes animations.
Ce circuit utilise 3 switches boutons à contact temporaire. 2 servent pour sélectioner l'animation. Le 3ième est pour faciliter la programmation du MCU.
Description du firmware
Les fichiers du projet sont disponible ici. C'est écris en assembleur pour SDCC
La minuterie TIMER 4 est configurée pour générer une interruption à intervalle d'une milliseconde. Le fonctionnement du multiplexeur est géré par la routine d'interruption suivante. Ce code est dans le fichier hardware_init.asm
;------------------------------
; TIMER 4 is used to maintain
; timers and ticks
; interrupt interval is 1 msec
;--------------------------------
Timer4UpdateHandler:
clr TIM4_SR ; reset interrupt flag
; multiplexer control
call leds_off
ld a,mx_step
inc a
cp a,#12
jrmi 1$
clr a
4$:
; check if pause is active
btjf flags,#F_PAUSE,1$
dec pause_timer
jrne 1$
; end of pause
bres flags, #F_PAUSE
1$:
; turn on LED if bit set
; shift the corresponding bit in carry
ld mx_step, a
ldw x, led_set
tnz a
jreq 3$
2$: srlw x
dec a
jrne 2$
3$: srLw x ; now bit is in carry flag
jrnc 9$ ; bit is reset
; bit set turn on LED
ld a,mx_step
call led_on
9$: callr read_buttons
iret
La variable mx_step contient un entier dans l'intervalle {0..11} qui indique quelle DEL doit-être contrôlée à cette étape. cette valeur est incrémentée à chaque interruption de sorte que la boucle de 12 DELs est parcourue en 12 interruptions soit 12msec. Ce qui donne une fréquence du multiplexeur de 83 cycles/seconde. C'est suffisant pour éviter l'effet de scintillement.
Les bits 0..11 de la variable led_set contiennent le patron de configuration allumée/éteint des 12 DELs. Si le bit est à 0 la DEL reste éteinte et elle est allumée si le bit est à 1
L'interruption gère aussi la lecture des boutons tactiles ainsi que le délais de la routine pause qui contrôle la vitesse de l'animation.
Notez que le fonctionnement du multiplexeur est indépendant de l'animation. On pourrait mettre un patron dans la variable led_set et à partir de là faire tourner le programme dans une bouche infinie. Le résultat serait une configuration de DELs fixe. Puisque le logiciel d'animation est un programme client du multiplexeur il est dans un fichier différent, animation-demo.asm
Une animation est une liste de mots de 16 bits. Chaque mot est structuré de la façon suivante:
| bits | description |
|---|---|
| 0..11 | ensemble de bits représentant chaque DEL, bit 0 pour la DEL 1 à bit 11 pour la DEL 12 |
| 12..15 | commande |
Liste des commandes
| commande | valeur | description |
|---|---|---|
| CPY | 0 | copie les bits 0..11 dans la variable led_set. |
| INC | 1 | copie les bits 0..11 dans la variable led_set et incrémente la variable anim_step. |
| DEC | 2 | copie les bits 0..11 dans la variable led_set et décrémente la variable anim_step. |
| RST | 3 | Boucle l'animation à partir du début de la liste. |
| SPD | 4 | Initialise la variable anim_delay avec les bits 0..7 et incrément la variable anim_step. Ce délais détermine le temps en multiple de 12 msec entre chaque étape de l'animation. |
| RND | 7 | Initialise la variable led_set avec une valeur aléatoire. |
Le bit 15 de chaque commande est appellée INV et a pour effet lorsqu'il est à 1 d'inverser les bits 0..11 avant de les copier dans anim_step.
Code de la routine d'animation
;------------------------------------
; animation client for the charlieplexr
;-------------------------------------
animation:
;initialize with first animation
ldw x,#swing
ldw anim_table,x
ld a,(1,x)
ld anim_delay,a
1$:
; check for button down
btjf flags,#F_BTN1,2$
call next_anim
jra 3$
2$: btjf flags,#F_BTN2,4$
call prev_anim
3$: ; wait button release
ld a,#3
and a,flags
jrne 3$
4$:
clrw x
ld a,anim_step
ld xl,a
sllw x
addw x,anim_table
ldw x,(x)
ld a,xh
swap a
and a,#0x7 ; command
cp a,#CPY
jreq 5$ ; copy_set
cp a,#INC
jreq 6$ ; inc_step
cp a,#DEC
jreq 7$ ;dec_step
cp a,#RST
jreq 8$ ;reset_step
cp a,#SPD
jreq 9$ ;set_speed
cp a,#RND
jreq 10$ ;random_set
jra 12$ ; bad command ignored
5$: ; copy_set
tnzw x
jrpl 52$
cplw x
52$:
ld a,xh
and a,#0xF
ld xh,a
ldw led_set,x
jra 12$
6$: ;inc_step
inc anim_step
jra 5$
7$: ;dec_step
dec anim_step
jra 5$
8$: ;reset_step
clr anim_step
jra 1$
9$: ;set_speed
ld a,xl
ld anim_delay,a
inc anim_step
jra 1$
10$: ;random_set
call lfsr
ldw led_set,x
12$: ; animation delay
ld a,anim_delay
call pause
jra 1$
ret
La variable anim_step est lue et sert à indexer la table de l'animation dont l'adresse est conservée dans la variable anim_table. Les bits 12..15 sont extrait et un sélecteur de commande est utilisé pour sélectionner le code à exécuter pour cette commande. Pour les commandes 0..3 ainsi que 7 la routine pause est appellée pour générer un délais avant l'exécution de la prochaine commande. Ce délais est consrvé dans la variable anim_delay et contrôle la vitesse d'exécution de l'animation.
La liste des animations disponible est conservée dans la table anim_list et l'animation désirée est sélectionnée en utilisant les boutons btn1 et btn2. Au démarrage c'est la première animation de la liste qui est active. btn1 descend dans la liste et btn2 remonte. L'indice de l'animation active est conservé dans la variable anim_select.


