Nouvelle ALIM 20V - 4A à découpage,
numérique, pilotée par un ATmega8

Cette réalisation est la suite logique de l'alimentation 20V à découpage, numérique, décrite sur ce site. Dans cette nouvelle version l'ATmega ne fait plus partie de la boucle d'asservissement de la tension, cette dernière étant assurée par des circuits analogiques (NE555 (géné dent de scie) + LM339 (comparateur rapide ) + LM324 (ampli OP acceptant un mode commun proche de la masse)). Les raisons de cette complication :
  • Je pense que la sécurité est ainsi plus grande (vis à vis d'un plantage éventuel du microcontrôleur)
  • La version avec asservissement logique fournissait une tension qui "respirait" très légèrement, ce n'est plus le cas de cette nouvelle version.
Cliquez sur une image ci-dessous pour visualiser l'album. Certaines sont commentées

1 Le schéma

Attention à la tension de service des divers condensateurs de filtrage... 40V mini, même en aval du MOSFET, sinon risque d'explosion... (si, suite à un plantage totalement imprévu du programme, le MOSFET venait à rester en conduction permanente).

L'alimentation 5V de la partie logique est obtenue par un module abaisseur de tension à découpage (LM2596 DC-DC adjustable power step-down module) en vente sur eBay (pas par moi !)

2 Le tranfo torique + fusibles et le redressement

Il va sans dire que les fusibles sont OBLIGATOIRES vu la puissance du transfo torique.

Pour éviter le pic de courant dans le pont de diodes lors de la mise sous tension, correspondant à la charge du condensateur de tête, on peut rajouter une résistance en série court-circuitée par un relais après un court instant. A vous de voir... Moi j'ai choisi d'utiliser un pont surdimentionné, parce que la fiabilité et l'impédance des contacts d'un relais à long terme me laissent perplexe.

3 Analyse du schéma

J'ai choisi, pour le découpage, d'utiliser un MOSFET canal N qui offre une résistance RDS(on) plus faible (0.028 ohm) qu'un canal P courant.

J'ai voulu placer ce MOSFET dans la branche positive de l'alim, pour des raisons de simplification de la mesure de la tension de sortie, ce qui oblige à l'utiliser en montage drain-commun. Mais dans cette configuration, la saturation du MOSFET n'est pas obtenue si on se contente d'amener la gate au potentiel du drain : il faut une tension positive supérieure à celle du drain pour conserver une valeur de tension gate-source suffisante pour saturer le transistor lorsque la source est ramenée au potentiel du drain. Cette tension peut être obtenue de diverses manières, petit transfo d'impulsions sur le signal de commande, survolteur par un doubleur de tension capacitif alimenté sur le 5V (40106 + capas + diodes), deuxième transfo d'alim, "pompage" capacitif depuis la tension de source ...

J'ai opté pour une prise intermédiaire sur le transfo torique principal (pourvu d'origine de plusieurs sorties au secondaire, ce qui n'ajoutait qu'une diode et un condensateur au montage), le circuit principal étant alimenté en +24V et le circuit de polarisation en +32V.

Pour que le rendement énergétique soit bon (que le MOSFET ne dissipe pas) le découpage doit s'effectuer à fronts raides. Or un MOSFET a une capacité Cgs importante. Pour obtenir un signal bien rectangulaire sur la source j'ai utilisé un montage push-pull haute tension (Q2 NPN- Q3 PNP en montage "collecteur commun"), car une simple résistance de rappel ne convient pas dans ce cas, sauf à lui donner une valeur bien trop faible provoquant une consommation trop importante.
Le transistor driver Q1 assure l'amplitude du signal de commande de ce push-pull à partir du signal 0..5V issu de la partie analogique.

Pour l'explication du fonctionnement du découpage (attaque du MOSFET par un signal rectangulaire à rapport cyclique ajustable, diode de "roue libre" etc...) je vous renvoie à la description de l'alimentation 20V analogique.

La principale différence avec cette alimentation est que la tension de consigne n'est plus obtenue par un simple potentiomètre, mais par intégration d'un signal PWM généré (classiquement) par le microcontrôleur ATmega8.

4 Le code source du firmware en langage C:

CODE SOURCE en assembleur PIC
  1. /*==============================================================================
  2. par Silicium628
  3. derniere mise à jour 4 aout 2014
  4. ================================================================================
  5. ATmega8
  6. Pilotage d une alimentation a decoupage 20V
  7. -Affichage LCD 2 x 16 caractères
  8. ================================================================================
  9. IMPORTANT: programmer les FUSES BODLEVEL et BODEN (Brown out level detector) afin de fiabiliser le RESET à l'allumage
  10.  
  11. */
  12.  
  13.  
  14. #define F_CPU 16000000
  15.  
  16. #include <avr/io.h>
  17. #include <util/delay.h>
  18.  
  19. #include "dm_lcd.c" // l'attribution des pins/ports pour le LCD (et le type de LCD) est faite dans le fichier "dm_lcd.h"
  20.  
  21. #define bouton_L 0b00000001
  22. // #define bouton_U 0b00000010
  23. // #define bouton_D 0b00000100
  24. #define bouton_R 0b00001000
  25.  
  26.  
  27. char * version = "6.6";
  28.  
  29.  
  30. /*
  31. RAPPEL variables avr-gcc (vérifiable avec le .map)
  32.  
  33. char 1 -128 .. 127 ou caractères
  34. unsigned char 1 0 .. 255 (equiv à byte du pascal)
  35. uint8_t 1 (c'est la même chose que l'affreux 'unsigned char')
  36. char toto[n] n
  37. int 2 -32768 .. 32767
  38. int16_t 2 idem 'int'
  39. short int 2 pareil que int (?)
  40. unsigned int 2 0 .. 65535
  41. uint16_t 2 idem 'unsigned int'
  42. long int 4 -2 147 483 648 à 2 147 483 647
  43. int32_t 4 32 bits ; idem long int
  44. unsigned long long 64-bit unsigned type.
  45. uint64_t 8 64-bit unsigned type.
  46. long long int 8
  47. unsigned long int 4 32 bits ; 0 .. 4 294 967 295 (4,2 x 10^9)
  48. float 4
  49. double 4 // (?)
  50.  
  51. La déclaration char JOUR[7][9];
  52. réserve l'espace en mémoire pour 7 mots contenant 9 caractères (dont 8 caractères significatifs).
  53. */
  54.  
  55. uint16_t consigne_V; // 0..200 pour 0V.. a 20.0V
  56. uint16_t valeur16b;
  57. // uint8_t digits_consigne_V[3];
  58. uint16_t I_max;
  59. // uint16_t mesure_V;
  60. uint16_t memo1_I;
  61. uint16_t memo2_I;
  62. uint16_t memo3_I;
  63. uint16_t memo4_I;
  64.  
  65. uint16_t mesure_I;
  66. uint16_t valeur_I;
  67.  
  68. uint8_t pos;
  69. uint8_t pos_curseur;
  70. uint8_t boutons_I;
  71. uint8_t boutons_V;
  72. uint8_t memo_boutons_V;
  73. uint8_t code_rot;
  74. uint8_t memo_code_rot;
  75. uint8_t etat;
  76. int16_t valeur_rot;
  77. uint16_t compteur1;
  78. uint16_t offset_I;
  79.  
  80.  
  81.  
  82. void init_ports (void) // ports perso
  83. // 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
  84. {
  85. PORTB = 0b00000000;
  86. DDRB |= 0b00000010; // portB[1] = sortie (OC1A = sortie PWM 16 bits du timer1)
  87.  
  88. DDRC = 0b11001111; //PC4 en entree (ADC4 - mesure du courant); PC5 en entree (ADC5 - mesure de la tension)
  89.  
  90. DDRD = 0b11000000; //portD[0..3] en entree (4 boutons) ; portD[4..5] en entree (4 boutons sur 2 bits)
  91. PORTD = 0b00111111;
  92. }
  93.  
  94.  
  95. void InitADC (void)
  96. {
  97. ADCSRA = _BV(ADEN) | _BV(ADPS2); // Activate ADC with Prescaler 16 --> 1Mhz/16 = 62.5kHz
  98. ADMUX |= 0b11000101; //Bit 7:6 – REFS1:0: ADC Reference Selection Bits =11 -> Internal 2.56V Voltage Reference with external capacitor at AREF pin ; Bits 0:3 - Analog Channel Selection Bits
  99. // ici Select pin ADC5 using MUX avec ref tension interne = 2.56V
  100.  
  101. }
  102.  
  103. void InitINTs (void)
  104. {
  105. GICR |= 0b00000000; // gere les INTs voir page 67 du pdf
  106. MCUCR |= 0b00000010; // The falling edge of INT0 generates an interrupt request. p:67 du pdf
  107. }
  108.  
  109.  
  110. void InitPWM (void)
  111. {
  112. TCCR1A |= (1 << COM1A1); // set none-inverting mode
  113.  
  114. TCCR1A |= (1 << WGM11) | (1 << WGM10); // set 10bit phase corrected PWM Mode
  115.  
  116. // TCCR1B |= (1 << CS11); // set prescaler to 8 and starts PWM
  117. TCCR1B |= (1 << CS10); // set no prescaler and starts PWM
  118.  
  119. OCR1A = 0;
  120. }
  121.  
  122.  
  123. void init_variables(void)
  124. {
  125. consigne_V=0;
  126. offset_I =0;
  127.  
  128. memo1_I=0;
  129. memo2_I=0;
  130. memo3_I=0;
  131. memo4_I=0;
  132.  
  133. valeur_rot=100;
  134.  
  135. }
  136.  
  137.  
  138. void lcd_gotoxy_clrEOL (int x, int y)
  139. // place le curseur en x,y et efface jusqu'a la fin de la ligne
  140. {
  141. lcd_gotoxy(x, y);
  142. uint8_t i;
  143. for (i=x; i<20; i++)
  144. { lcd_puts(" "); }
  145. lcd_gotoxy(x, y);
  146. }
  147.  
  148.  
  149.  
  150. void lcd_aff_nb (uint16_t valeur, uint8_t nb_chiffres, uint8_t nb_decimales)
  151. {
  152. //affiche un nombre en representation decimale
  153. unsigned char r ;
  154. char tbl[7];
  155. uint8_t i;
  156.  
  157. for (i=1; i<=nb_chiffres; i++)
  158. {
  159. r=48 + valeur % 10; // modulo (reste de la division)
  160. valeur /= 10; // quotient
  161. tbl[i]=r;
  162. }
  163. for (i=1; i<=nb_chiffres; i++)
  164. {
  165. if (i== (nb_chiffres - nb_decimales +1) ) { lcd_puts("."); }
  166. lcd_putc(tbl[nb_chiffres +1 -i]);
  167. }
  168. }
  169.  
  170.  
  171.  
  172. void lcd_aff_bin (unsigned long int valeur, int nb_digits)
  173. {
  174. //affiche un nombre en representation binaire
  175. // 16 bits max
  176. unsigned char r ;
  177. char tbl[17];
  178. uint8_t i;
  179.  
  180. for (i=1; i<=nb_digits; i++)
  181. {
  182. r= 48 + valeur % 2; // modulo (reste de la division)
  183. valeur /= 2; // quotient
  184. tbl[i]=r;
  185. };
  186.  
  187. for (i=1; i<=nb_digits; i++)
  188. {
  189. lcd_putc(tbl[nb_digits +1 -i]);
  190. }
  191. }
  192.  
  193.  
  194.  
  195. void affiche_consigne_V(void)
  196. {
  197. // void lcd_aff_nb (uint16_t valeur, uint8_t nb_chiffres, uint8_t nb_decimales)
  198. lcd_gotoxy_clrEOL (0,0);
  199. lcd_puts("V: ");
  200. lcd_aff_nb(consigne_V, 3, 1);
  201. lcd_puts("V");
  202. lcd_gotoxy(pos_curseur,0);
  203. }
  204.  
  205. /*
  206. void affiche_mesure_V(void)
  207. {
  208. // void lcd_aff_nb (uint16_t valeur, uint8_t nb_chiffres, uint8_t nb_decimales)
  209. lcd_gotoxy_clrEOL (6,0);
  210. lcd_puts("mesu:");
  211. lcd_aff_nb(mesure_V, 3, 1);
  212. lcd_puts("V");
  213. lcd_gotoxy(pos_curseur,0);
  214. }
  215. */
  216.  
  217. void affiche_valeur_I(valeur)
  218. {
  219. lcd_gotoxy_clrEOL (0,1);
  220. lcd_puts("I=");
  221. lcd_aff_nb(valeur, 4, 0);
  222. lcd_puts("mA");
  223. lcd_gotoxy(pos_curseur,0);
  224. }
  225.  
  226.  
  227. void affiche_offset_I(valeur)
  228. {
  229. lcd_gotoxy_clrEOL (9,1);
  230. lcd_aff_nb(valeur, 4, 0);
  231. lcd_gotoxy(pos_curseur,0);
  232. }
  233.  
  234.  
  235. void affiche_consigne_I(void)
  236. {
  237. uint16_t i_A;
  238. i_A = I_max / 1000;
  239. lcd_gotoxy_clrEOL (6,0);
  240. lcd_puts("Imax=");
  241. lcd_aff_nb(i_A, 1, 0);
  242. lcd_puts("A");
  243. lcd_gotoxy(pos_curseur,0);
  244. }
  245.  
  246. /*
  247. void affiche_consigne_V(void)
  248. {
  249. uint8_t c, i, p;
  250.  
  251.  
  252. lcd_gotoxy_clrEOL (0,0);
  253.  
  254. for (i=0; i<=2; i++)
  255. {
  256. p=2-i;
  257. c=48+digits_consigne_V[p];
  258. if ((p==2) & digits_consigne_V[p] ==0 )
  259. {
  260. lcd_putc(' '); // n'affiche pas le premier 0 non sinificatif
  261. }
  262. else {lcd_putc(c); }
  263. if (p==1) {lcd_putc('.');}
  264. }
  265. lcd_puts("V");
  266.  
  267. pos_curseur =2-pos;
  268. if (pos_curseur>1) {pos_curseur++;}
  269. lcd_gotoxy(pos_curseur,0);
  270. }
  271.  
  272. */
  273.  
  274.  
  275.  
  276. /*
  277. void acqui_tension(void)
  278. {
  279. ADMUX = 0b11000101; // Select pin ADC5 using MUX - ref tension interne = 2.56V
  280. ADCSRA |= _BV(ADSC); //Start conversion - resolution 10bits
  281. while (ADCSRA & _BV(ADSC) ) {} // attend la fin de la converstion
  282. // ADCW = 0..1024 pour Vin = 0..2V56
  283.  
  284. mesure_V = ADCW;
  285. }
  286. */
  287.  
  288. void acqui_courant(void)
  289. {
  290. ADMUX = 0b11000100; // Select pin ADC4 using MUX - ref tension interne = 2.56V
  291. ADCSRA |= _BV(ADSC); //Start conversion - resolution 10bits
  292. while (ADCSRA & _BV(ADSC) ) {} // attend la fin de la converstion
  293.  
  294. //mesure_I = (894-ADCW)*16; // en mA ; lit la valeur convertie ; ADCW = 0..1024 pour Vin = 0..2V56
  295.  
  296. mesure_I = ADCW;
  297. }
  298.  
  299.  
  300. void lit_boutons_I(void)
  301. {
  302. boutons_I = PIND & 0b00110000;
  303. if (boutons_I == 0b00000000) {I_max = 4000; }
  304. if (boutons_I == 0b00010000) {I_max = 3000; }
  305. if (boutons_I == 0b00100000) {I_max = 2000; }
  306. if (boutons_I == 0b00110000) {I_max = 1000; }
  307. }
  308.  
  309.  
  310. void out_V()
  311. {
  312. valeur16b = 220 + consigne_V * 94;
  313.  
  314. OCR1A = valeur16b / 32; // fixe le rapport cyclique du signal PWM qui, une fois intégré par une cellule RC, produira la tension de consigne
  315. affiche_consigne_V();
  316. }
  317.  
  318.  
  319. void test_codeur_rot()
  320. {
  321. // pour test des états (diffèrent suivant modèles) du codeur rotatif pas à pas code gray
  322. // le mien est toujours à 11 en position stable
  323. // dans le sens CW il fait 11->01->00->10->11
  324. // et par conséquent dans le sens CCW il fait 11->10->00->01->11
  325. lcd_clrscr();
  326. while (1)
  327. {
  328. code_rot = PIND & 0b00000011;
  329. lcd_gotoxy(0,0);
  330. lcd_aff_bin (code_rot, 2);
  331. _delay_ms(10);
  332. }
  333. }
  334.  
  335.  
  336.  
  337. void lit_codeur_rot()
  338. {
  339.  
  340. // codeur incrémental code Gray avec en plus fonction bouton poussoir
  341. int p;
  342. uint8_t fine = 0;
  343. uint8_t mult = 10;
  344.  
  345. memo_code_rot = code_rot;
  346. code_rot = PIND & 0b00000011;
  347. fine = PIND & 0b00000100;
  348. if (fine == 0b00000100) { mult = 10; } else { mult =1; } // reglage fin si bouton appuyé (pas = 0.1V) sinon pas = 1V
  349. if (code_rot != memo_code_rot)
  350. {
  351. if ((memo_code_rot == 0b11) & (code_rot == 0b01)) { etat=1; p=0; }
  352. if ((etat==1) & (code_rot == 0b00)) { etat=2; p=0;}
  353. if ((etat==2) & (code_rot == 0b10)) { etat=3; p=0;}
  354. if ((etat==3) & (code_rot == 0b11)) { etat=4; p=+1;}
  355.  
  356. if ((memo_code_rot == 0b11) & (code_rot == 0b10)) { etat=5; p=0; }
  357. if ((etat==5) & (code_rot == 0b00)) { etat=6; p=0;}
  358. if ((etat==6) & (code_rot == 0b01)) { etat=7; p=0;}
  359. if ((etat==7) & (code_rot == 0b11)) { etat=8; p=-1;}
  360.  
  361. if ((etat==4) || (etat == 8))
  362. {
  363. consigne_V += (p * mult); p=0; etat =0;
  364.  
  365. if (consigne_V < 0) {consigne_V = 0;}
  366. if (consigne_V > 210) {consigne_V = 0;}
  367. if (consigne_V > 200) {consigne_V = 200;}
  368.  
  369. out_V();
  370. }
  371.  
  372. lcd_gotoxy(12,0);
  373. lcd_aff_nb (etat, 2, 0); // pour test du bouton encodeur
  374. if (etat > 8) {etat =8; } // pour éviter de se retrouver dans une impasse...
  375. _delay_ms(10);
  376. }
  377. }
  378.  
  379.  
  380. /*
  381.  
  382. void lit_boutons_V(void)
  383. {
  384. // pour boutons poussoirs traditionnels
  385. calcul_consigne_V();
  386.   memo_boutons_V = boutons_V;
  387.   boutons_V = PIND & 0b00001111;
  388.  
  389.   if (boutons_V != memo_boutons_V)
  390.   {
  391. //--------------------------------
  392. // position du curseur (digit actif)
  393. if( (boutons_V & bouton_L) == 0)
  394. {
  395. pos++;
  396. if (pos>2) { pos=2;}
  397. }
  398. if( (boutons_V & bouton_R) == 0)
  399. {
  400. if (pos>0) { pos--;}
  401. }
  402. //--------------------------------
  403. // edition du digit actif
  404.  
  405. //--------------- UP -----------------
  406. if ( (boutons_V & bouton_U) == 0)
  407. {
  408. digits_consigne_V[pos]++;
  409. if (digits_consigne_V[pos]>9)
  410. {
  411. digits_consigne_V[pos]=0;
  412. digits_consigne_V[pos+1]++;
  413. if (digits_consigne_V[pos+1]>9)
  414. {
  415. digits_consigne_V[pos+1]=0;
  416. digits_consigne_V[pos+2]++;
  417. }
  418. }
  419. calcul_consigne_V();
  420. if (consigne_V > 200)
  421. {
  422. digits_consigne_V[0]=0;
  423. digits_consigne_V[1]=0;
  424. digits_consigne_V[2]=2;
  425. calcul_consigne_V();
  426. }
  427. }
  428. //--------------- DOWN -----------------
  429. if (( (boutons_V & bouton_D) == 0) & (consigne_V > 0) )
  430. {
  431. if (digits_consigne_V[pos]>0)
  432. {
  433. digits_consigne_V[pos]--;
  434. }
  435. else if (digits_consigne_V[pos]==0)
  436. {
  437. if (digits_consigne_V[pos+1]>0)
  438. {
  439. digits_consigne_V[pos+1]--;
  440. digits_consigne_V[pos]=9;
  441. }
  442. else if (digits_consigne_V[pos+2]>0)
  443. {
  444. digits_consigne_V[pos+2]--;
  445. digits_consigne_V[pos+1]=9;
  446. digits_consigne_V[pos]=9;
  447. }
  448. }
  449. }
  450. calcul_consigne_V();
  451. if (consigne_V > 200) // possible ici par debordement lors de la decrementation
  452. {
  453. digits_consigne_V[0]=0;
  454. digits_consigne_V[1]=0;
  455. digits_consigne_V[2]=0;
  456. }
  457. calcul_consigne_V();
  458. affiche_consigne_V();
  459.  
  460.  
  461. }
  462. while ( (PIND & 0b00001111) != 0b00001111) { ;} // boucle en attendant le relachement du bouton
  463. }
  464.  
  465. */
  466.  
  467.  
  468. int main (void)
  469. {
  470. init_variables();
  471. init_ports();
  472. InitADC();
  473. // InitINTs(); non utilisees
  474. InitPWM();
  475.  
  476. //OCR1A = 65535;
  477.  
  478. lcd_init(LCD_DISP_ON_CURSOR);
  479. lcd_clrscr();
  480. lcd_home();
  481. lcd_puts("ALIM 20V");
  482. lcd_gotoxy(0,1);
  483. lcd_puts("version ");
  484. lcd_puts(version);
  485.  
  486. _delay_ms(1000);
  487.  
  488. lcd_clrscr();
  489.  
  490. consigne_V = 0;
  491. affiche_consigne_V();
  492. _delay_ms(500);
  493.  
  494. // ici la tension de sortie est maintenue = 0
  495. // le courant est donc nul. Toutefois la mesure du courant n'est pas exactement nulle.
  496. // on va donc l'annuler logiciellement (auto setup)
  497.  
  498. offset_I =0;
  499. acqui_courant();
  500. _delay_ms(200);
  501. offset_I = mesure_I;
  502.  
  503. consigne_V = 50; // -> 5.0V
  504. out_V();
  505.  
  506. // affiche_valeur_I(mesure_I);
  507. // affiche_offset_I(offset_I);
  508.  
  509. //test_codeur_rot(); // pour test des états (diffèrent suivant modèles)
  510.  
  511.  
  512. while(1)
  513. {
  514. lit_codeur_rot();
  515.  
  516. lit_boutons_I();
  517. // acqui_tension();
  518.  
  519.  
  520. compteur1++;
  521. if (compteur1 >= 60000)
  522. {
  523. memo1_I = valeur_I;
  524. acqui_courant();
  525.  
  526. if (offset_I > mesure_I) {valeur_I = offset_I - mesure_I;} else {valeur_I = 0;}
  527. valeur_I *=15;
  528.  
  529. valeur_I += memo1_I;
  530. valeur_I /=2;
  531.  
  532. affiche_valeur_I(valeur_I);
  533.  
  534. //affiche_offset_I(offset_I);
  535. //lcd_gotoxy_clrEOL (0, 1);
  536. //lcd_aff_nb (valeur16b, 5, 0);
  537.  
  538.  
  539. compteur1=0;
  540. }
  541.  
  542. _delay_us(10);
  543. }
  544.  
  545.  
  546. }
  547.  
  548.  

5 Explication de quelques points du soft:

Le signal PWM de génération de la tension de consigne est généré par le timer1 en configuration de résolution temporelle sur 16bits:

code:
"TCCR1A |= (1 << WGM13) | (1 << WGM12) | (1 << WGM11) | (1 << WGM10); // set 16bit phase corrected PWM Mode"

Lors de la phase de RESET (qui peut durer... un certain temps surtout si l'on s'endort avec le doigt appuyé sur le bouton "reset") tous les pins d'E/S de l'ATmega8 se placent en mode haute impédance. Leur potentiel est alors déterminé par la connectique. C'est la raison de la présence d'une résistance de 10k câblée entre le pin15 (PB1 = sortie OC1A : signaux PWM) et GND de façon à annuler la tension de sortie pendant cette phase.

L'attribution des pins/ports pour le LCD (et le type de LCD) est faite dans le fichier "dm_lcd.h"

6 La limitation en courant

La limitation du courant de sortie est obtenue par logiciel. L'acquisition de l'intensité est réalisée par un capteur à effet hall (UGN 3503) inséré dans une fente pratiquée dans un tore en ferrite sur lequel sont bobinées 30 spires parcourues par le courant.

Toute la difficulté réside dans la réalisation de la fente dans la ferrite. La meilleure des scies à métaux ne tient pas plus d'une minute, après quoi elle est bonne à couper le beurre.

Un disque miniature de perceuse voit son diamètre se réduire tout aussi vite...

La solution: une petite fraise diamantée, visible sur la photo ci-contre.

7 -

Le capteur UGN 3503 à effet Hall est maintenu dans la fente par l'épaisseur d'un morceau de gaine thermorétractable transparente (solution démontable, la transparence de la gaine permettra aux générations futures de lire facilement le type du composant utilisé ;)

8 Le circuit imprimé

Le circuit imprimé est réalisé avec le logiciel libre Kicad sous Linux Mint. Les "gros" composants (transfo, pont de diodes, selfs toriques, condensateurs électrochimiques, Mosfet et radiateur) restent en dehors de la carte, ils sont directement fixés dans le boîtier.

9 -



15314