Le circuit cible est un microcontrôleur faible coût, PIC12C508 ou PIC16F628 avec horloge interne Fx=4 MHz -8/+10%.
Circuit |
Tension |
Consommation |
Horloge interne |
PIC12C508A |
3-5,5V |
1,4mA max @5,5V ; 0,8mA typ @5,5V |
4 MHz -8/+10% |
PIC16F628A |
3-5,5V |
1,3mA max @5,5V ; 0,8mA typ @5,5V |
4 MHz -9/+7% |
L'horloge interne n'est pas précise, et sensible à la température. Ce qui veut dire que sa valeur peut évoluer dans le temps ; par exemple +2% au démarrage à froid et +3.7% après quelques minutes de chauffe. Il faudra la mesurer (avec le secteur lui même) puis appliquer des corrections. On va développer une solution avec un oscillateur numérique asservi. Evidemment une solution à Quartz est plus simple, mais elle est plus chère.
L'alimentation sera prélevée directement sur le secteur, au travers d'une capacité. Par exemple 50nF+2k donne 1,6mA moyens, avec un condensateur de filtrage 100µF, ripple de 100mV. Montée à 5V en 0,5s.
Fondamentalement, c'est un circuit de découpage de phase. Le µlogiciel employé peut être rustique : attendre x ms après le passage à zéro puis amorcer le triac. Le nombre de pas nécessaires pour régler la puissance en sortie peut être raisonnable (le circuit LS7631 en a 83, les dimmer DMX512 en ont 256 dont les LSB ne sont pas forcément employés). En utilisant une résolution de 1µs, on a le choix entre les solutions suivantes :
Si on souhaite garder le nombre de pas inférieur à 255 pour tenir sur un octet, alors on considèrera un quantum à 64µs, ce qui offre 156 pas par demi-période.
Le cas simple consiste à utiliser un PIC12C508, et son timer TIMER0, avec un quartz 4MHz et une détection secteur des 2 fronts, montant et descendant. Chaque demi période est divisée en plusieurs tranches temporelles, ou modes, ce qui permet une écriture aisée du logiciel
Au passage à zéro du secteur, on charge le timer avec une valeur "N0", sauf qu'en fait on ne connaît pas bien l'instant du 0 secteur.
En supposant une détection directe sur une entrée du microcontrôleur avec une résistance élevée (2 x 330k par exemple) et une capacité de filtrage de 39pF pour être moins sensible à la HF et 7pF de capacité parasite, la montée du signal logique « détection de zéro » se fera 140µs après le vrai zéro secteur. Dans ces conditions, il ne faudrait pas charger N0 mais N0+140µ/résolution soit à peu près N0+2.
Arrivée à 255, le timer passe à zéro et active une interruption qui va changer le mode, c'est à dire autoriser un amorçage du triac.
La valeur de N0 va de 255 (plein feu), à maxdim (minimum).
La valeur de maxdim est telle que le compteur déborde à la fin de la demi période, Ta=10ms, Tb=0, N1=0, donc maxdim = 256-0.01*Fx/256 dont maxdim=99.75 [84.1 : 115.4] à 50 Hz.
Pour n'importe quelle N0 on a l'équation N = N0 - maxdim, à chaque passage à zéro, en lisant N1, on en déduit une valeur de maxdim = N0 - N1.
Divers considérations :
Algorithme :
Attendre le zéro secteur ; en fait on attendra le front
Si N0>timer0, Maxdim = N0 - timer0 ; timer0 = 0.01*Fx/256 - 256 + N0
Sinon maxdim=maxdim+256-timer0
N0 = min (N0, maxdim) ; clamp
Charger le timer avec N0 ; le compteur s'incrémente toute les 256/Fx
Attendre Timer=0 ; attention cet état ne dure que 64µs
Amorcer le triac ; impulsion de quelques µs
Attendre le zéro secteur
etc
Dans tous les cas, lorsqu'on recherche des fronts montants ou descendants, on fera systématiquement plusieurs acquisitions successives pour éviter le déclenchement sur parasite.
La détection des fronts sera armée x µs avant de façon à être robuste à des parasites. Si le front n'est pas détecté dans une fenêtre prédéfinie,
On découpe la période en plusieurs tranches.
En utilisant un seul signal de détection de zero, D1 à +2.5V, on considère 4 tranches.
Mode |
Localisation entre ... |
et … |
Tache |
0 |
... |
D1+ |
Si front montant D1 alors |
1 |
D1+ |
OVF timer0 |
Attente OVF et passage au mode 2 |
2 |
OVF timer0 |
D1- |
Activation Triac, 50µs tous les 500µs |
3 |
D1- |
OVF timer0 |
Attente OVF et passage au mode 4 (->0) |
N2+100h-(N0+off1) = D1un |
|
N1+100h-(N0-off2) = D1zero |
|
D1zero - D1un = 2off1 + 2off2 |
Impossible de discerner off1 de off2 |
En utilisant deux détections de zéro, D1 et D2, on considère 8 tranches.
N3+100h-N2 = D1un
N1+100h-N4 = D2zero
N2-(N0-off1) = 2.off1 si D1/D2 appairés
N4-(N0-off2) = 2.off2 si D1/D2 appairés
N2-(N0-off1) + N4-(N0-off2) + D1un = D2un
N2-(N0-off1) + N4-(N0-off2) + D2zero = D1zero
Si _e=01h |
Si D2=111 alors _e=02h |
Si _e=02h |
_N1=timer0 |
Si _e=04h |
Si D1=111 alors _e=08h |
Si _e=08h |
_N2=timer0 |
Si _e=10h |
Si D1=000 alors _e=20h |
Si _e=20h |
_N3=timer0 |
Si _e=40h |
Si D2=000 alors _e=80h |
Si _e=80h |
_N4=timer0 |
Sinon |
Erreur ? |
Si _fire=1 |
Décrémente _tfire |
Interruption _timer=0 |
_fire=1 |
Pour un hacheur qui laisse passer quelques demi périodes entières seulement
Si _etat=7(80h) |
Si TMR0>=DP-1 alors _etat=0 |
Attente fenêtre synchro |
Si _etat=0(01h) |
Si D2=111 et D1=000 alors |
Passage 0 arche positive |
Si TMR2>=DP+1 alors |
Absence de synchro, on fait pareil et on incrémente le compteur d'erreur |
|
Si _etat=1(02h) |
Si TMR0>=2 alors fire=0 |
Fin d'amorçage triac à 128µs |
Si _etat=2(04h) |
Etat libre |
|
Si _etat=3(08h) |
Si TMR0>=DP-1 alors _etat=4 |
Attente fenêtre synchro |
Si _etat=4(10h) |
Si D1=000 et D2=111 alors |
Passage 0 arche négative |
Si TMR2>=DP+1 alors |
Absence de synchro, on fait pareil et on incrémente le compteur d'erreur |
|
Si _etat=5(20h) |
Si TMR0>=2 alors fire=0 |
Fin d'amorçage triac à 128µs |
Si _etat=6(40h) |
Etat libre |
La durée totale de la boucle est de 6 tests (BTFSS GOTO) soit 6*(1+2)=18µs @4MHz, bien inférieure à la résolution TMR0.
Le cas évolué consiste à utiliser un PIC16F628, et son timer TIMER1, sur oscillateur interne et une détection secteur simple. L'amorçage triac se fait de façon intelligente et des courbes de correction de puissance sont implantées.
Le circuit utilisé doit être robuste aux parasites. Il faut qu'il ait une horloge propre, en phase avec le secteur. On ne peut pas compter sur la détection au zéro pour cadencer tout le processus.
On peut utiliser l'horloge interne et se passer de quartz, si on met au point un asservissement, comme une PLL. Par exemple, à chaque passage à zéro secteur, on échantillonnera le timer pour générer une erreur, qui sera utilisée pour corriger la consigne en fréquence.
Dans ce cas on utilisera une détection secteur simple, à 20ms, il suffit qu'elle soit précise, c'est à dire que la gigue soit aussi faible que possible, pour toujours échantillonner précisément au même instant.
Dans toute PLL il y a un oscillateur piloté, il sera réalisé par un timer rechargé périodiquement.
On supposera que la fréquence de l'horloge est 4MHz.
Le choix du timer est très limité dans la série PIC :
timer2 ne peut pas être utilisé, son prédiviseur limité à 16 ne lui permet pas d'avoir une période de 10ms.
timer0 sur 8 bits avec un prédiviseur à 64, LSB = 64µs, interruption au passage FF-00, rechargement avec -155 (0x65). Le timer balaye les valeurs 0x65 à 0xFF et aussi 0x00 à cause de la durée de la routine d'interruption et de rechargement.
timer 1 sans prédiviseur, LSB=1µs, interruption au passage FFFF-0000, stop timer, rechargement avec -10000 (0xD8F0), run timer. Le timer balaye les valeurs 0xD8F0 à 0xFFFF puis de 0x0001 à 0x00ii selon la durée de la routine d'interruption et de rechargement. L'interruption devra être gérée de façon fine, et prioritaire. Par contre le registre de capture reste disponible pour la boucle de phase.
timer 1 sans prédiviseur, LSB=1µs, comparaison avec CCPR1 initialisé à 10000 (0x2710), reset sur coïncidence (et interruption CCP1IF si nécessaire). Le timer balaye les valeurs 0x0000 à 0x270F précisément. Cette méthode (special event) utilise le registre de capture qui n'est plus disponible pour la boucle de phase, mais elle ne requiert pas d'interruption pour maintenir le timer.
Cette dernière solution est la plus stable et la plus simple à mettre en oeuvre. La fréquence de sortie de cet oscillateur est égale à Fxtal/N0, et doit être égale à 100Hz.
Ce choix disqualifie les microcontrolleurs de la série PIC12.
Dans le cas d'un montage sans quartz, sur horloge interne, il est nécessaire de faire une calibration au démarrage, en mesurant n périodes secteur, pour trouver la valeur précise de N0 et démarrer ainsi la PLL à la bonne fréquence.
Avec un timer de 16 bits, tournant à 1MHz, on pourrait aller jusqu'à mesurer 3 périodes entières, mais 2 suffiront et on évitera ainsi des divisions compliquées.
L'horloge interne à 4 MHz étant donnée à +/-5%, la valeur mesurée sur 2 période est égale à 2*Fq/50, valeur nominale = 40000 (0x9C40) +/-5%.
La valeur à recharger est pour une demi période est donc N0 = N/4 = 10000 (0x2710) +/- 40 (0x0028), elle doit être comprise entre 9500 (0x251C) et 10500 (0x2904).
Une valeur plus forte trahit une horloge locale trop rapide.
A chaque front montant de la détection zéro secteur, toutes les 20ms, une interruption EXT0 est générée et le timer1 est échantillonné. Comme nous utilisons le registre CCPR1 pour le rechargement, cet échantillonnage sera réalisée par double lecture TMR1H/TMR1L selon les recommandations de Microchip.
Un écart fréquentiel de 0.1% se traduit par une fréquence de battement de 0.05Hz soit une période de 20s, et un écart entre 2 échantillons successifs de l'ordre de 10.
Si le front de montée de la détection zéro est présent entre 50 et 10µs avant le vrai zéro (soit détection entre -5V et -1V), on s'attend à ce que la valeur du timer soit comprise entre N0-50 et N0.
Si on veut asservir la phase autour de ce 0, il faut décaler les valeurs lues pour qu'elles soient continues à cet endroit, sinon les calculs risquent d'être très compliqués. Ainsi l'asservissement travaillera autour de N0/2.
Il faut maintenant appliquer le filtre de boucle afin de calculer en temps
réel la nouvelle valeur de l'oscillateur.
Source :
Un filtre numérique récursif ou non récursif réalise la fonction numérique suivante :
Il a pour fonction de transfert
Le gain en continu est obtenu en faisant z=1 et le gain à l'infini (à la fréquence de Shannon = Fech/2) en faisant z=-1
Transformation bi linéaire
On passe de la transformée en Z à la transformée de Laplace avec les relations et .
En développant en série et en se limitant au premier ordre :
et et
Le point p= 0 se transforme en z = 1, tandis que p= se transforme en z = -1
Exemple de synthèse :
1er ordre, 1 pole, 1 zéro |
Voir aussi table d'équivalence plus complète chez université de Bordeaux
NOTA : utilisation de J-DSP editor, problème de signes de A0, A1, A2
On retrouve le premier avec A0=1, A1=-0.909, A2=0.818, B0=0, B1=0.909
L'oscillateur numérique (NCO) piloté par le timer 1, se comporte comme un intégrateur par rapport à Fxtal. A chaque échantillonnage de sa phase, toutes les 20ms (à 50Hz), une valeur phi est lue.
, N0 étant la consigne, c'est à dire la commande appliquée au NCO.
En considérant que l'entrée, on peut écrire cette équation , elle a pour transfert :
, gain infini à f=0 (z=1), et -6dB à f=Fe/2=25Hz (z=-1)
C'est un magnifique intégrateur 1/p (un pole à z=1, et un zéro à z=0), la boucle de phase devra comporter au moins un zéro afin d'avoir un système stable.
En considérant un filtre simple avec un transfert du type , le système NCO+filtre peut se symboliser comme suit :
On peut écrire . Si on considère que Fxtal/200 est l'entrée, on en déduit la fonction de transfert , qui donne H(0)=0 et H(infini)=1/(2-b0+b1)
Ceci est un filtre IIR, avec B0=1, B1=-1, A0=1, A1=2b0-2 et A2=1+2b1
Avec 2 zéros : [0;0], [1;0] et 2 pôles conjugués [1- b0;+/-rac((b0-1)²-1-2b1)]
Pour simuler de tels filtres, j'ai acquis la phase en boucle ouverte, mesurée sur la maquette (courbe bleue). Cette série montre un décalage moyen de l'ordre de 2,8 par période de 20ms (700 sur un horizon de 5 secondes), soit un écart en fréquence de 0.028% après calibration. Avec une telle entrée il est facile de simuler sur le comportement du filtre de boucle sur le NCO au global.
Prenons une exemple, avec b0=0.50 et b1=-0.45.
On constate que ce filtre offre un amortissement fort, la consigne est atteinte en 1 seconde, avec un résidu crête-crête de 12.
Le transfert équivalent a été simulé : A0=1, A1=2b0-2=-1, A2=1+2b1=0.1, B0=1, B1=-1
On a implanté sur la maquette les coefficients b0=0.5 et b1=-0.25 très faciles à coder (shift droit), avec un calcul sur 8 bits, donc avec sans doute pas mal d'erreur. Le transfert équivalent a été simulé : A0=1, A1=2b0-2=-1, A2=1+2b1=0.5, B0=1, B1=-1
L'amortissement n'est pas optimal, le système est un peu trop rapide, le bruit en sortie est plus fort, mais çà fonctionne quand même.
La figure ci dessous donne l'allure de N0, sur presque 2000 périodes (40 secondes), avec b0=0.5 et b1=-0.25 avec un calcul sur 8 bits. Les erreurs dues à l'arrondi sont grandes, le bruit crête à crête est de 6 à 10 unités.
Le démarrage du NCO montre que l'amortissement du filtre n'est pas optimal, par contre il est très rapide, on converge à +/-10 en moins de 6 périodes de 20ms. On voit aussi que le filtre fonctionne si Phi est supérieur à 5, c'est le seuil qui a été choisi sur la maquette.
L'implantation sur micro nécessite un peu de soin pour éviter les erreurs d'arrondi. Si la phase est sur 16 bits signés, on fera les calculs sur 24 bits signés en utilisant des coefficients b0, b1 sur 8bits signés.
Un arrondi propre est pratiqué pour éviter que la convergence de la boucle soit égale à 0.5/(b0+b1).
Une série d'essais a été réalisées avec différentes valeurs de b0,b1, avec un seuil de mise en route à +/-5 (l'algorithme tourne si |phi|>5).
Les courbes pleines sont représentent N0, les pointillés la phase Phi.
On utilise une détection simple, en envoyant le secteur au travers de 2 résistances de 330k, sur la broche RB0/INT. Une routine d'interruption lit le timer1 et retourne la valeur dans le corps du programme pour traitement ultérieur (on a 20ms pour le faire).
L'entrée étant un trigger de schmitt, la détection se fait autour de 3.5V, soit 1.5V en dessous du Vdd, soit 15µs avant le vrai zéro secteur. L'oscillogramme suivant illustre la durée de la routine interruption au total, avec la sauvegarde et la restitution du contexte, elle dure un peu plus de 25µs.
Astuces :
Le prototype a été mis au point avec un PIC16F628.
L'alimentaion utilise une capacité de 330nF (soit un courant moyen consommé de 10mA) mais cela devrait fonctionner avec une capacité shunt de 100nF.
L'amorçage triac utilise un transistor pour avoir une capacité en courant assez forte (50mA).
L'analyse de la tension gate, est réalisée par les comparateurs internes du PIC, sur les entrées RA0, RA1, RA2, RA3.
Quelques idées d'amélioration :