PROGRAMMATEUR POUR LAVE LINGE
basé sur un ATmega32 - firmware en C

15 mai 2012: J'ai acheté en 2008 un lave linge dont le programmateur électronique à grillé au bout de 10 jours! Que faire dans ce cas? moi je me suis empressé de jeter le certificat de garantie à la poubelle et j'ai mis au point ce programmateur électronique basé sur un ATméga32, dont le firmware (programme interne) est libre et pour cause, c'est moi qui l'ai écrit, et les schémas publics pour la même raison. Je me suis dis: comme ça s'il tombe en panne, au moins je pourrai le réparer moi-même. Mais il fonctionne toujours, depuis quatre ans maintenant (2008)! (Je pense toutefois à débrancher la prise de courant en cas d'orage, comme je le fais du reste pour la totalité des appareil chez moi). Le programme n'est pas parfait, mais il est modifiable, améliorable, d'ailleurs il m'arrive d'y apporter de petites modifications de temps en temps... Par exemple, la machine vieillissant, je vais ajouter des fonctions importantes de détection de panne du matériel (temps de remplissage anormalement long suite à fuite d'eau par exemple...)

1 Mise en garde préalable

Cette réalisation comprend deux parties:
  • une carte basse tension regroupant le microprocesseur et quelques composants.
  • une carte haute tension reliée au secteur 230V comprenant des triacs, mais aussi des circuits d'isolation galvanique entre le secteur et la partie basse tension, à savoir des optotriacs (MOC3043), des relais, ainsi qu'un transformateur d'alimentation. De ce fait cette carte doit être routée et réalisée avec le plus grand soin de façon à ce que la partie basse tension ne puisse en aucun cas entrer en contact avec le secteur 230V.
Pour cette raison je ne publierai pas les typons de réalisation des cartes mais seulement les schémas théoriques. A partir du même schéma, une implantation des composants ou une réalisation mal faite peut vous amener tout droit au cimetière! Si vous n'êtes pas habitué aux montages fonctionnant sur le secteur, je vous déconseille vivement de réaliser ce programmateur. Je précise que je ne vends rien, je ne réalise rien pour les autres. Je me contente d'exposer ce que je fais pour moi, à titre d'exemple à ne PAS suivre, afin d'illustrer les extraordinaires possibilités des microcontrôleurs. En revanche je fournis tous mes codes sources en Pascal, et/ou en C, commentés. D'autre part les lave-linges sont en principe équipés d'une sécurité (mécanisme de blocage électrique de la porte) qu'il est hors de question de supprimer, même si je ne l'ai pas fait figurer sur mes schémas.

2 Principe général:

Le  microcontrôleur ATmega32 contrôle l'ensemble des organes.

1) En sortie:
  •  marche - arrêt, vitesse et sens de rotation du moteur (moteur "type universel" à balais et charbons)
  •  électrovannes d'admission d'eau
  •  pompe de vidange
  •  résistance de chauffage
  • Afficheur LCD 4lignes de 20 caractères (bleu).
  • Quelques LED de toutes les couleurs
2) En entrée:
  • capteur de niveau d'eau (celui d'origine, à contacts, je prévois de la remplacer par un capteur de pression)
  • dynamo tachymétrique sur l'axe du moteur (d'origine)
  • sonde de température résistive (d'origine)
  • signal de référence de phase du 50Hz secteur.
  • récepteur de télécommande IR
  • boutons poussoirs.
La vitesse de rotation du moteur est asservie par le microcontrôleur. Sa tension d'alimentation 230V est découpée par un triac commandé par l'ATmega. En effet, directement alimenté en 230V le moteur tourne à la vitesse d'essorage. Il faut donc le ralentir pour le lavage. Mais l'asservissement de vitesse est rendu nécessaire du fait que le couple varie ENORMEMENT lors de chaque tour du tambour dû à la répartition et aux déplacements du linge dans ce tambour. D'où la présence de la dynamo tachymétrique sur l'axe du moteur. l'ATmega mesure en permanence la vitesse réelle du tambour (par une fonction fréquencemètre programmée) et la compare à une consigne. Le résultat sert à régler l'angle de conduction du triac afin de maintenir la vitesse constante (asservissement de vitesse). C'est un des points les plus délicats du programme.

Le sens de rotation du moteur est choisi par permutation du branchement  du stator par rapport au rotor, par deux relais.
La pompe et les électrovannes sont commandées par des triacs.
La résistance de chauffage est commandée par un relais 230V - 10A.

Le microcontrôleur et les circuits basse tension (5V) sont isolés du secteur 230V:
  • l'alimentation par un transformateur 230V - 2x6V
  • les triacs par des opto-triacs à détection de passage à zéro MOC3043.
  • le triac de découpage de la tension du moteur par un opto-triac SANS détection de passage à zéro MOC3023 (réponse instantanée)
 Le tout est géré à distance par une télécommande pour TV ! (ça évite de toucher à quoi que ce soit pendant le fonctionnement de la machine)

3 Vue d'ensemble

  • La petite carte tout en haut: c'est le programmateur AVR USB.
  • A gauche la carte haute tension.
  • A droite la carte logique avec l'ATmega32 et l'afficheur LCD.
  • et  la zappète TV (modèle universel en mode "TV") qui permet de mettre la machine en marche de choisir les programmes de lavage et bien d'autres choses.

4 La carte logique et la carte d'affichage à LED

Une carte d'affichage à LED disposées en cercle donne un petit air rétro.

C'est bien pratique pour apprécier du premier coup d'œil où en est le cycle de lavage.

5 L'ensemble en fonctionnement

L'ensemble des cartes reliées à la machine, le tout en fonctionnement.

6 Le schéma de la carte haute tension

7 Le schéma de la carte logique

8 La carte haute tension

Pour la partie haute de la carte, de gauche à droite:

-tout en haut en jaune les borniers de raccordement des (nombreux) fils du lave linge.
-le triac BT137 -600 de commande de la vitesse du moteur
- les deux relais de commande du sens de rotation
- emplacement vide qui reçoit le relais de chauffage
- les triacs pour la pompe et les électrovannes


Viennent au dessous les optotriacs d'isolation secteur (petits boîtier blancs)
Le transfo d'alim. pour le 5V et quelques composants basse tension

9 La carte logique

  • Au centre de la carte se trouve le gros circuit 40 pins de l'ATmega32 (signalons au passage que la version CMS est minuscule en comparaison)
  • Le petit boîtier noir à sa gauche est le récepteur infra-rouge pour recevoir les ordres de la télécommande.
  • L' afficheur se situe en dehors de la carte proprement dite, il comporte bien 4 lignes et non deux comme il semblerait sur cette photo (le microprocesseur n'était pas encore programmé).

Le programme est en Pascal. 

10 L' implantation des composants de la carte à LED

11 Le code source du Firmware en langage Pascal (obsolete, désormais programmé en C, voir plus bas)

CODE SOURCE en langage Pascal
  1. program lavelinge;
  2. {===============================================================================
  3. par Silicium628 - voir la description de cette realisation sur mon site
  4. (chercher silicium628 sur Google.fr, on ne peut pas le rater!)
  5. versions: voir plus bas dans la partie "const" - derniere mise a jour 3 mars 2009
  6. La version est visible sur l'afficheur par la touche 9 de la telecommande IR
  7. Quel plaisir de programmer un uControleur en PASCAL ! :-)
  8. ================================================================================
  9. PRINCIPE:
  10. --------------------------------------------------------------------------------
  11. Le moteur est un modele dit "universel" (a charbons)
  12. La vitesse du moteur en 220V est tres grande
  13. La vitesse est limitee par un decoupage de la tension secteur par un triac BT137 - 800
  14. drive par un optocoupleur MOC3023 (sans circuit de detection de passage a zero)
  15. Le sens de rotation du moteur est change par inversion du bobinage du stator
  16. par rapport au rotor cable en serie. Cette inversion est obtenue au moyen de deux relais inverseurs.
  17. Le moteur n'est pas alimente si les relais sont tous deux au repos ou tous deux colles.
  18. Toutefois cette deuxieme configuration (tous deux colles) est sans interet et consomme
  19. inutilement sur l'alim 5V. Elle n'est donc pas permise.
  20.  
  21. Le moteur est egalement stoppe par absence d'impulsions de commande sur l'optocoupleur
  22. (et donc le triac)
  23.  
  24. IMPORTANT:
  25. 1) Les relais ne doivent jamais etres commutes alors que des impulsions de commandes
  26. du triac sont presentes, sous peine de destruction possible du triac.
  27. La procedure consiste donc a arreter les impulsions et a attendre quelques secondes
  28. avant de commuter un relais.
  29. 2) Je deconseille d'envoyer des impulsions lorsque les deux relais sont au repos,
  30. et donc lorsque le triac est en roue libre.
  31.  
  32. --------------------------------------------------------------------------------
  33. REMARQUE: Triac sur charge inductive:
  34. Lors de la conduction du triac, le courant dans une inductance s'etablit progressivement.
  35. Donc pas de di/dt important, et partant pas de surtension (e=-L.di/dt)).
  36. Mais un dv/dt important et genant.
  37.  
  38. Une coupure du courant dans une inductance provoque un di/dt qui genere mathematiquement une
  39. surtension E=-L.di/dt. Oui mais un triac n'est pas un transistor! Un triac se bloque
  40. naturellement de lui meme lorsque le courant s'annule. DONC PAS DE SURTENSION au blocage contrairement
  41. a ce qu'on lit ici ou la a longueur de journee.
  42. Dans une self, la tension est en quadrature avec le courant. Donc le minimum de courant correspond
  43. a une tension non nulle (aux bornes de la self, en serie avec le secteur et en opposition
  44. de phase avec celui-ci vu du triac, donc zero volt vu du triac, me trompe-je ?)
  45. Un circuit dit "snubber" (100nF 250V alternatif + 100 ohm en serie) est cable en //
  46. entre A1 et A2 du triac. La fonction du condensateur est de maintenir un courant non nul dans le triac
  47. a la mise en conduction, le courant passant dans le bobinage ne s'etablissant que trop lentement.
  48. Quant a la resistance en serie avec le condensateur, elle sert a limiter le courant en question.
  49. Sans la resistance, c'est la destruction assuree du triac. De meme une resistance de trop
  50. faible valeur fait veillir le triac prematurement et aboutit a une destruction plus ou moins rapide.
  51.  
  52. Il existe maintenent des triacs qui se passent de snubber...
  53. --------------------------------------------------------------------------------
  54. TEMPERATURES
  55. degres (Acquisition) (compte tenu de mon schema)
  56. 20 (112)
  57. 30 (85)
  58. 40 (69)
  59. 50 (58)
  60. 60 (44)
  61. 80 (39)
  62. 90 (35)
  63. ================================================================================
  64. La carte electronique repond aux signaux d'une telecommande TV infrarouge universelle
  65. Beaucoup de modeles conviennent, il faudra adapter les codes des touches dans ce
  66. programme le cas echeant (voir les 'case octet_IR of') dans la partie "main"
  67. Pour ma part, j'utilise une PHILIPS type 'UNIVERSAL SBC RU 252 II'
  68.  
  69. ================================================================================
  70. }
  71.  
  72. { $W+ Warnings} {Warnings off}
  73.  
  74. Device = mega32, VCC = 5;
  75.  
  76. Import SysTick, LCDport, RTclock, {TickTimer,} RC5Rxport, FreqCount, ADCPort;
  77.  
  78. From RTclock Import RTCtimer;
  79.  
  80. From System Import Int64, float;
  81.  
  82. Define
  83. ProcClock = 16000000; {Hertz}
  84. SysTick = 10, Timer0; {msec} // ATTENTION: necessaire pour l'horloge RTC et LCD
  85. RTclock = iData, DateTime; {Time, DateTime}
  86. RTCtimer = 4; // 4 cannaux
  87. RTCsource = SysTick {, adj}; { adj = +/-100}
  88.  
  89. // TickTimer = Timer1; //le Timer1 de l'ATmega32 est un timer 16bits
  90. FreqTimer = Timer1; // (used 16bit Timer}
  91.  
  92. StackSize = 512, iData; // (voir affi en runtime)
  93. FrameSize = 512, iData;
  94. LCDport = PortC;
  95. LCDtype = 44780;
  96. LCDrows = 4; {rows}
  97. LCDcolumns = 20; {columns per line}
  98.  
  99. RC5Rxport = PinC, 7, negative; {Port, Pin#, polarity}
  100. RC5mode = rc_6bit; {command bit count}
  101.  
  102. ADCchans = [8], iData; {use only 1 Channel, ADC7}
  103. ADCpresc = 128;
  104.  
  105. Define_usr
  106. bouton_inc_h = %00100000;
  107.  
  108.  
  109. Implementation
  110.  
  111. //==============================================================================
  112. {$IDATA}
  113.  
  114. type
  115. Tprog = (couleur, blanc, laine, froid, rapide, test);
  116.  
  117. const
  118. version : string = '3.12';
  119. // icone_anime : string = '|/-\';
  120. Labels_numeros : array [1..15] of string[8] = ('eau', 'lavage', 'vidange', 'eau',
  121. 'rincage1', 'vidange', 'eau', 'rincage2', 'vidange', 'eau',
  122. 'rincage3', 'vidange', 'eau', 'rincage4', 'essorage');
  123.  
  124. OCRmin_ESS : byte = 60; // vitesse la plus rapide
  125. OCRmin_purge : byte = 80;
  126. OCRmin_LAV : byte = 75; // 95
  127.  
  128. OCRmax_ESS : byte = 130;
  129. OCRmax_purge : byte = 130;
  130. OCRmax_LAV : byte = 130;
  131. OCRmax : byte = 130; // vitesse la plus lente
  132. // attention 162 est la limite au dela de laquelle on retablit les alternances a 100%
  133. // compte tenu de mon schema
  134.  
  135. P_cons_lav : word = 1500; // 2000
  136. // P_cons_defoul : word = 4000;
  137. P_cons_purge : word = 300; // 300
  138. tps_rincage_max : word = 90; // secondes
  139.  
  140. { Type Declarations }
  141.  
  142.  
  143.  
  144. //==============================================================================
  145. {$IDATA}
  146.  
  147. var
  148. // delay : SysTimer8;
  149. compteur1 : integer;
  150. ti : byte;
  151. ticked : boolean;
  152. timeout1 : boolean; // pour RTCtimer
  153. timeout2 : boolean; // pour RTCtimer
  154. timeout3 : boolean; // pour RTCtimer
  155. timeout4 : boolean; // pour RTCtimer
  156. stk1 : word;
  157. stk1_min : word;
  158. fram_free : word;
  159. fram_free_min : word;
  160.  
  161. // FreqMode : tFreqCountMode;
  162. // Freq : word;
  163. Periode : word;
  164. OCR2_real : float;
  165. str12 : string[12];
  166.  
  167. rxAdr : byte;
  168. rxCmd : byte;
  169. adr1 : integer;
  170. cmd1 : integer;
  171. octet_IR : byte; //octet recu par le recepteur IR
  172. bitsix : byte;
  173. memobitsix : byte;
  174. nouveau : boolean; // pour l'anti rebond signaux IR
  175. acqui_ADC : word;
  176. pos_bt : byte;
  177.  
  178. stop_imps : boolean; // force le blocage du triac
  179. relais1 : boolean;
  180. relais2 : boolean;
  181. EV1 : boolean; // electrovanne 1 (admision d'eau pour le prelavage)
  182. EV2 : boolean; // electrovanne 2 (admision d'eau pour le lavage et les rincages)
  183. pompe : boolean;
  184. NIV1 : boolean; // pressostat
  185. NIV2 : boolean; // pressostat
  186. TXTniv : string[2];
  187. Nom_prg : string[10];
  188. affi_requis : boolean;
  189. temps_i : byte; // pour le generateur d'impulsions vers le triac moteur. compteur en secondes
  190. temps_ch_sens : byte; // pour le changement automatique de sens
  191. periode_ch_sens : byte;
  192.  
  193. lavage : boolean;
  194. temps_lavage : word; // compteur en secondes
  195. tps_lavage_max : word; // secondes
  196. timeOUT_lavage : boolean;
  197. tps_pause : longword; // pause reglable de qq secondes ou plus lors du changement de sens (longue pour la laine)
  198.  
  199. temps_pompe : word; // compteur en secondes
  200. temps_EV2 : word; // compteur en secondes
  201.  
  202. rincage : boolean;
  203. temps_rincage : word; // compteur en secondes
  204. timeOUT_rincage : boolean;
  205. nb_rincage_max : byte;
  206.  
  207. essorage : boolean;
  208. temps_essorage : word; // compteur en secondes
  209. tps_essr_max : word;
  210. timeOUT_ess : boolean;
  211. P_cons_ess : word;
  212. ajout_vt_esso : word;
  213. accelere : boolean;
  214.  
  215. purge : boolean;
  216. temps_purge : word; // compteur en secondes
  217. tps_purge_max : word;
  218. timeOUT_purge : boolean;
  219.  
  220. temps_defoul : word;
  221. tps_deffou_max : word;
  222. TimeOUT_defoul : boolean;
  223.  
  224. temps_total : byte; // compteur en minutes
  225. num_requis : byte;
  226. remplissage : boolean;
  227.  
  228. chauffage : boolean;
  229. chauffe_enable : boolean;
  230. brassage : boolean;
  231.  
  232. defoulage : boolean;
  233.  
  234. vidange : boolean;
  235. sens_enable : boolean; // permet ou bloque le changement de sens automatique du moteur toutes les 15s
  236. TimeOUT_sens : boolean;
  237. vert : boolean;
  238. Temperat_max : float; // temperature de lavage
  239. prog1 : Tprog;
  240. numero : byte;
  241. a_choisir : boolean;
  242. {--------------------------------------------------------------}
  243. {functions }
  244.  
  245. procedure init_ports; // ports perso
  246. // 0 = entree, 1=sortie
  247. begin
  248.  
  249. portA:= %00000000;
  250. DDRA:= %01111111; // portA[7] = entree Thermistance
  251.  
  252. portB:= %00000000;
  253. DDRB:= %11111101; // portB[1] = T1 = entree (pour le frequencemetre)
  254.  
  255. DDRC:= DDRC and %01111111;
  256.  
  257. portD := %10100011; // les 1 sur les pins en entrees activent les R de Pull Up (tirage a VCC)
  258. DDRD:= DDRD or %10011000; // portD[6] en entree (ICP periodemetre) portD[7] en sortie (OC2)
  259.  
  260. SFIOR:= SFIOR and %11111011; // p:50 (bit PUD du SFIOR)
  261. // (the Pull-up Disable PUD bit in SFIOR disables the pull-up function for all pins in all ports when set)
  262. end;
  263.  
  264.  
  265. procedure interroge_IR;
  266. begin
  267. if RecvRC5(rxAdr, rxCmd) then // interroge IR
  268. adr1:= integer(rxAdr);
  269. cmd1:= {%00111111 and} integer(rxCmd);
  270. octet_IR:= byte(cmd1); // le bit6 (=64 decimal) est=1 un appui de touche de la zapette sur deux
  271. memobitsix:= bitsix;
  272. bitsix:= octet_IR and %01000000;
  273. if bitsix <> memobitsix then
  274. nouveau:= true;
  275. else nouveau:= false;
  276. endif;
  277. octet_IR:= octet_IR and %00111111; // on supprime l'info de repetition de l'octet
  278. // portx:= portx or ......; // allume LED
  279. else
  280. octet_IR:= $FF;
  281. // portx:= portx and %......; // eteint LED
  282. endif;
  283. if nouveau = false then octet_IR:= $FF; endif; // pas de repetition auto dans cette application
  284. end;
  285.  
  286.  
  287. procedure InitINTs;
  288. begin
  289. {Les 3 bits de poids faible de TCCR2 selectionnent l'horloge et le prescaler. voir page 119 et 125 du pdf
  290. Bit 6, 3 WGM21:0 = 01 -> mode CTC voir p:125 du pdfCTC = "Clear Timer on Compare Match" (CTC) Mode
  291. In "Clear Timer on Compare mode" (CTC mode, WGM21:0 = 2), the counter is cleared to zero when the
  292. counter value (TCNT2) matches the OCR2. The OCR2 defines the top value for the counter, hence also its resolution.
  293. }
  294. TCCR2 := TCCR2 or %10001111; // p:125
  295. TIMSK := TIMSK and %01111111; // INT Timer2 comp disable; Voir le datasheet ATmega32.pdf p:130}
  296. GICR := GICR or %01000000; // extINT0 enable; voir page 67 du pdf
  297. MCUCR := MCUCR or %00000010; // The falling edge of INT0 generates an interrupt request. p:67 du pdf
  298. end;
  299.  
  300.  
  301. (*
  302. interrupt Timer2COMP;
  303. { Commande de l'angle de fermeture du triac
  304.  Cette interruption n'est plus utilisee (abandonnee parce que trop de telescopages avec les autres)
  305.  On utilise directement le signal sur la sortie OCE
  306.  la sortie OC2 Genere un signal "carre" qui bascule a chaque comparaison reussie.
  307.  un petit circuit (monostable avec un NE555 et des inverseurs 40106) genere ensuite 2 impulsions
  308.  espacees de 10ms pour commander les deux alternances
  309.  en 50Hz, la periode vaut 20ms (1/50Hz) et la demi periode vaut donc 10ms
  310.  REMARQUE: The OCF2 Flag is automatically cleared when the interrupt is executed. (p:116 du pdf)
  311. }
  312. begin
  313. {
  314.  portB:= portB or %00000001; // POUR TEST
  315.  udelay(20); // POUR TEST
  316.  portB:= portB and %11111110; // POUR TEST
  317. }
  318. end;
  319. *)
  320.  
  321. interrupt Int0;
  322. // front descendant sur l'entree Int0
  323. begin
  324. PushAllRegs;
  325. TCNT2:= 0;
  326. TCCR2:= TCCR2 or %00110000; // set OCE on compare match
  327. TCCR2:= TCCR2 or %10000000; // bit FOCE2 voir p:125 (force comparaison virtuelle pour RAZ OCE)
  328. // ce qui a pour effet de passer la sortie OCE a 1
  329. if not stop_imps then
  330. TCCR2:= TCCR2 and %11101111; // clear OCE on compare match (generera le signal sur OCE)
  331. endif;
  332. PopAllRegs;
  333. end;
  334.  
  335.  
  336. procedure Affiche_STACK_free; // attention: ne pas appeller depuis une INT sinon fait planter
  337. begin
  338. LCDxy(16, 3);
  339. Write(LCDout, IntToStr(stk1 : 3 : '0') );
  340. // LCDxy(16, 3);
  341. // Write(LCDout, IntToStr(fram_free : 3 : '0') ); fonction bugguee? chaque lecture consomme 1 octet!
  342. //
  343. end;
  344.  
  345.  
  346. procedure vitesse_mini;
  347. begin
  348. OCR2:= OCRmax;
  349. OCR2_real:= OCRmax;
  350. end;
  351.  
  352.  
  353. procedure relais1_on;
  354. begin
  355. portA:= portA or %00000100;
  356. relais1:= true;
  357. LCDxy(0, 3);
  358. Write(LCDout, '>');
  359. end;
  360.  
  361.  
  362. procedure relais1_off;
  363. begin
  364. portA:= portA and %11111011;
  365. relais1:= false;
  366. LCDxy(0, 3);
  367. Write(LCDout, ' ');
  368. end;
  369.  
  370.  
  371. procedure relais2_on;
  372. begin
  373. portB:= portB or %00000100;
  374. relais2:= true;
  375. LCDxy(0, 3);
  376. Write(LCDout, '<');
  377. end;
  378.  
  379.  
  380. procedure relais2_off;
  381. begin
  382. portB:= portB and %11111011;
  383. relais2:= false;
  384. LCDxy(0, 3);
  385. Write(LCDout, ' ');
  386. end;
  387.  
  388.  
  389. procedure EV2_on; // commande electrovanne2. //(on peut en rajouter... pour le prelavage par exemple...)
  390. begin
  391. portA:= portA or %00000010;
  392. EV2:= true;
  393. temps_EV2:= 0;
  394. LCDxy(5, 3);
  395. Write(LCDout, 'EV');
  396. LCDxy(7, 3);
  397. Write(LCDout, '2');
  398. end;
  399.  
  400.  
  401. procedure EV2_off;
  402. begin
  403. portA:= portA and %11111101;
  404. EV2:= false;
  405. if not(EV1) then // le dernier ferme la porte en sortant!
  406. LCDxy(5, 3);
  407. Write(LCDout, ' ');
  408. endif;
  409. LCDxy(7, 3);
  410. Write(LCDout, ' '); // chacun balaye devant sa porte
  411. end;
  412.  
  413.  
  414. procedure CHAUFFAGE_off;
  415. begin
  416. // stk1:= GetStackFree; if stk1 < stk1_min then stk1_min:= stk1; endif;
  417. // fram_free:= GetStackFree; if fram_free < fram_free_min then fram_free_min:= fram_free; endif;
  418. portB:= portB and %11101111; // relais chauffage
  419. chauffage:= false;
  420. periode_ch_sens:= 12;
  421. end;
  422.  
  423.  
  424. procedure CHAUFFAGE_on;
  425. begin
  426. //stk1:= GetStackFree; if stk1 < stk1_min then stk1_min:= stk1; endif;
  427. if chauffe_enable then
  428. stop_imps:= true;
  429. portB:= portB or %00010000; // relais chaufage
  430. chauffage:= true;
  431. periode_ch_sens:= 8;
  432. endif;
  433. end;
  434.  
  435.  
  436. procedure POMPE_on;
  437. begin
  438. Chauffage_OFF;
  439. portB:= portB or %00001000; // pompe
  440. pompe:= true;
  441. temps_pompe:= 0;
  442. end;
  443.  
  444.  
  445. procedure POMPE_off;
  446. begin
  447. portB:= portB and %11110111; // pompe
  448. pompe:= false;
  449. end;
  450.  
  451.  
  452. procedure detection_niveau_eau; // j'ai supprime la detection du niveau2 (3/4 de cuve, c'est trop)
  453. begin
  454. //stk1:= GetStackFree; if stk1 < stk1_min then stk1_min:= stk1; endif;
  455. if (PinD and %00100000) = 0 then
  456. TXTniv:= 'Lo'; NIV1:= true; NIV2:= false;
  457. // elsif (PinD and %00100000) = 0 then
  458. // TXTniv:= 'Hi'; NIV1:= false; NIV2:= true;
  459. else
  460. NIV1:= false;
  461. NIV2:= false;
  462. TXTniv:= '--';
  463. endif;
  464. end;
  465.  
  466.  
  467. procedure RAZ_tempos;
  468. begin
  469. // initialisation des compteurs avec des valeurs qui les bloquent
  470. temps_lavage:= 100*60; // en secondes
  471. temps_rincage:= 100*60; // en secondes
  472. temps_pompe:= 0;
  473. temps_EV2:= 0;
  474. // temps_fin_vidange:= 100;
  475. temps_essorage:= 100*60; // en secondes
  476. temps_defoul:= 100*60;
  477. temps_total:= 100;
  478. temps_ch_sens:= 5;
  479. tps_pause:= 1;
  480.  
  481. prog1:= couleur;
  482. Temperat_max:= 40;
  483. tps_lavage_max:= 10*60; // secondes
  484. tps_pause:= 1;
  485. tps_essr_max:= 4*60; // secondes
  486. tps_purge_max:= 20; // secondes //15
  487. tps_deffou_max:= 30; // secondes
  488. periode_ch_sens:= 10; // secondes
  489. ti:= 0;
  490. end;
  491.  
  492.  
  493. procedure init_variables;
  494. begin
  495. stk1_min:= 1000;
  496. fram_free_min:= 1000;
  497. stop_imps:= true;
  498. remplissage:= false;
  499. lavage:= false;
  500. chauffe_enable:= false;
  501. brassage:= false;
  502. rincage:= false;
  503. nb_rincage_max:= 4;
  504. vidange:= false;
  505. essorage:= false;
  506. defoulage:= false;
  507. sens_enable:= false;
  508. a_choisir:= true;
  509. RAZ_tempos;
  510. affi_requis:= false;
  511. // F_purge:= 30;
  512. relais1_off;
  513. relais2_off;
  514. EV2_off;
  515. Pompe_off;
  516. OCR2:= 140; // [10..162] retard a la commutation du triac alimentant le moteur (162 = pas de tension)
  517. compteur1:= 0;
  518. Temperat_max:= 20; // en degres C
  519. end;
  520.  
  521.  
  522. procedure eteint_toutes_LED;
  523. begin
  524. portA:= portA or %00001000; // RAZ des deux CD4017 (eteint tout because les Q0 ne sont pas cbles)
  525. udelay(1);
  526. portA:= portA and %11110111;
  527. udelay(1);
  528. end;
  529.  
  530.  
  531. procedure allume_LED(num : byte); // n in [0..17]
  532. var
  533. n : byte;
  534. begin
  535. portA:= portA or %00001000; // RAZ des deux CD4017 (eteint tout because les Q0 ne sont pas cbles)
  536. udelay(1);
  537. portA:= portA and %11110111;
  538. udelay(1);
  539. inc(num);
  540.  
  541. if num in [1..18] then
  542. if num < 10 then
  543. for n:= 1 to num do
  544. portA:= portA or %00010000; // CLK du premier CD4017
  545. udelay(1);
  546. portA:= portA and %11101111;
  547. udelay(1);
  548. endfor;
  549. else
  550. for n:= 10 to num do
  551. portA:= portA or %00100000; // CLK du second CD4017
  552. udelay(1);
  553. portA:= portA and %11011111;
  554. udelay(1);
  555. endfor;
  556. endif;
  557. endif;
  558. end;
  559.  
  560.  
  561. procedure STOP(str1 : string[20]);
  562. begin
  563. init_variables; // stop de tous les organes
  564. portA:= portA and %10111111; // eteint LED essorage
  565. allume_LED(16);
  566. LCDclr;
  567. LCDxy(0, 0); Write(LCDout, 'STOP logigiel ');
  568. LCDxy(0, 1); Write(LCDout, str1);
  569. LCDxy(0, 1); Write(LCDout, 'Appuyez bouton rouge');
  570. mdelay(1000);
  571. repeat until (PinD and %00000010) = 0; // attend appui sur bouton rouge avant de reseter
  572. system_reset;
  573. end;
  574.  
  575.  
  576. procedure detection_bouton_ROUGE; // ARRET et RESET du programme
  577. begin
  578. //stk1:= GetStackFree; if stk1 < stk1_min then stk1_min:= stk1; endif;
  579. //fram_free:= GetFrameFree; if fram_free < fram_free_min then fram_free_min:= fram_free; endif;
  580.  
  581. if (PinD and %00000010) = 0 then
  582. STOP('BT R');
  583. endif;
  584. end;
  585.  
  586.  
  587. procedure detection_bouton_VERT; // ABREGE le lavage ou le rincage en cours (passe au numero suivant=vidange)
  588. begin
  589. if (PinD and %00000001) = 0 then
  590. vert:= true;
  591. LCDclr;
  592. LCDxy(10, 1);
  593. Write(LCDout, 'NEXT !');
  594. mdelay(500);
  595. LCDclr;
  596. else
  597. vert:= false;
  598. endif;
  599. end;
  600.  
  601. (*
  602. procedure ACQUI_vitessse;
  603. begin
  604. //Frequencemetre - acquisition de la vitesse du moteur
  605.   if SemaStat(FreqCountSema) <> 0 then
  606.   Freq:= GetFreqCounter;
  607.   endif;
  608. end;
  609. *)
  610.  
  611. procedure ACQUI_vitessse;
  612. begin
  613. //Periodemetre - acquisition de la vitesse du moteur
  614. Periode:= GetTimeCounter;
  615. end;
  616.  
  617.  
  618.  
  619. procedure TEMPO_s(nb_secondes : longword);
  620. // boucle de tempo qui ne bloque pas l'arret d'urgence...
  621. begin
  622. disableInts;
  623. RTCTimer_Load(1, nb_secondes); // canal1, 3secondes
  624. enableInts;
  625.  
  626. RTCTimer_Start(1); // start RTCTimer canal 1
  627. timeout1:= false; // sera mis a true par l'INT RTCTimer
  628. repeat
  629. if (PinD and %00000010) = 0 then // detection bouton rouge
  630. STOP('Bt_R'); // reset le programme
  631. endif;
  632. detection_bouton_vert;
  633. until timeout1 or vert;
  634. vert:= false;
  635. end;
  636.  
  637.  
  638. procedure acqui_analogique;
  639. // lit la position d'un potentiometre a resistances CMS discretes (63k au total)
  640. begin
  641. // LCDclr;
  642.  
  643. acqui_ADC:= GetADC; // resolution 10bits
  644.  
  645. case acqui_ADC of
  646. 859..865 : pos_bt:= 0; // 860
  647. |
  648. 854..858 : pos_bt:= 1; // 856
  649. |
  650. 848..853 : pos_bt:= 2; // 850
  651. |
  652. 842..847 : pos_bt:= 3; // 844
  653. |
  654. 836..841 : pos_bt:= 4; // 838
  655. |
  656. 827..835 : pos_bt:= 5; // 830
  657. |
  658. 816..826 : pos_bt:= 6; // 822
  659. |
  660. 806..815 : pos_bt:= 7; // 811
  661. |
  662. 791..805 : pos_bt:= 8; // 799
  663. |
  664. 776..790 : pos_bt:= 9; // 785
  665. |
  666. 756..775 : pos_bt:= 10; // 768
  667. |
  668. 736..755 : pos_bt:= 11; // 749
  669. |
  670. 711..735 : pos_bt:= 12; // 724
  671. |
  672. 671..710 : pos_bt:= 13; // 693
  673. |
  674. 631..670 : pos_bt:= 14; // 653
  675. |
  676. 551..630 : pos_bt:= 15; // 603
  677. |
  678. 501..550 : pos_bt:= 16; // 537
  679. |
  680. 400..500 : pos_bt:= 17; // 445
  681. |
  682. 250..350 : pos_bt:= 18; // 310
  683. |
  684. 80..100 : pos_bt:= 19; // 92
  685. |
  686. endcase;
  687.  
  688.  
  689. // LCDxy(0, 1);
  690. // Write(LCDout, ByteToStr(n : 3));
  691.  
  692. end;
  693.  
  694.  
  695. procedure regulation_TEMPERATURE;
  696. // allume le chauffage si la temperature est trop basse sinin l'eteint
  697. var
  698. T : float;
  699. t1 : integer;
  700. begin
  701. //mesure de la temperature
  702. acqui_ADC:= GetADC;
  703. acqui_ADC:= acqui_ADC shr 2; // 8 bits au lieu de 10 de resolution
  704. T:= (3500 / float(acqui_ADC)) - 11; // voir feuille de calcul Ooo
  705.  
  706. LCDxy(8, 3);
  707. if (T > 0) and (T < 100) then
  708. t1:= round(T);
  709. Write(LCDout, 'T=' + IntToStr(t1 : 2) + ' ');
  710.  
  711. if (T < (Temperat_max - 5) ) and not(chauffage) then
  712. relais1_off;
  713. relais2_off;
  714. chauffage_ON;
  715. elsif (T > Temperat_max) and chauffage then
  716. Chauffage_OFF;
  717. endif;
  718. endif;
  719. end;
  720.  
  721.  
  722. procedure Affiche_temps(nb_secondes : word);
  723. var
  724. h, mn, sec : byte;
  725. R1 : word;
  726. signe : char;
  727. begin
  728. h : = byte(nb_secondes div 3600);
  729. R1 : = nb_secondes mod 3600;
  730. mn : = byte(R1 div 60);
  731. sec : = byte(R1 mod 60);
  732. LCDxy(13, 0);
  733. LCDclrEOL;
  734. Write(LCDout, ByteToStr(mn : 2 : '0') + ':' + ByteToStr(sec : 2 : '0'));
  735. end;
  736.  
  737.  
  738. procedure change_SENS;
  739. begin
  740. //stk1:= GetStackFree; if stk1 < stk1_min then stk1_min:= stk1; endif;
  741. //fram_free:= GetFrameFree; if fram_free < fram_free_min then fram_free_min:= fram_free; endif;
  742. vitesse_mini; // pour ralentir
  743. stop_imps:= true;
  744. tempo_s(1);
  745. if relais1 and not relais2 then
  746. relais1_off;
  747. tempo_s(1);
  748. if chauffage then tempo_s(19); endif; // ARRET
  749. relais2_on;
  750. elsif relais2 and not(relais1) then
  751. relais2_off;
  752. tempo_s(1);
  753. if chauffage then tempo_s(19); endif; // ARRET
  754. relais1_ON;
  755. elsif not(relais1) and not(relais2) then // si aucun
  756. relais1_ON;
  757. elsif relais1 and relais2 then // si les deux
  758. relais2_off;
  759. endif;
  760.  
  761. tempo_s(tps_pause);
  762. vitesse_mini; // pour repartir lentement
  763.  
  764. TimeOUT_sens:= false;
  765. temps_ch_sens:= 0;
  766. end;
  767.  
  768.  
  769. procedure AFFICHAGES; // permsise toutes les secondes par le flag affi_requis.
  770. begin
  771. affi_requis:= false;
  772. if lavage then
  773. Affiche_temps(tps_lavage_max - temps_lavage);
  774. if chauffe_enable then
  775. regulation_temperature; // comporte un affichage donc ne pas deplacer dans 1 boucle rapide
  776. endif;
  777. endif;
  778.  
  779. if chauffage then
  780. LCDxy(13, 3);
  781. Write(LCDout, 'CH');
  782. else
  783. LCDxy(13, 3);
  784. Write(LCDout, ' ');
  785. endif;
  786.  
  787. LCDxy(2, 3);
  788. Write(LCDout, TXTniv);
  789.  
  790. //------------------------------------------------------------------------------
  791. if rincage then
  792. Affiche_temps(tps_rincage_max - temps_rincage);
  793. endif;
  794. // stk1:= GetStackFree;
  795. //fram_free:= GetFrameFree;
  796. // Affiche_STACK_free;
  797.  
  798. //------------------------------------------------------------------------------
  799. {
  800.   if temps_pause < 100 then inc(temps_pause); endif; // ne reboucle pas
  801.   if temps_pause = 2 then
  802.   vitesse_mini;
  803.   pause1:= false;
  804.   endif;
  805.   endif;
  806. }
  807. //------------------------------------------------------------------------------
  808. if defoulage then
  809. Affiche_temps(tps_deffou_max - temps_defoul);
  810. endif;
  811. //------------------------------------------------------------------------------
  812. if essorage then
  813. Affiche_temps(tps_essr_max - temps_essorage);
  814. endif;
  815.  
  816. if TimeOUT_sens then
  817. TimeOUT_sens:= false;
  818. change_sens;
  819. endif;
  820. end;
  821.  
  822.  
  823. procedure remplissage_NIV1(tps_plus : longword); // par EV2
  824. begin
  825. remplissage:= true;
  826. LCDxy(3, 0);
  827. LCDclrEOL;
  828. Write(LCDout, 'EAU');
  829.  
  830. vitesse_mini;
  831. stop_imps:= true;
  832. sens_enable:= false;
  833. relais1_off;
  834. relais2_off;
  835. EV2_on;
  836.  
  837. repeat
  838. detection_bouton_ROUGE;
  839. detection_bouton_vert;
  840. detection_niveau_eau;
  841.  
  842. if affi_requis then // 1 fois par seconde
  843. AFFICHAGES;
  844. endif;
  845. LCDxy(2, 3);
  846. Write(LCDout, TXTniv);
  847. until NIV1 or NIV2 or vert; // oui, NIV2 convient bien entendu.
  848. vert:= false;
  849. if octet_IR = 12 then
  850. STOP('3');
  851. endif;
  852. octet_IR:= 255;
  853. LCDxy(0, 2);
  854. LCDclrEOL;
  855. Write(LCDout, 'Remplissage +'); // un peu plus, pour eviter d'en reprendre un verre 10 fois de suite
  856. tempo_s(tps_plus);
  857.  
  858. EV2_off;
  859. LCDclrLine(2);
  860. remplissage:= false;
  861. end;
  862.  
  863.  
  864. procedure RINCER(num_rincage : byte);
  865. begin
  866.  
  867. rincage:= true;
  868. LCDxy(3, 0);
  869. LCDclrEOL;
  870. Write(LCDout, 'RINCAGE' + ByteToStr(num_rincage : 1));
  871.  
  872. stop_imps:= true;
  873. vitesse_mini;
  874. chauffe_enable:= false;
  875. Chauffage_OFF;
  876. periode_ch_sens:= 10;
  877. sens_enable:= true;
  878. stop_imps:= true;
  879. vitesse_mini; // pour partir lentement
  880. tempo_s(1);
  881. relais2_off;
  882. tempo_s(1);
  883. relais1_ON;
  884. tempo_s(1);
  885.  
  886. stop_imps:= false;
  887. temps_rincage:= 0;
  888.  
  889. //---------------------------- boucle rincage ----------------------------------
  890. LCDclrLine(2);
  891. LCDxy(0, 2);
  892. Write(LCDout, 'boucle rincage');
  893.  
  894. timeOUT_rincage:= false;
  895. repeat
  896. detection_bouton_ROUGE;
  897. detection_bouton_vert;
  898. detection_niveau_eau;
  899. if not NIV1 then
  900. remplissage_NIV1(30);
  901. endif; // si le niveau baisse, on complete;
  902.  
  903. stop_imps:= false;
  904. Periode:= GetTimeCounter; // 50Hz -> P=2000
  905. if ((Periode > P_cons_lav + 10) or (Periode = 0)) and (OCR2_real > OCRmin_LAV) then // asservissement de la vitesse
  906. OCR2_real := OCR2_real - 0.01; //accelere
  907. endif;
  908. if (Periode < P_cons_lav - 10 ) and (Periode <> 0) and (OCR2_real < OCRmax_LAV) then
  909. OCR2_real := OCR2_real + 0.01; //ralentit
  910. endif;
  911. OCR2:= round(OCR2_real);
  912. udelay(50);
  913.  
  914. if affi_requis and not vert then
  915. AFFICHAGES;
  916. endif;
  917.  
  918. until timeOUT_rincage or vert;
  919. vert:= false;
  920. //------------------------------------------------------------------------------
  921. vitesse_mini;
  922. stop_imps:= true;
  923.  
  924. sens_enable:= false;
  925. stop_imps:= true;
  926. vitesse_mini;
  927. LCDxy(3, 0);
  928. LCDclrEOL;
  929. Write(LCDout, 'fin rincage');
  930.  
  931. tempo_s(1);
  932. relais1_off;
  933. relais2_off;
  934. tempo_s(1);
  935. rincage:= false;
  936. LCDclr;
  937. end;
  938.  
  939.  
  940. procedure PURGER; // mini essorage a la fin de la vidange afin de purger l'eau du linge
  941. begin
  942. // offset_OCR2:= 0;
  943. Chauffage_OFF;
  944. EV2_off;
  945. LCDxy(3, 0);
  946. LCDclrEOL;
  947. Write(LCDout, 'PURGE');
  948.  
  949. stop_imps:= false;
  950. pompe_on;
  951.  
  952. vitesse_mini;
  953. stop_imps:= true;
  954.  
  955. tempo_s(1);
  956. relais2_off;
  957. tempo_s(1);
  958. relais1_ON;
  959. tempo_s(1);
  960. sens_enable:= false;
  961. stop_imps:= false; // demarrre le moteur
  962.  
  963. temps_purge:= 0;
  964. purge:= true;
  965.  
  966. //------------------------- boucle "esso-purge" --------------------------------
  967. LCDclrLine(2);
  968. LCDxy(0, 2);
  969. Write(LCDout, 'boucle purge');
  970.  
  971. timeOUT_purge:= false;
  972. repeat
  973. detection_bouton_ROUGE;
  974. detection_bouton_vert;
  975. stop_imps:= false;
  976.  
  977. Periode:= GetTimeCounter; // 50Hz -> P=2000
  978. if ((Periode > P_cons_purge + 10) or (Periode = 0)) and (OCR2_real > OCRmin_LAV) then // asservissement de la vitesse
  979. OCR2_real := OCR2_real - 0.01; //accelere
  980. udelay(200);
  981.  
  982. endif;
  983. if (Periode < P_cons_purge - 10 ) and (Periode <> 0) and (OCR2_real < OCRmax_LAV) then
  984. OCR2_real := OCR2_real + 0.01; //ralentit
  985. endif;
  986. OCR2:= round(OCR2_real);
  987. udelay(20);
  988.  
  989. if affi_requis then
  990. AFFICHAGES;
  991. endif;
  992.  
  993. until timeOUT_purge or vert;
  994. //------------------------------------------------------------------------------
  995.  
  996. stop_imps:= true;
  997. vitesse_mini;
  998.  
  999. tempo_s(1);
  1000. relais1_off;
  1001. relais2_off;
  1002. tempo_s(1);
  1003.  
  1004. tempo_s(10); // 10s de vidange supplementaires a la fin
  1005. Pompe_off;
  1006. vidange:= false;
  1007. defoulage:= false;
  1008. stop_imps:= true;
  1009. purge:= false;
  1010. LCDclr;
  1011. end;
  1012.  
  1013.  
  1014. procedure TEST_asservissement;
  1015. var
  1016. P_consigne : word;
  1017. begin
  1018. LCDclr;
  1019. LCDxy(5, 1);
  1020. LCDclrEOL;
  1021. Write(LCDout, ' TEST vitesse');
  1022. stop_imps:= true;
  1023. tempo_s(1);
  1024. relais2_off;
  1025. relais1_ON;
  1026. tempo_s(1);
  1027.  
  1028. sens_enable:= false;
  1029. stop_imps:= false;
  1030. P_consigne:= 2000;
  1031.  
  1032. loop
  1033. detection_bouton_ROUGE;
  1034. acqui_analogique;
  1035. P_consigne:= 1000 + 100 * word(pos_bt);
  1036.  
  1037. Periode:= GetTimeCounter; // 50Hz -> P=2000
  1038. if ((Periode > P_consigne + 10) or (Periode = 0)) and (OCR2_real > OCRmin_LAV) then // asservissement de la vitesse
  1039. OCR2_real := OCR2_real - 0.01; //accelere
  1040. endif;
  1041. if (Periode < P_consigne - 10 ) and (Periode <> 0) and (OCR2_real < OCRmax_LAV) then
  1042. OCR2_real := OCR2_real + 0.01; //ralentit
  1043. endif;
  1044. OCR2:= round(OCR2_real);
  1045. udelay(50);
  1046. endloop;
  1047. end;
  1048.  
  1049.  
  1050. procedure ESSORER;
  1051. begin
  1052. portA:= portA or %01000000; // allume LED essorage
  1053. LCDclr;
  1054. accelere:= false;
  1055. // offset_OCR2:= 0;
  1056. Chauffage_OFF;
  1057. EV2_off;
  1058. LCDxy(3, 0);
  1059. LCDclrEOL;
  1060. Write(LCDout, 'ESSORAGE');
  1061.  
  1062. stop_imps:= false;
  1063. pompe_on;
  1064.  
  1065. stop_imps:= true;
  1066. tempo_s(1);
  1067. relais2_off;
  1068. tempo_s(1);
  1069. relais1_ON;
  1070. tempo_s(1);
  1071.  
  1072. sens_enable:= false;
  1073. stop_imps:= false;
  1074. if tps_essr_max > 5*60 then tps_essr_max:= 5*60; endif; // securite
  1075. temps_essorage:= 0;
  1076. essorage:= true;
  1077.  
  1078. LCDclrLine(2);
  1079. LCDxy(0, 2);
  1080. Write(LCDout, 'boucle essorage');
  1081. // mdelay(1000);
  1082.  
  1083. timeOUT_ess:= false;
  1084. accelere:= true; // add_F_ess sera incremente chaque seconde par RTCTickSecond
  1085.  
  1086. // baseOCR2:= 130;
  1087. // offset_OCR2:= 0;
  1088.  
  1089. vitesse_mini;
  1090. P_cons_ess:= 2000; // vitesse tres lente au depart pour defouler
  1091.  
  1092. //------------------------- boucle essorage ------------------------------------
  1093. repeat
  1094. detection_bouton_ROUGE;
  1095. detection_bouton_vert;
  1096.  
  1097. if vert then
  1098. vert:= false;
  1099. stop_imps:= true;
  1100. tempo_s(12); // pour laisser le temps au tambour de ralentir
  1101. OCR2_real:= 130;
  1102. P_cons_ess:= 2000;
  1103. stop_imps:= false;
  1104. endif;
  1105.  
  1106. stop_imps:= false;
  1107.  
  1108. Periode:= GetTimeCounter; // 50Hz -> P=2000
  1109. if ((Periode > P_cons_ess + 10) or (Periode = 0)) and (OCR2_real > OCRmin_ESS) then // asservissement de la vitesse
  1110. OCR2_real := OCR2_real - 0.01; //accelere
  1111. endif;
  1112. if (Periode < P_cons_ess - 10 ) and (Periode <> 0) and (OCR2_real < OCRmax_ESS) then
  1113. OCR2_real := OCR2_real + 0.01; //ralentit
  1114. endif;
  1115. OCR2:= round(OCR2_real);
  1116. udelay(20);
  1117.  
  1118. if affi_requis then
  1119. AFFICHAGES;
  1120. endif;
  1121.  
  1122. until timeOUT_ess;
  1123. vert:= false;
  1124. //------------------------------------------------------------------------------
  1125. portA:= portA and %10111111; // eteint LED essorage
  1126. LCDclr;
  1127. Write(LCDout, 'FIN ESSORAGE');
  1128.  
  1129. stop_imps:= true;
  1130. vitesse_mini;
  1131.  
  1132. tempo_s(1);
  1133. relais1_off;
  1134. tempo_s(1);
  1135. relais2_off;
  1136. tempo_s(1);
  1137.  
  1138. tempo_s(15); // 15s de vidange supplementaires a la fin
  1139. Pompe_off;
  1140.  
  1141. vidange:= false;
  1142. defoulage:= false;
  1143. essorage:= false;
  1144.  
  1145. LCDxy(0, 1);
  1146. Write(LCDout, 'Lessive terminee');
  1147.  
  1148. allume_LED(16);
  1149. while true do
  1150. detection_bouton_ROUGE;
  1151. endwhile;
  1152. end;
  1153.  
  1154.  
  1155. procedure VIDANGER;
  1156. begin
  1157. LCDxy(3, 0);
  1158. LCDclrEOL;
  1159. Write(LCDout, 'VIDANGE');
  1160.  
  1161. chauffe_enable:= false;
  1162. Chauffage_OFF;
  1163. vidange:= true;
  1164. LCDclrLine(2);
  1165. LCDxy(0, 2);
  1166. Write(LCDout, 'Pompe en marche');
  1167.  
  1168. pompe_on;
  1169. affi_requis:= false;
  1170. repeat
  1171. detection_bouton_ROUGE;
  1172. detection_bouton_vert;
  1173. detection_niveau_eau;
  1174.  
  1175. if affi_requis then // 1 fois par seconde
  1176. affi_requis:= false;
  1177. LCDxy(2, 3);
  1178. Write(LCDout, TXTniv);
  1179. endif;
  1180.  
  1181. until not(NIV1 or NIV2) or vert;
  1182. vert:= false;
  1183.  
  1184. //octet_IR:= 255;
  1185. // a partir de cet instant il faut encore au minimum 16s pour vider la cuve
  1186. // On fait donc tourner la pompe 20s supplementaires
  1187. LCDxy(3, 0);
  1188. LCDclrEOL;
  1189. Write(LCDout, 'VIDANGE +');
  1190. LCDxy(2, 3);
  1191. Write(LCDout, TXTniv);
  1192. tempo_s(20);
  1193.  
  1194. Pompe_off;
  1195. LCDclrLine(2);
  1196. vidange:= false;
  1197. end;
  1198.  
  1199.  
  1200. procedure test_IR;
  1201. var
  1202. chr1 : char;
  1203. begin
  1204. LCDclr;
  1205. LCDxy(0, 0);
  1206. Write(LCDout, 'Lave Linge v: ' + version );
  1207. LCDxy(0, 1);
  1208. Write(LCDout, 'Test IR' );
  1209. LCDxy(0, 2);
  1210. Write(LCDout, 'ok ou 0 pour sortir' );
  1211. repeat
  1212. detection_bouton_ROUGE;
  1213. interroge_IR;
  1214. if nouveau = true then
  1215. chr1:= '*';
  1216. else chr1:= ' ';
  1217. endif;
  1218. if octet_IR <> 255 then
  1219. LCDxy(0, 3);
  1220. Write(LCDout, ByteToStr(octet_IR : 3 : ' ') + ' ' + chr1);
  1221. mdelay(200);
  1222. endif;
  1223. until (octet_IR = 0) or (octet_IR = 23);
  1224. STOP('4'); // reset
  1225. end;
  1226.  
  1227.  
  1228. procedure LAVER;
  1229. begin
  1230. lavage:= true;
  1231. if tps_lavage_max > 30*60 then tps_lavage_max:= 30*60; endif; // 30mn max (securite)
  1232. if Temperat_max > 80 then Temperat_max:= 80; endif; // securite
  1233. LCDxy(3, 0);
  1234. LCDclrEOL;
  1235. Write(LCDout, 'LAVAGE');
  1236. LCDclrLine(1);
  1237. LCDxy(7, 1);
  1238. Write(LCDout, Nom_prg);
  1239. sens_enable:= true;
  1240. stop_imps:= true;
  1241. tempo_s(1);
  1242. relais2_off;
  1243. tempo_s(1);
  1244. relais1_ON;
  1245. tempo_s(1);
  1246. vitesse_mini; // pour partir lentement
  1247. temps_ch_sens:= 0;
  1248. temps_lavage:= 0; // le temps est incremente par la procedure RTCtickMinute
  1249.  
  1250. //----------------------------- BOUCLE LAVAGE ----------------------------------
  1251. LCDclrLine(2);
  1252. LCDxy(0, 2);
  1253. Write(LCDout, 'boucle lavage');
  1254.  
  1255. timeOUT_lavage:= false;
  1256. repeat
  1257. detection_bouton_ROUGE;
  1258. detection_bouton_vert;
  1259. detection_niveau_eau;
  1260.  
  1261. if not NIV1 then
  1262. remplissage_NIV1(30);
  1263. endif; // si le niveau baisse, on complete;
  1264.  
  1265. if (NIV1 or NIV2) and (prog1 <> froid) and (temps_lavage > (5*60) ) and (temps_lavage < (15*60) ) then
  1266. //on ne chaufffe pas avant 5 minutes (prelavage a froid)
  1267. //ni apres 15mn de tournage (because on arrete le moteur pendant le chauffage et ca risquerait de trop
  1268. // augmenter la duree de la lesssive)
  1269. //(la temperature descendra alors lentement... je prefere ca a rechauffer a plusieurs reprises)
  1270. // pouquoi ne pas tourner en chauffant? because trop de consomation des 2 bobines de relais sur l'alim...
  1271. chauffe_enable:= true; // CHAUFFAGE
  1272. else
  1273. chauffe_enable:= false;
  1274. Chauffage_OFF;
  1275. endif;
  1276.  
  1277. stop_imps:= false;
  1278. // stop_imps:= chauffage; // le moteur ne peut tourner qu'en l'absence de chauffage;
  1279. // sens_enable:= not(chauffage);
  1280.  
  1281. Periode:= GetTimeCounter; // 50Hz -> P=2000
  1282. if ((Periode > P_cons_lav + 10) or (Periode = 0)) and (OCR2_real > OCRmin_LAV) then // asservissement de la vitesse
  1283. OCR2_real := OCR2_real - 0.01; //accelere
  1284. endif;
  1285. if (Periode < P_cons_lav - 10 ) and (Periode <> 0) and (OCR2_real < OCRmax_LAV) then
  1286. OCR2_real := OCR2_real + 0.02; //ralentit //0.01
  1287. endif;
  1288. OCR2:= round(OCR2_real);
  1289. udelay(25); // 50
  1290.  
  1291. if affi_requis then
  1292. AFFICHAGES;
  1293. endif;
  1294.  
  1295. until timeOUT_lavage or vert;
  1296. vert:= false;
  1297. //-------------------------------- FIN LAVAGE ----------------------------------
  1298.  
  1299. Chauffage_OFF;
  1300. chauffe_enable:= false;
  1301.  
  1302. LCDxy(3, 0);
  1303. LCDclrEOL;
  1304. Write(LCDout, 'fin lavage');
  1305.  
  1306. vitesse_mini;
  1307. sens_enable:= false;
  1308. stop_imps:= true;
  1309. vitesse_mini;
  1310. tempo_s(1);
  1311. relais1_off;
  1312. relais2_off;
  1313. lavage:= false;
  1314. LCDclr;
  1315. end;
  1316.  
  1317.  
  1318. procedure choix_programme;
  1319. begin
  1320. disableInts;
  1321. LCDclr;
  1322. LCDxy(0, 0); Write(LCDout, '==== PROGRAMME: ====' );
  1323. LCDxy(0, 1); Write(LCDout, '1:COULEUR 2:BLANC ' );
  1324. LCDxy(0, 2); Write(LCDout, '3:LAINE 4:FROID ' );
  1325. LCDxy(0, 3); Write(LCDout, '5:RAPIDE' );
  1326. repeat
  1327. detection_bouton_ROUGE;
  1328. interroge_IR;
  1329. until octet_IR in [1..6, 12];
  1330.  
  1331. case octet_IR of
  1332. 1 : prog1:= couleur;
  1333. Nom_prg:= 'Couleur';
  1334. Temperat_max:= 40;
  1335. tps_lavage_max:= 20*60;
  1336. tps_pause:= 1;
  1337. nb_rincage_max:= 4;
  1338. tps_essr_max:= 3*60;
  1339. tps_deffou_max:= 15;
  1340. |
  1341. 2 : prog1:= blanc;
  1342. Nom_prg:= 'Blanc';
  1343. Temperat_max:= 60;
  1344. tps_lavage_max:= 25*60;
  1345. tps_pause:= 1;
  1346. nb_rincage_max:= 4;
  1347. tps_essr_max:= 3*60;
  1348. tps_deffou_max:= 15;
  1349. |
  1350. 3 : prog1:= laine;
  1351. Nom_prg:= 'Laine';
  1352. Temperat_max:= 30;
  1353. tps_lavage_max:= 15*60;
  1354. tps_pause:= 2;
  1355. nb_rincage_max:= 4;
  1356. tps_essr_max:= 2*60;
  1357. tps_deffou_max:= 20;
  1358. |
  1359. 4 : prog1:= froid;
  1360. Nom_prg:= 'A froid';
  1361. Temperat_max:= 0;
  1362. tps_lavage_max:= 20*60;
  1363. tps_pause:= 1;
  1364. nb_rincage_max:= 4;
  1365. tps_essr_max:= 3*60;
  1366. tps_deffou_max:= 15;
  1367. |
  1368. 5 : prog1:= rapide;
  1369. Nom_prg:= 'Rapide';
  1370. Temperat_max:= 30;
  1371. tps_lavage_max:= 10*60;
  1372. tps_pause:= 1;
  1373. nb_rincage_max:= 2;
  1374. tps_essr_max:= 2*60;
  1375. tps_deffou_max:= 15;
  1376. |
  1377.  
  1378. 12 : STOP('8');
  1379. |
  1380. endcase;
  1381. LCDclr;
  1382. Write(LCDout, Nom_prg + ' ' + IntToStr(round(Temperat_max)) + 'deg ' + IntToStr(tps_lavage_max div 60) + 'mn');
  1383. LCDxy(0, 1);
  1384. Write(LCDout, '5 prem. mn = froid');
  1385. LCDxy(0, 2);
  1386. Write(LCDout, ByteToStr(nb_rincage_max) + ' rincages ');
  1387. tempo_s(5);
  1388. LCDclr;
  1389. temps_total:= 0;
  1390. enableInts;
  1391. end;
  1392.  
  1393.  
  1394. procedure numero_15; // ESSORAGE
  1395. begin
  1396. numero:= 15;
  1397. allume_LED(numero);
  1398. LCDxy(0, 0);
  1399. Write(LCDout, ByteToStr(numero : 2));
  1400.  
  1401. vidanger;
  1402. purger;
  1403. LCDclr;
  1404. LCDxy(0, 0); Write(LCDout, '5 pour essorer' );
  1405. LCDxy(0, 1); Write(LCDout, 'bouton rouge = stop' );
  1406. repeat
  1407. detection_bouton_ROUGE;
  1408. interroge_IR;
  1409. until (octet_IR = 5);
  1410.  
  1411. essorer;
  1412. LCDclr;
  1413. STOP('5');
  1414. end;
  1415.  
  1416.  
  1417. procedure numero_14; // RINCAGE 4 facultatif
  1418. begin
  1419. numero:= 14;
  1420. allume_LED(numero);
  1421. LCDxy(0, 0);
  1422. Write(LCDout, ByteToStr(numero : 2));
  1423. rincer(4);
  1424. num_requis:= 15;
  1425. end;
  1426.  
  1427.  
  1428. procedure numero_13;
  1429. begin
  1430. numero:= 13;
  1431. allume_LED(numero);
  1432. LCDxy(0, 0);
  1433. Write(LCDout, ByteToStr(numero : 2));
  1434. if nb_rincage_max > 3 then
  1435. remplissage_NIV1(45);
  1436. num_requis:= 14;
  1437. else
  1438. num_requis:= 15; // vers essorage
  1439. endif;
  1440. end;
  1441.  
  1442.  
  1443. procedure numero_12;
  1444. begin
  1445. numero:= 12;
  1446. allume_LED(numero);
  1447. LCDxy(0, 0);
  1448. Write(LCDout, ByteToStr(numero : 2));
  1449. vidanger;
  1450. purger;
  1451. num_requis:= 13;
  1452. end;
  1453.  
  1454.  
  1455. procedure numero_11; // RINCAGE 3 facultatif
  1456. begin
  1457. numero:= 11;
  1458. allume_LED(numero);
  1459. LCDxy(0, 0);
  1460. Write(LCDout, ByteToStr(numero : 2));
  1461. rincer(3);
  1462. num_requis:= 12;
  1463. end;
  1464.  
  1465.  
  1466. procedure numero_10;
  1467. begin
  1468. numero:= 10;
  1469. allume_LED(numero);
  1470. LCDxy(0, 0);
  1471. Write(LCDout, ByteToStr(numero : 2));
  1472.  
  1473. if nb_rincage_max > 2 then
  1474. remplissage_NIV1(45);
  1475. num_requis:= 11;
  1476. else
  1477. num_requis:= 15; // vers essorage
  1478. endif;
  1479. end;
  1480.  
  1481.  
  1482. procedure numero_9;
  1483. begin
  1484. numero:= 9;
  1485. allume_LED(numero);
  1486. LCDxy(0, 0);
  1487. Write(LCDout, ByteToStr(numero : 2));
  1488.  
  1489. vidanger;
  1490. purger;
  1491. num_requis:= 10;
  1492. end;
  1493.  
  1494.  
  1495. procedure numero_8; // RINCAGE 2
  1496. begin
  1497. numero:= 8;
  1498. allume_LED(numero);
  1499. LCDxy(0, 0);
  1500. Write(LCDout, ByteToStr(numero : 2));
  1501.  
  1502. rincer(2);
  1503. num_requis:= 9;
  1504. end;
  1505.  
  1506.  
  1507. procedure numero_7;
  1508. begin
  1509. numero:= 7;
  1510. allume_LED(numero);
  1511. LCDxy(0, 0);
  1512. Write(LCDout, ByteToStr(numero : 2));
  1513.  
  1514. remplissage_NIV1(47);
  1515. num_requis:= 8;
  1516. end;
  1517.  
  1518.  
  1519. procedure numero_6;
  1520. //bonjour chez vous
  1521. begin
  1522. numero:= 6;
  1523. allume_LED(numero);
  1524. LCDxy(0, 0);
  1525. Write(LCDout, ByteToStr(numero : 2));
  1526.  
  1527. vidanger;
  1528. purger;
  1529. num_requis:= 7;
  1530. end;
  1531.  
  1532.  
  1533. procedure numero_5; // RINCAGE 1
  1534. begin
  1535. numero:= 5;
  1536. allume_LED(numero);
  1537. LCDxy(0, 0);
  1538. Write(LCDout, ByteToStr(numero : 2));
  1539.  
  1540. rincer(1);
  1541. num_requis:= 6;
  1542. end;
  1543.  
  1544.  
  1545. procedure numero_4;
  1546. begin
  1547. numero:= 4;
  1548. allume_LED(numero);
  1549. LCDxy(0, 0);
  1550. Write(LCDout, ByteToStr(numero : 2));
  1551.  
  1552. remplissage_NIV1(45);
  1553. num_requis:= 5;
  1554. end;
  1555.  
  1556.  
  1557. procedure numero_3;
  1558. begin
  1559. numero:= 3;
  1560. allume_LED(numero);
  1561. LCDxy(0, 0);
  1562. Write(LCDout, ByteToStr(numero : 2));
  1563.  
  1564. vidanger;
  1565. purger;
  1566. num_requis:= 4;
  1567. end;
  1568.  
  1569.  
  1570. procedure numero_2;
  1571. begin
  1572. if a_choisir then choix_programme; endif;
  1573. numero:= 2;
  1574. allume_LED(numero);
  1575. LCDxy(0, 0);
  1576. Write(LCDout, ByteToStr(numero : 2));
  1577. laver;
  1578. num_requis:= 3;
  1579. end;
  1580.  
  1581.  
  1582. procedure numero_1;
  1583. begin
  1584. choix_programme;
  1585. a_choisir:= false; // pour ne pas devoir le choisir une 2eme fois au numero_2
  1586. numero:= 1;
  1587. allume_LED(numero);
  1588. LCDxy(0, 0);
  1589. Write(LCDout, ByteToStr(numero : 2));
  1590.  
  1591. // vidanger;
  1592. remplissage_NIV1(30); // niveau haut mais inferieur a NIV2 (qui demande 3mn de remplissage!)
  1593. num_requis:= 2;
  1594. end;
  1595.  
  1596.  
  1597. procedure numero_0;
  1598. begin
  1599. numero:= 0;
  1600. allume_LED(numero);
  1601. LCDxy(0, 0);
  1602. Write(LCDout, ByteToStr(numero : 2));
  1603.  
  1604. STOP('6');
  1605. end;
  1606.  
  1607.  
  1608. procedure RTCtimer(chan : byte); // CallBack from RTCtimer
  1609. begin
  1610. if chan = 1 then
  1611. timeout1:= true;
  1612. endif;
  1613. end;
  1614.  
  1615. {$NOSAVE}
  1616. procedure RTCtickSecond; // CallBack from RTClock
  1617. //var
  1618. // char1 : char;
  1619. begin
  1620. PushAllRegs; // sauvegarde sur la pile et non dans iData en statique
  1621.  
  1622. // portA:= portA xor %00100000; // fait clignoter une LED pour TEST
  1623.  
  1624. if lavage then
  1625. if (temps_lavage < 120*60) and not(chauffage) then // ne boucle pas 120mn= 2h
  1626. inc(temps_lavage);
  1627. if temps_lavage = tps_lavage_max then
  1628. timeOUT_lavage:= true;
  1629. endif;
  1630. endif;
  1631. endif;
  1632. //------------------------------------------------------------------------------
  1633. if rincage then
  1634. if temps_rincage < 120*60 then
  1635. inc(temps_rincage); // ne boucle pas
  1636. if temps_rincage = tps_rincage_max then
  1637. timeOUT_rincage:= true;
  1638. endif;
  1639. endif;
  1640. endif;
  1641. //------------------------------------------------------------------------------
  1642. if essorage then
  1643. if temps_essorage < 120*60 then
  1644. inc(temps_essorage);
  1645. if temps_essorage = tps_essr_max then
  1646. timeOUT_ess:= true;
  1647. endif;
  1648.  
  1649. if (temps_essorage > 10) then // 10s de defoulage
  1650. P_cons_ess:= 10000 div (temps_essorage);
  1651. // ce qui fait accelerer la vitesse lineairement / temps (f=1/T)
  1652. if P_cons_ess < 50 then
  1653. P_cons_ess := 50;
  1654. endif;
  1655. endif;
  1656.  
  1657. {
  1658.   if (temps_essorage >= 90) and (temps_essorage < 110) then
  1659.   P_cons_ess:= 2000; // redefoulage avec le linge presque sec
  1660.   endif;
  1661. }
  1662.  
  1663. {
  1664.   if (temps_essorage >= 110 ) then
  1665.   P_cons_ess:= 50; // grande vitesse, superieure a la frequence de resonnance du tambour
  1666.   endif; // la resonnance du tambour se situe aux environs de 80
  1667. }
  1668.  
  1669.  
  1670. endif; // ne boucle pas
  1671. endif;
  1672. //------------------------------------------------------------------------------
  1673. if purge then
  1674. if temps_purge < 120*60 then
  1675. inc(temps_purge);
  1676. if temps_purge = tps_purge_max then
  1677. timeOUT_purge:= true;
  1678. endif;
  1679. endif; // ne boucle pas
  1680. // inc(offset_OCR2); //pour accelerer petit a petit
  1681. endif;
  1682.  
  1683. //------------------------------------------------------------------------------
  1684. if defoulage then
  1685. if temps_defoul < 120*60 then
  1686. inc(temps_defoul);
  1687. if temps_defoul = tps_deffou_max then
  1688. TimeOUT_defoul:= true;
  1689. endif;
  1690. endif;
  1691. endif;
  1692.  
  1693. //------------------------------------------------------------------------------
  1694. if pompe then inc(temps_pompe); endif;
  1695. if temps_pompe > 5*60 then
  1696. STOP('PB vidange > 5mn');
  1697. endif;
  1698.  
  1699. if EV2 then inc(temps_EV2); endif;
  1700. if temps_EV2 > 5*60 then
  1701. STOP('PB niveau eau');
  1702. endif;
  1703.  
  1704. //------------------------------------------------------------------------------
  1705. inc(temps_ch_sens);
  1706. if temps_ch_sens >= periode_ch_sens then
  1707.  
  1708. if sens_enable then
  1709. TimeOUT_sens:= true; // changement de sens requis
  1710. endif;
  1711. endif;
  1712. //------------------------------------------------------------------------------
  1713. affi_requis:= true; // pas d'affichage directement dans une interruption
  1714. PopAllRegs;
  1715. end;
  1716.  
  1717.  
  1718. procedure RTCtickMinute; // CallBack from RTClock
  1719. begin
  1720. if temps_total < 255 then inc(temps_total); endif;
  1721. end;
  1722.  
  1723.  
  1724. procedure RTCtickHour; // CallBack from RTClock
  1725. begin
  1726. end;
  1727.  
  1728.  
  1729. procedure choix_numero;
  1730. var
  1731. num : byte;
  1732. begin
  1733. disableInts;
  1734. LCDclr;
  1735. LCDxy(0, 0); Write(LCDout, '== CHOIX NUMERO ====' );
  1736. LCDxy(0, 1); Write(LCDout, 'Touches < > ok' );
  1737. num:= 1;
  1738. allume_LED(num);
  1739. LCDxy(0, 3); Write(LCDout, ByteToStr(num) + ' ' + Labels_numeros[num]);
  1740. repeat
  1741. detection_bouton_ROUGE;
  1742. octet_IR:= 255;
  1743.  
  1744. repeat
  1745. detection_bouton_ROUGE;
  1746. interroge_IR;
  1747. until octet_IR in [16, 17, 23];
  1748.  
  1749. case octet_IR of
  1750. 16 : if num < 15 then inc(num); mdelay(20); endif;
  1751. |
  1752. 17 : if num > 1 then dec(num); mdelay(20); endif;
  1753. |
  1754. endcase;
  1755. allume_LED(num);
  1756.  
  1757. LCDclrLine(3);
  1758. LCDxy(0, 3);
  1759. Write(LCDout, ByteToStr(num) + ' ' + Labels_numeros[num]);
  1760.  
  1761. until (octet_IR = 23);
  1762.  
  1763. LCDclr;
  1764. enableInts;
  1765. num_requis:= num;
  1766. if num_requis = 2 then a_choisir:= true; endif;
  1767. end;
  1768.  
  1769.  
  1770.  
  1771. //==============================================================================
  1772. { Main Program }
  1773. {$IDATA}
  1774.  
  1775. begin
  1776. init_variables;
  1777. init_ports;
  1778. allume_LED(0);
  1779. InitINTs;
  1780. ticked:= true;
  1781. Chauffage_OFF;
  1782. LCDclr; { clear display }
  1783. LCDcursor(false, false); { display on, cursor off & no blink }
  1784. Write(LCDout, 'RESET');
  1785. if (MCUCSR and %00001000) <> 0 then
  1786. Write(LCDout, ' WT-Dog');
  1787. while true do
  1788. detection_bouton_ROUGE;
  1789. endwhile;
  1790. endif;
  1791.  
  1792. mdelay(300);
  1793. LCDclr;
  1794. Write(LCDout, 'Lave Linge v: ' + version );
  1795. tempo_s(2);
  1796. // SetFreqCountMode(TFreqBase100kHz); // mode frequencemetre
  1797. SetFreqCountMode(TTimeBase100ms); // mode periodemetre
  1798. num_requis:= 0;
  1799.  
  1800.  
  1801. LCDclr;
  1802. LCDxy(0, 0); Write(LCDout, '1:LAVAGE');
  1803. LCDxy(0, 1); Write(LCDout, '2:Choix Numero');
  1804. LCDxy(0, 2); Write(LCDout, '3:vitesse');
  1805. LCDxy(0, 3); Write(LCDout, '9:Test IR');
  1806. octet_IR:= 255;
  1807. repeat
  1808. detection_bouton_ROUGE;
  1809. interroge_IR;
  1810. until octet_IR in [1, 2, 3, 9, 32, 33]; // attention cette LISTE doit etre exacte
  1811.  
  1812. case octet_IR of
  1813. 1 : numero_1;
  1814. |
  1815. 2 : choix_numero;
  1816. |
  1817. 3 : TEST_asservissement;
  1818. |
  1819. 9 : Test_IR;
  1820. |
  1821. 12 : STOP('9');
  1822. |
  1823. 32 : inc(OCR2); //F_essorage:= F_essorage + 5;
  1824. |
  1825. 33 : dec(OCR2); //F_essorage:= F_essorage - 5;
  1826. |
  1827. else
  1828. LCDclr;
  1829. LCDxy(0, 0);
  1830. Write(LCDout, 'err1 - choix inconnu');
  1831. while true do
  1832. detection_bouton_ROUGE;
  1833. endwhile;
  1834. endcase;
  1835.  
  1836. enableInts; // ne pas remonter cette ligne.
  1837.  
  1838. loop
  1839. case num_requis of
  1840. 1 : numero_1;
  1841. |
  1842. 2 : numero_2;
  1843. |
  1844. 3 : numero_3;
  1845. |
  1846. 4 : numero_4;
  1847. |
  1848. 5 : numero_5;
  1849. |
  1850. 6 : numero_6;
  1851. |
  1852. 7 : numero_7;
  1853. |
  1854. 8 : numero_8;
  1855. |
  1856. 9 : numero_9;
  1857. |
  1858. 10 : numero_10;
  1859. |
  1860. 11 : numero_11;
  1861. |
  1862. 12 : numero_12;
  1863. |
  1864. 13 : numero_13;
  1865. |
  1866. 14 : numero_14;
  1867. |
  1868. 15 : numero_15;
  1869. |
  1870. else
  1871. LCDxy(0, 0);
  1872. Write(LCDout, 'err2 - n requis NC');
  1873. while true do
  1874. detection_bouton_ROUGE;
  1875. endwhile;
  1876. endcase;
  1877.  
  1878. endloop;
  1879.  
  1880.  
  1881.  
  1882. // RTCtimer_Stop(0);
  1883. end lavelinge.
  1884.  
  1885.  
  1886.  
  1887.  
  1888.  

12 Le code source du Firmware en langage C

CODE SOURCE en langage C
  1. /***************************************************************************
  2.  * http://www.silicium628.fr/ *
  3.  * *
  4.  * This program is free software; you can redistribute it and/or modify *
  5.  * it under the terms of the GNU General Public License as published by *
  6.  * the Free Software Foundation; *
  7.  * *
  8.  * This program is distributed in the hope that it will be useful, *
  9.  * but WITHOUT ANY WARRANTY; *
  10.  * See the GNU General Public License for more details. *
  11.  ***************************************************************************/
  12.  
  13. /*=========================================================================================
  14. Lave_Linge
  15.  
  16. par Silicium628 - voir la description de cette réalisation sur mon site
  17. versions: voir plus bas dans la partie "const" - dernière mise à jour 2012-11-02
  18. La version est visible sur l'afficheur au reset du programme
  19. Quel plaisir de programmer un uControleur en PASCAL ! disais-je:-)
  20. Quel plaisir donc, de programmer un uControleur en C ! et sous Linux :-))
  21. ===========================================================================================
  22. PRINCIPE:
  23. PRINCIPE:
  24. --------------------------------------------------------------------------------
  25. Le moteur est un modèle dit "universel" (à charbons)
  26. La vitesse du moteur en 220V est très grande
  27. La vitesse est limitée par un decoupage de la tension secteur par un triac BT137 - 800
  28. drivé par un optocoupleur MOC3023 (sans circuit de detection de passage a zero)
  29. Le sens de rotation du moteur est changé par inversion du bobinage du stator
  30. par rapport au rotor cablé en série. Cette inversion est obtenue au moyen de deux relais inverseurs.
  31. Le moteur n'est pas alimenté si les relais sont tous deux au repos ou tous deux collés.
  32. Toutefois cette deuxième configuration (tous deux collés) est sans interet et consomme
  33. inutilement sur l'alim 5V. Elle n'est donc pas permise.
  34.  
  35. Le moteur est également stoppé par absence d'impulsions de commande sur l'optocoupleur
  36. (et donc le triac)
  37.  
  38. IMPORTANT:
  39. 1) Les relais ne doivent jamais êtres commutés alors que des impulsions de commandes
  40. du triac sont présentes, sous peine de destruction possible du triac.
  41. La procedure consiste donc à arrêter les impulsions et à attendre quelques secondes
  42. avant de commuter un relais.
  43. 2) Je déconseille d'envoyer des impulsions lorsque les deux relais sont au repos,
  44. et donc lorsque le triac est en roue libre.
  45.  
  46. --------------------------------------------------------------------------------
  47. Le principe du découpage de la tension alternative du secteur consiste à déclencher la conduction d'un triac après un délai très précis débutant au début de chaque alternance.
  48. Il faut donc connaître l'instant du début de l'alternance: cette information est obtenue par l'optocoupleur CNX34 suivi d'une mise en forme par un inverseur à hystérésis CD40106.
  49. On applique ce signal sur l'entrée d'interruption externe INT0 de l'ATmega32 (pin16).
  50.  
  51. Cette interruption ISR (INT0_vect) va faire partir le compteur du Timer2
  52. voir la suite de l'explication sur la page html associee a ce montage
  53. --------------------------------------------------------------------------------
  54.  
  55. REMARQUE: Triac sur charge inductive:
  56. Lors de la conduction du triac, le courant dans une inductance s'établit progressivement.
  57. Donc pas de di/dt important, et partant pas de surtension (e=-L.di/dt)).
  58. Mais un dv/dt important et gênant.
  59.  
  60. Une coupure du courant dans une inductance provoque un di/dt qui genere mathematiquement une
  61. surtension E=-L.di/dt. Oui mais un triac n'est pas un transistor! Un triac se bloque
  62. naturellement de lui même lorsque le courant s'annule. DONC PAS DE SURTENSION au blocage contrairement
  63. à ce qu'on lit ici ou là à longueur de journée.
  64. Dans une self, la tension est en quadrature avec le courant. Donc le minimum de courant correspond
  65. à une tension non nulle (aux bornes de la self, en série avec le secteur et en opposition
  66. de phase avec celui-ci vu du triac, donc zéro volt vu du triac, me trompe-je ?)
  67. Un circuit dit "snubber" (100nF 250V alternatif + 100 ohm en série) est cablé en //
  68. entre A1 et A2 du triac. La fonction du condensateur est de maintenir un courant non nul dans le triac
  69. à la mise en conduction, le courant passant dans le bobinage ne s'établissant que trop lentement.
  70. Quant à la résistance en série avec le condensateur, elle sert à limiter le courant en question.
  71. Sans la résistance, c'est la destruction assurée du triac. De même une résistance de trop
  72. faible valeur fait veillir le triac prématurément et aboutit à une destruction plus ou moins rapide.
  73.  
  74. Il existe maintenant des triacs qui se passent de snubber...
  75. --------------------------------------------------------------------------------
  76. TEMPERATURES
  77. degres (Acquisition) (compte tenu de mon schéma)
  78. 20 (112)
  79. 30 (85)
  80. 40 (69)
  81. 50 (58)
  82. 60 (44)
  83. 80 (39)
  84. 90 (35)
  85. ================================================================================
  86. La carte electronique répond aux signaux d'une télécommande TV infrarouge universelle
  87. Beaucoup de modèles conviennent, il faudra adapter les codes des touches dans ce
  88. programme le cas écheant (voir les 'case octet_IR of') dans la partie "main"
  89. Pour ma part, j'utilise une PHILIPS type 'UNIVERSAL SBC RU 252 II'
  90. ================================================================================
  91.  
  92.  
  93.  
  94. ======================== Rappel ATmega32 =======================================
  95.  
  96. Device Flash EEPROM SRAM Speed Volts
  97. ATmega32 32kB 1024B 2048B 0 - 16MHz 4.5 - 5.5V
  98. ================================================================================
  99. */
  100.  
  101. #include "lave_linge.h"
  102.  
  103. //#define F_CPU 16000000
  104.  
  105. //#include <math.h>
  106. #include <stdlib.h>
  107. //#include <stdint.h>
  108. #include <stdio.h>
  109. #include <string.h>
  110. #include <avr/wdt.h>
  111.  
  112. #include <avr/io.h>
  113. #include <avr/interrupt.h>
  114.  
  115. #include <util/delay.h>
  116. #include "dm_lcd.c" // ATTENTION: la configuration des ports dedies a l'afficheur LCD est effectuee dans le fichier "dm_lcd.h"
  117.  
  118. #include <avr/pgmspace.h>
  119.  
  120.  
  121.  
  122. extern uint8_t asmfunction(uint8_t); // all assembly subroutines must be declared external to the C source
  123.  
  124.  
  125. #define false 0
  126. #define true 1
  127.  
  128. #define OCRmin 60
  129. #define OCRdemar 105
  130. #define OCRmax 140
  131. // attention 162 est la limite au dela de laquelle on retablit les alternances à 100%
  132. // compte tenu de mon schéma
  133.  
  134. // #define P_cons_purge 188
  135. #define tps_rincage_max 120
  136.  
  137. char * version = "4.08";
  138.  
  139. char Labels_numeros[16][8+1] = {"STOP", "eau", "lavage", "vidange", "eau",
  140. "rincage1", "vidange", "eau", "rincage2", "vidange", "eau",
  141. "rincage3", "vidange", "eau", "rincage4", "essorage"};
  142.  
  143.  
  144. /*
  145. RAPPEL variables avr-gcc (vérifiable avec le .map)
  146.  
  147. char 1 -128 .. 127 ou caractères
  148. unsigned char 1 0 .. 255 (equiv à byte du pascal)
  149. uint8_t 1 (c'est la même chose que l'affreux 'unsigned char')
  150. char toto[n] n
  151. int 2 -32768 .. 32767
  152. int16_t 2 idem 'int'
  153. short int 2 pareil que int (?)
  154. unsigned int 2 0 .. 65535
  155. uint16_t 2 idem 'unsigned int'
  156. long int 4 -2 147 483 648 à 2 147 483 647
  157. int32_t 4 32 bits ; idem long int
  158. long long int 8
  159. unsigned long int 4 32 bits ; 0 .. 4 294 967 295 (4,2 x 10^9)
  160. uint32_t 4 32 bits ; idem 'unsigned long int'
  161. float 4
  162. double 4 // (?)
  163.  
  164. La déclaration char JOUR[7][9];
  165. réserve l'espace en mémoire pour 7 mots contenant 9 caractères (dont 8 caractères significatifs).
  166. */
  167.  
  168.  
  169. //types
  170.  
  171. enum Prg { couleur = 0, blanc, laine, froid, rapide, test };
  172.  
  173.  
  174. // variables en RAM
  175. int Prg = froid;
  176. uint8_t rxAdr;
  177. uint8_t rxCmd;
  178. uint8_t adr1;
  179. uint8_t cmd1;
  180. uint8_t rxAdr_IR;
  181. uint8_t rxCmd_IR;
  182. uint8_t bit_bascul_IR; // BOOLEAN
  183. uint8_t octet_IR; //octet recu par le recepteur IR
  184. uint8_t bitsix;
  185. uint8_t memo_bitsix;
  186. uint8_t nouveau; // BOOLEAN // pour l'anti rebond signaux IR
  187. uint8_t stop; // BOOLEAN
  188. uint8_t stop_imps; // boolean // force le blocage du triac
  189. uint8_t memo_stop_imps; // boolean
  190. uint16_t nb_ms2;
  191. int compteur1;
  192. uint8_t ti;
  193.  
  194. uint16_t periode;
  195. float OCR2_real;
  196. char str12[12+1];
  197.  
  198. uint16_t acqui_ADC;
  199. float T; // temperature
  200. uint8_t pos_bt;
  201.  
  202. uint8_t pause; //boolean
  203. uint8_t relais1; // boolean
  204. uint8_t relais2; // boolean
  205. uint8_t EV1; // boolean // électrovanne 1 (admision d'eau pour le prélavage)
  206. uint8_t EV2; // boolean // électrovanne 2 (admision d'eau pour le lavage et les rinçages)
  207. uint8_t pompe; // boolean
  208. uint8_t memo_pompe; // boolean
  209. uint8_t NIV1; // boolean // pressostat
  210. uint8_t NIV2; // boolean // pressostat
  211. char TXTniv[2+1];
  212. char Nom_prg1[10+1];
  213. char Nom_prg2[10+1];
  214. uint8_t affi_requis; // boolean
  215. uint8_t temps_i; // pour le generateur d'impulsions vers le triac moteur. compteur en secondes
  216. uint8_t temps_ch_sens; // pour le changement automatique de sens
  217. uint8_t periode_ch_sens; // en secondes
  218.  
  219. uint8_t prelavage; // boolean
  220. uint8_t lavage; // boolean
  221. uint8_t memo_lavage; // boolean
  222. uint16_t temps_lavage; // compteur en secondes
  223. uint16_t duree_lavage; // duree totale (consigne, en minutes)
  224. uint8_t mn_froides; // nombre de minutes de lavage à froid au bébut du cycle
  225. uint16_t P_cons_lav;
  226. uint16_t tps_lavage_max; // secondes
  227. uint8_t timeOUT_lavage; // boolean
  228.  
  229. uint16_t temps_chauffage; // compteur en secondes
  230. uint8_t temps_chauffage_max; // en secondes
  231. uint8_t timeOUT_chauffage; //boolean
  232.  
  233. uint16_t temps_brassage; // compteur en secondes
  234. uint8_t temps_brassage_max; // en secondes
  235. uint8_t timeOUT_brassage; //boolean
  236.  
  237. uint16_t temps_pompe; // compteur en secondes
  238. uint16_t temps_EV2; // compteur en secondes
  239.  
  240. uint8_t rincage; // boolean
  241. uint8_t memo_rincage; // boolean
  242. uint16_t temps_rincage; // compteur en secondes
  243. uint8_t timeOUT_rincage; // boolean
  244. uint8_t nb_rincage_max;
  245.  
  246. uint8_t essorage; // boolean
  247. int16_t temps_essorage; // compteur en secondes
  248. uint16_t tps_essr_max;
  249. uint8_t timeOUT_ess; // boolean
  250. uint16_t P_cons_ess;
  251. uint16_t ajout_vt_esso;
  252. uint8_t accelere; // boolean
  253.  
  254. uint8_t purge; // boolean
  255. uint16_t temps_purge; // compteur en secondes
  256. uint16_t tps_purge_max;
  257. uint8_t timeOUT_purge; // boolean
  258. uint16_t P_cons_purge;
  259.  
  260. uint16_t temps_defoul;
  261. uint16_t tps_defoul_max;
  262. uint8_t timeOUT_defoul; // boolean;
  263.  
  264. uint8_t temps_total; // compteur en minutes
  265. uint8_t num_requis;
  266. uint8_t remplissage; // boolean
  267. uint8_t memo_remplissage; // boolean
  268.  
  269. uint8_t chauffage; // boolean
  270. uint8_t memo_chauffage; // boolean
  271. uint8_t chauffe_enable; // boolean
  272. uint8_t memo_chauffe_enable; // boolean;
  273. uint8_t brassage; // boolean
  274.  
  275. uint8_t defoulage; // boolean
  276.  
  277. uint8_t vidange; // boolean
  278. uint8_t memo_vidange; // boolean
  279. uint8_t sens_enable; // boolean permet ou bloque le changement de sens automatique du moteur toutes les 15s
  280. uint8_t TimeOUT_sens; // boolean
  281. uint8_t vert; // boolean
  282. float Temperat_max; // temperature de lavage
  283. uint8_t numero;
  284. uint8_t a_choisir; // boolean
  285.  
  286. //--------------------------------------------------------------
  287.  
  288.  
  289.  
  290.  
  291. void init_ports(void) // ports perso DDRx 0=entree, 1=sortie
  292. {
  293. PORTA = 0b00000000;
  294. DDRA = 0b01111111; // portA[7] = entree Thermistance
  295.  
  296. PORTB = 0b00000000;
  297. DDRB = 0b11111101; // portB[1] = T1 = entree (pour le frequencemetre)
  298.  
  299. DDRC = 0b01111111; // PC7 en entree (IR)
  300.  
  301. PORTD = 0b10100011; // les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
  302. DDRD |= 0b10011000; // portD[6] en entree (ICP periodemetre) portD[7] en sortie (OC2)
  303.  
  304. SFIOR &= 0b11111011; // p:50 (bit PUD du SFIOR)
  305. // (the Pull-up Disable – PUD bit in SFIOR disables the pull-up function for all pins in all ports when set)
  306. }
  307.  
  308.  
  309.  
  310.  
  311. void InitINTs(void)
  312. {
  313.  
  314. /*
  315. TIMER0 ------------------------------------------------------------------------------------------------------
  316. utilise comme base de temps 1ms (et 1s)
  317. */
  318. TCCR0 |= 0b01001000; // Timer0 en mode CTC (Clear Timer on Compare Match): WGM00=1 (bit6) et WGM01=0 (bit3
  319. //voir p:74 et 80
  320. TCCR0 |= 0b00000011; // Timer0 prescaller = 1/64. 0CS0[2,1,0] = 011 voir p:82 et p:80
  321. TIMSK |= 0b00000010; // Timer/Counter0 Output Compare Match Interrupt Enable.( Bit 1 – OCIE0) p:82
  322. OCR0 = 250; // Timer0 freq = 16MHz/64/250= 1kHz (T=1ms)
  323.  
  324. /*
  325. TIMER1 16 bits -------------------------------------------------------------------------------------------------
  326. utilise comme PERIODEMETRE pour determiner la vitesse de rotation du moteur
  327. Le Timer1 s'incremente avec clk/256 (From prescaler)
  328. 16MHz / 256 = 62500Hz (=16us)
  329. Le Timer1 sera utilise avec la fonction 'capture' sur pin ICP1 (PD6)
  330. Le front sur ICP appelle l'interruption ISR (TIMER1_CAPT_vect) (voir plus bas)
  331. Cette interruption recopie la valeur du compteur du timer1 (TCNT1H,L) dans les registres de capture ICR1H,L
  332. la valeur obtenue représente donc la durée de la période du signal sur le pin ICP1
  333. */
  334.  
  335. // TCCR1A
  336. TCCR1B |= 0b00000100; // clk/256 (From prescaler)
  337. TIMSK |= 0b00100000; //TICIE1 = bit5 (TICIE1) Timer/Counter1, Input Capture Interrupt Enable
  338.  
  339. /*
  340. TIMER2 - 8bits ------------------------------------------------------------------------------------------------
  341. Utilise pour generer le signal de decoupage de l'alimentation secteur du moteur
  342. Les 3 bits de poids faible de TCCR2 selectionnent l'horloge et le prescaler. voir page 119 et 125 du pdf
  343. Bit 6, 3 WGM21:0 = 01 -> mode CTC voir p:125 du pdfCTC = "Clear Timer on Compare Match" (CTC) Mode
  344. In "Clear Timer on Compare mode" (CTC mode, WGM21:0 = 2), the counter is cleared to zero when the
  345. counter value (TCNT2) matches the OCR2. The OCR2 defines the top value for the counter, hence also its resolution.
  346. */
  347. TCCR2 |= 0b10001111; // p:125
  348. TIMSK &= 0b01111111; // INT Timer2 comp disable; Voir le datasheet ATmega32.pdf p:130}
  349. GICR |= 0b01000000; // extINT0 enable; voir page 67 du pdf
  350. MCUCR |= 0b00000010; // The falling edge of INT0 generates an interrupt request. p:67 du pdf
  351. }
  352.  
  353.  
  354.  
  355.  
  356. void init_variables(void)
  357. {
  358. stop_imps = true;
  359. remplissage = false;
  360. prelavage = false;
  361. lavage = false;
  362. chauffe_enable = false;
  363. brassage = false;
  364. rincage = false;
  365. nb_rincage_max = 4;
  366. mn_froides = 5;
  367. vidange = false;
  368. essorage = false;
  369. defoulage = false;
  370. sens_enable = false;
  371. a_choisir = true;
  372. RAZ_tempos();
  373. affi_requis = false;
  374.  
  375. relais1_off();
  376. relais2_off();
  377. EV2_off();
  378. POMPE_off();
  379. OCR2 = 140; // [10..162] retard a la commutation du triac alimentant le moteur (162 = pas de tension)
  380. compteur1 = 0;
  381. Temperat_max = 20; // en degres ºC
  382. pause = false;
  383. }
  384.  
  385.  
  386.  
  387. void RAZ_tempos(void)
  388. {
  389. // initialisation des compteurs avec des valeurs qui les bloquent
  390. temps_lavage = 100*60; // en desondes
  391. P_cons_lav = 875;
  392. temps_rincage = 100*60; // en secondes
  393. temps_pompe = 0;
  394. temps_EV2 = 0;
  395. temps_essorage = 100*60; // en secondes
  396. temps_defoul = 100*60;
  397. temps_total = 100;
  398. temps_ch_sens = 5;
  399.  
  400. Prg = couleur;
  401. Temperat_max = 40;
  402. tps_lavage_max = 10 *60; //secondes
  403. temps_chauffage_max = 60; // secondes, puis on fait tourner quelques tours
  404. tps_essr_max = 4*60; // secondes
  405. tps_purge_max = 35; // secondes
  406. tps_defoul_max = 5; // secondes
  407. periode_ch_sens = 10; // secondes
  408. ti = 0;
  409. }
  410.  
  411.  
  412. void lcd_gotoxy_clrEOL (int x, int y)
  413. // place le curseur en x,y et efface jusqu'a la fin de la ligne
  414. {
  415.  
  416. lcd_gotoxy(x, y);
  417. int i;
  418. for (i=x; i<(20-x); i++) lcd_puts(" ");
  419. lcd_gotoxy(x, y);
  420. }
  421.  
  422.  
  423. void relais1_off(void)
  424. {
  425. PORTA &= 0b11111011;
  426. relais1 = false;
  427. lcd_gotoxy(0,3);
  428. lcd_puts(" ");
  429. }
  430.  
  431.  
  432. void relais2_off(void)
  433. {
  434. PORTB &= 0b11111011;
  435. relais2 = false;
  436. lcd_gotoxy(0,3);
  437. lcd_puts(" ");
  438. }
  439.  
  440.  
  441. void relais1_on(void)
  442. {
  443. PORTA |= 0b00000100;
  444. relais1 = true;
  445. lcd_gotoxy(0,3);
  446. lcd_puts(">");
  447. }
  448.  
  449.  
  450.  
  451. void relais2_on(void)
  452. {
  453. PORTB |= 0b00000100;
  454. relais2 = true;
  455. lcd_gotoxy(0,3);
  456. lcd_puts("<");
  457. }
  458.  
  459.  
  460.  
  461. void EV2_on(void) // commande électrovanne2. //(on peut en rajouter)
  462. {
  463. PORTA |= 0b00000010;
  464. EV2 = true;
  465. temps_EV2 = 0;
  466. lcd_gotoxy(5,3);
  467. lcd_puts("EV");
  468. lcd_gotoxy(7,3);
  469. lcd_puts("2");
  470. }
  471.  
  472.  
  473. void EV2_off(void)
  474. {
  475. PORTA &= 0b11111101;
  476. EV2 = false;
  477. if (!EV1)
  478. { // le dernier ferme la porte en sortant!
  479. lcd_gotoxy(5,3);
  480. lcd_puts(" ");
  481. }
  482. lcd_gotoxy(7,3);
  483. lcd_puts(" ");
  484. }
  485.  
  486.  
  487. void POMPE_on(void)
  488. {
  489. CHAUFFAGE_off();
  490. PORTB |= 0b00001000; // pompe
  491. pompe = true;
  492. temps_pompe = 0;
  493. }
  494.  
  495.  
  496.  
  497. void POMPE_off(void)
  498. {
  499. PORTB &= 0b11110111; // pompe
  500. pompe = false;
  501. }
  502.  
  503.  
  504.  
  505. void RESET(void)
  506. {
  507. lcd_clrscr();
  508. lcd_gotoxy(1,1);
  509. lcd_puts("SOFT RESET dans 1s");
  510. _delay_ms(300);
  511. wdt_enable( 10 ); // active le chien de garde
  512. while(1); // boucle infinie --> le chien de garde fait reseter
  513. }
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520. void initADC(void)
  521. {
  522. // voir p:201
  523. // RAPPEL: ADCH,L sont les deux registres contennat le resultat de la conversion (voir p:217)
  524.  
  525. ADMUX = 0b00000111; // ADC7 en mode "Single Ended Input" voir p:215
  526. ADCSRA = 0b11000111; // ADC prescaler = 1/128 voir p:217 ADEN = 1 (ADC Enable) Bit 6 start conversion
  527. }
  528.  
  529.  
  530. /*
  531. RAPPEL: pour la liste complete des interruptions disponibles:
  532. voir le fichier iom32.h situé (sous Linux) dans /usr/lib/avr/include/avr
  533. */
  534.  
  535.  
  536. ISR(BADISR_vect)
  537. {
  538. // évite de planter si une int est enable et pas de procedure associée écrite (ce qui fait reseter l'ATmega)
  539. }
  540.  
  541.  
  542. ISR (INT0_vect)
  543. //interruption sur front descendant sur l'entree Int0
  544. // declenchee par le signal secteur 50Hz
  545. {
  546. // genere le signal de decoupage de la tension du moteur sur la sortie OC2
  547. // PushAllRegs;
  548. TCNT2 = 0;
  549. TCCR2 |= 0b00110000; // set OCE on compare match
  550. TCCR2 |= 0b10000000; // bit FOCE2 voir p:125 (force comparaison virtuelle pour RAZ OCE)
  551. // ce qui a pour effet de passer la sortie OC2 à 1
  552. if (!stop_imps) TCCR2 = TCCR2 &= 0b11101111; // clear OCE on compare match (generera le signal sur OCE)
  553. // PopAllRegs;
  554. }
  555.  
  556.  
  557. ISR (TIMER1_CAPT_vect)
  558. /* TIMER1 = PERIODEMETRE
  559. voir p:110, 111, 112 du datasheet
  560. The Input Capture (ICR1H - ICR1L) is updated with the counter (TCNT1) value each time an event occurs on the ICP1 pin
  561. 16MHz/256(prescaler)=62500Hz
  562. 62500/50=1250
  563. */
  564. {
  565. cli();
  566. periode = ICR1L + 256 * ICR1H; //lit le registre de capture ( 50Hz -> periode = 1250 )
  567. TCNT1H = 0; //raz TCNT1, registre de comptage
  568. TCNT1L = 0;
  569. sei();
  570. }
  571.  
  572.  
  573.  
  574. /*
  575. ISR (ANA_COMP_vect)
  576. {
  577. //interruption du convertisseur analogique/numerique
  578.  ======= NON UTILISEE DANS CE PROGRAMME ==========
  579. }
  580. */
  581.  
  582.  
  583. void GetADC(void)
  584. {
  585. ADCSRA |= 0b01000000; // Bit 6 start conversion
  586. _delay_us(10);
  587. acqui_ADC = ADCL + 256 * ADCH;
  588. }
  589.  
  590.  
  591. int32_t abs_int32(int32_t x)
  592. {
  593. if (x >= 0) return x ; else return -x;
  594. }
  595.  
  596.  
  597.  
  598. void strcpy_a_n(char *CH1, char *CH2, uint8_t a, uint8_t n )
  599. /*
  600. recopie n caractères depuis i0 de CH2 dans CH1
  601. attention: CH2 peut ne pas être un string (pas de \0 à la fin) ce qui peut être pratique pour lire un flux
  602. mais a+n ne doit pas déborder de CH1 et CH2 !
  603. ajoute \0 à la fin (le prévoir dans la longueur de la chaine CH1)
  604. */
  605. {
  606. uint8_t i;
  607. i=0;
  608. while ( i < n )
  609. {
  610. CH1[i] = CH2[a+i];
  611. i++;
  612. }
  613. CH1[i]='\0';
  614. }
  615.  
  616.  
  617. uint8_t isNumeric(char *CH1)
  618. {
  619. uint8_t i;
  620. i=0;
  621. while (CH1[i] != '\0')
  622. {
  623. if ((CH1[i]>='0' && CH1[i]<='9') == 0) return 0;
  624. i++;
  625. }
  626. return 1;
  627. }
  628.  
  629.  
  630. void vitesse_mini(uint8_t ocr2_i)
  631. {
  632. OCR2 = ocr2_i;
  633. OCR2_real = ocr2_i;
  634. }
  635.  
  636.  
  637. void CHAUFFAGE_on(void)
  638. // cette fonction est appellée uniquement par la fonction "regulation_TEMPERATURE" (ligne 1165 environ)
  639. {
  640. if (chauffe_enable)
  641. {
  642. stop_imps = true;
  643. PORTB |= 0b00010000; // colle le relais de chaufage
  644. chauffage = true;
  645. }
  646. }
  647.  
  648.  
  649. void CHAUFFAGE_off(void)
  650. {
  651. PORTB &= 0b11101111; // décolle le relais de chauffage
  652. chauffage = false;
  653. }
  654.  
  655.  
  656.  
  657. void interroge_IR(void)
  658. {
  659. if (RecvRC5() == 0)
  660. {
  661. octet_IR = rxCmd_IR;
  662. memo_bitsix= bitsix;
  663. bitsix= bit_bascul_IR;
  664. if (bitsix != memo_bitsix) nouveau=1; else nouveau=0;
  665.  
  666. PORTD |= 0b01000000; /* allume LED */
  667. }
  668. else { octet_IR = 0xFF; }
  669.  
  670. PORTD &= 0b10111111; /* eteint LED */
  671.  
  672. if (!nouveau) { octet_IR = 0xFF; } /* pas de répétition auto dans cette application */
  673. }
  674.  
  675.  
  676. void PAUSER(char str1[20+1])
  677. {
  678.  
  679. vitesse_mini(OCRmax); // pour ralentir
  680. memo_stop_imps = stop_imps;
  681. stop_imps = true; // STOP MOTEUR
  682.  
  683. memo_chauffage = chauffage;
  684. memo_chauffe_enable = chauffe_enable ;
  685. chauffe_enable = false;
  686. CHAUFFAGE_off();
  687. EV2_off();
  688. memo_pompe = pompe;
  689. POMPE_off();
  690.  
  691. pause = true;
  692.  
  693. // ligne 0 non touchée
  694. lcd_gotoxy_clrEOL(0,1);
  695. lcd_puts("== PAUSE == ");
  696. lcd_puts(str1);
  697. lcd_gotoxy_clrEOL(0,2);
  698. lcd_puts("Bouton rouge = RESET");
  699. lcd_gotoxy_clrEOL(0,3);
  700. lcd_puts("Touche 5 = MARCHE");
  701. _delay_ms(1000);
  702.  
  703. octet_IR = 255; // securité
  704. do
  705. {
  706. interroge_IR();
  707. } // attend appui sur bouton rouge ou touche 5 avant de reseter ou de remettre en marche
  708. while (( ((PIND & 0b00000010) != 0) && (octet_IR != 5)));
  709.  
  710. if ((PIND & 0b00000010) == 0) RESET(); // (bouton rouge)
  711.  
  712.  
  713. // (touche 5)suite, remise en marche normale avec restauration des parametres courants
  714.  
  715. if (essorage)
  716. {
  717. temps_essorage = 0;
  718. P_cons_ess = 2000; // vitesse tres lente au depart pour defouler
  719. }
  720. chauffe_enable = memo_chauffe_enable;
  721. if (memo_chauffage == 1) { CHAUFFAGE_on(); }
  722.  
  723. pompe = memo_pompe;
  724. if (pompe == 1) { POMPE_on(); }
  725.  
  726. vitesse_mini(OCRmax);
  727. stop_imps = memo_stop_imps;
  728.  
  729. // ligne 0 non touchée
  730. lcd_gotoxy_clrEOL(0,1);
  731. lcd_gotoxy_clrEOL(0,2);
  732. lcd_gotoxy_clrEOL(0,3);
  733.  
  734. pause = false;
  735. }
  736.  
  737.  
  738.  
  739. void detection_bouton_ROUGE(void)
  740. {
  741. if ((PIND & 0b00000010) == 0 ) PAUSER("BT R");
  742. }
  743.  
  744.  
  745. void detection_bouton_VERT(void) // ABREGE le lavage ou le rincage en cours (passe au numero suivant=vidange)
  746. {
  747. if ((PIND & 0b00000001) == 0)
  748. {
  749. vert = true;
  750. lcd_clrscr();
  751. lcd_gotoxy(10,1);
  752. lcd_puts("NEXT !");
  753. _delay_ms(500);
  754. lcd_clrscr();
  755.  
  756. } else vert = false;
  757. }
  758.  
  759.  
  760. void _delay_s(uint8_t nb_s)
  761. {
  762. while ((nb_s > 0) && !vert)
  763. {
  764. detection_bouton_ROUGE();
  765. detection_bouton_VERT();
  766. _delay_ms(500);
  767. detection_bouton_ROUGE();
  768. detection_bouton_VERT();
  769. _delay_ms(500);
  770. nb_s--;
  771. }
  772. vert = false;
  773. }
  774.  
  775.  
  776.  
  777. void Timer1_setTime(int t) // en microsecondes
  778. // quartz = 16MHz et prescaller (du Timer1) = 1/8 ce qui fait 2MHz
  779. //voir p:87
  780. {
  781. OCR1A = 2 * t;
  782. }
  783.  
  784.  
  785. int RecvRC5 (void)
  786. /* recepteur RC5 bas niveau qui scrute le port relié au capteur et décode le signal
  787.  
  788. 2 bits de start
  789. 1 bit de basculement
  790. 5 bits d'adressage (type d'appareil, TV, VCR etc...)
  791. 6 bits de commande (touches)
  792. */
  793. {
  794. uint32_t t;
  795. uint8_t niv_entree, niv1, niv2; /* booleens - niveaux des deux demi plateaux constituant un bit */
  796. uint8_t n;
  797. uint16_t data;
  798.  
  799. t=0;
  800. niv1=0;
  801. niv2=0;
  802. data = 0;
  803.  
  804. niv_entree=1;
  805. /* attente pendant la durée d'une trame d'un front descendant (le signal issu du capteur est à 1 au repos) */
  806.  
  807. const unsigned long int tmax = 14*1778; //24892us = durée de 1 trame (environ 25ms donc)
  808.  
  809. while ( (niv_entree == 1) && (t<= tmax) )
  810. {
  811. if ( (PINC & 0b10000000) > 0) { niv_entree=1; } else { niv_entree=0; }
  812. _delay_us(1);
  813. t++;
  814. }
  815. /* si le signal parvient trop vite (< 2 bits) on en déduit qu'on a pris le train en marche et on saute,
  816. puisque lecture impossible de la trame en cours
  817. */
  818. if (t < (889 * 2)) return t;
  819.  
  820. if (t > tmax) return 2; /* temps maxi écoulé, pas de signal reçu */
  821.  
  822. /* ici on se trouve juste un epsilon après le basculement à 0 du premier bit de start (milieu de bit) */
  823.  
  824. _delay_us(444); /* durée de 1/4 bit */
  825.  
  826. for (n=1; n<=13; n++)
  827. {
  828. _delay_us(889); // durée de 1/2 bit
  829. /* ici on se trouve au milieu du niveau du plateau du demi bit */
  830. if ( (PINC & 0b10000000) == 0) { niv1 = 0; } else { niv1 = 1; }
  831. _delay_us(889); // durée de 1/2 bit
  832. /* ici on se trouve au milieu du second plateau du demi bit */
  833. if ( (PINC & 0b10000000) == 0) { niv2 = 0; } else { niv2 = 1; }
  834. /* ici on connait les valeurs des deux niveaux, on en déduit le sens de la transition (front montant ou descendant)*/
  835. if (niv1 == niv2) { return 3; } // erreur de lecture, bit non valide
  836. if ((niv1 == 1 ) && (niv2 == 0)) { data |= 0b00000001; }
  837. data = data << 1;
  838. }
  839. data = data >> 1; // on rejette le dernier décallage (sans perte de bit puisque largeur data = 16 bits > )
  840.  
  841. rxCmd_IR = data & 0b0000000000111111;
  842. rxAdr_IR = (data & 0b0000011111000000) >> 6;
  843. bit_bascul_IR = (data & 0b0000100000000000) >> 11;
  844. return 0;
  845. }
  846.  
  847.  
  848.  
  849.  
  850. void lcd_aff_nb (int32_t valeur1, uint8_t nb_chiffres, uint8_t position_pt_decimal, char affi_zero )
  851. //affiche un nombre positif en representation decimale
  852. // affi_zero = 1 affiche les zéros non significatifs
  853. {
  854. int32_t N;
  855. uint8_t r ;
  856. char tbl[7];
  857. uint8_t i;
  858. char affz;
  859.  
  860. affz = affi_zero;
  861.  
  862. if ((valeur1 == 0) && (affz == 0)) // le zéro tout seul est significatif
  863. {
  864. for (i=1; i<nb_chiffres; i++) {lcd_putc(' '); }
  865. lcd_putc('0');
  866. }
  867. N = valeur1;
  868.  
  869. for (i=1; i<=nb_chiffres; i++)
  870. {
  871. r=48 + N % 10; // modulo (reste de la division)
  872. N /= 10; // quotient
  873. tbl[i]=r;
  874. }
  875.  
  876. for (i=1; i<=nb_chiffres; i++)
  877. {
  878. if (i == (nb_chiffres - position_pt_decimal +1) ) { lcd_puts("."); affz=1;} // après le . les 0 seront affichés
  879. if (tbl[nb_chiffres+1-i] != '0') affz=1; // si 1 digit est >0 alors les 0 ultérieurs deviennent significatifs
  880. if ((!affz) && (tbl[nb_chiffres+1-i] == '0')) lcd_putc(' ');
  881. else lcd_putc(tbl[nb_chiffres+1-i]);
  882. }
  883. }
  884.  
  885.  
  886.  
  887. void lcd_aff_bin (unsigned long int valeur, int nb_digits)
  888. //affiche un nombre en representation binaire
  889. // 16 bits max
  890. {
  891. unsigned char r ;
  892. char tbl[17];
  893. unsigned i;
  894.  
  895. for (i=1; i<=nb_digits; i++)
  896. {
  897. r= 48 + valeur % 2; // modulo (reste de la division)
  898. valeur /= 2; // quotient
  899. tbl[i]=r;
  900. };
  901. for (i=1; i<=nb_digits; i++) lcd_putc(tbl[nb_digits +1 -i]);
  902. }
  903.  
  904.  
  905.  
  906. void test_IR(void)
  907. {
  908. int r1;
  909. lcd_clrscr();
  910. lcd_gotoxy(0, 0);
  911.  
  912. lcd_puts("Test IR STOP=ok ou 0");
  913. interroge_IR();
  914. while (rxCmd_IR !=0)
  915. {
  916. r1 = RecvRC5();
  917. if (r1==0)
  918. {
  919. lcd_gotoxy(2,1);
  920. lcd_puts("CMD= ");
  921. lcd_aff_nb (rxCmd_IR, 5, 0, 0 );
  922.  
  923. lcd_gotoxy(2,2);
  924. lcd_puts("Adr= ");
  925. lcd_aff_nb (rxAdr_IR, 5, 0, 0 );
  926.  
  927. lcd_gotoxy(2,3);
  928. lcd_puts("Bsc= ");
  929. lcd_aff_nb (bit_bascul_IR, 5, 0, 0 );
  930.  
  931. _delay_ms(10);
  932. }
  933. }
  934.  
  935. lcd_clrscr();
  936. lcd_gotoxy(1,0);
  937. lcd_puts("fin de test");
  938. _delay_ms(500);
  939. lcd_clrscr();
  940. PAUSER("1");
  941. }
  942.  
  943.  
  944.  
  945. uint32_t StrTo_uint32 (char *string1)
  946. // nombres positifs (non signés) seulement 0...4 294 967 295 (4,2 x 10^9)
  947. // atoi m'a occasionné des problèmes... pour les grands nombres > 2 octets
  948. {
  949. uint8_t i;
  950. uint32_t x;
  951. i=0;
  952. x=0;
  953.  
  954. while (string1[i] != '\0')
  955. {
  956. x=(10 * x) + (string1[i] -48);
  957. i++;
  958. }
  959. return x;
  960. }
  961.  
  962.  
  963.  
  964. void Event_1s(void)
  965. {
  966. if (!pause)
  967. {
  968. // PushAllRegs; // sauvegarde sur la pile et non dans iData en statique
  969.  
  970. // portA:= portA xor %00100000; // fait clignoter une LED pour TEST
  971.  
  972. if (lavage)
  973. {
  974. if (temps_lavage < 120 *60) // ne boucle pas 120mn= 2h
  975. {
  976. if (!remplissage) {temps_lavage++;}
  977. if (temps_lavage >= tps_lavage_max) { timeOUT_lavage = true; }
  978. }
  979. }
  980. //------------------------------------------------------------------------------
  981. if (chauffage)
  982. {
  983. if (temps_chauffage < 120 * 60) // ne boucle pas 120mn= 2h
  984. {
  985. temps_chauffage++;
  986. if (temps_chauffage >= temps_chauffage_max) { timeOUT_chauffage = true; }
  987. }
  988. }
  989. //------------------------------------------------------------------------------
  990. if (brassage)
  991. {
  992. if (temps_brassage < 120 * 60) // ne boucle pas 120mn= 2h
  993. {
  994. temps_brassage++;
  995. if (temps_brassage >= temps_brassage_max) { timeOUT_brassage = true; }
  996. }
  997. }
  998. //------------------------------------------------------------------------------
  999. if (rincage)
  1000. {
  1001. if (temps_rincage < 120*60 )
  1002. {
  1003. temps_rincage++; // ne boucle pas
  1004. if (temps_rincage >= tps_rincage_max ) { timeOUT_rincage = true; }
  1005. }
  1006. }
  1007. //------------------------------------------------------------------------------
  1008. if (essorage)
  1009. {
  1010. if (temps_essorage < 120*60) // ne boucle pas
  1011. {
  1012. temps_essorage++;
  1013. if (temps_essorage >= tps_essr_max) { timeOUT_ess = true;}
  1014.  
  1015. if (temps_essorage > 10) // 10s de defoulage
  1016. {
  1017. P_cons_ess = 6250 / temps_essorage;
  1018. // ce qui fait accelerer la vitesse linéairement / temps, puisque f=1/T
  1019. if (P_cons_ess < 31 ) { P_cons_ess = 31; }
  1020. }
  1021. }
  1022. }
  1023. //------------------------------------------------------------------------------
  1024. if (purge)
  1025. {
  1026. if (temps_purge < 120*60) // ne boucle pas
  1027. {
  1028. temps_purge++;
  1029. if (temps_purge >= tps_purge_max ) { timeOUT_purge = true; } //35s max
  1030.  
  1031. P_cons_purge = 1000 / temps_purge;
  1032. // ce qui fait accelerer la vitesse pour un départ en douceur
  1033. if (P_cons_purge < 190 ) { P_cons_purge = 190; } // atteint au bout de 5s
  1034.  
  1035. }
  1036.  
  1037. // inc(offset_OCR2); //pour accelerer petit à petit
  1038. }
  1039.  
  1040. //------------------------------------------------------------------------------
  1041. if (defoulage)
  1042. {
  1043. if (temps_defoul < 120*60)
  1044. {
  1045. temps_defoul++;
  1046. if (temps_defoul >= tps_defoul_max) { timeOUT_defoul = true; }
  1047. }
  1048. }
  1049.  
  1050. //------------------------------------------------------------------------------
  1051. if (pompe) { temps_pompe++; }
  1052.  
  1053. if (temps_pompe > 5*60)
  1054. {
  1055. PAUSER("PB vidange > 5mn");
  1056. }
  1057.  
  1058. if (EV2) { temps_EV2++; }
  1059. if (temps_EV2 > 5*60) { PAUSER("PB niveau eau"); }
  1060.  
  1061. //------------------------------------------------------------------------------
  1062. temps_ch_sens++;
  1063. if (temps_ch_sens >= periode_ch_sens)
  1064. {
  1065. if (sens_enable) {TimeOUT_sens= true;} // changement de sens requis
  1066. }
  1067. //------------------------------------------------------------------------------
  1068. affi_requis = true; // pas d'affichage directement dans une interruption
  1069. // PopAllRegs;
  1070. }
  1071. }
  1072.  
  1073.  
  1074.  
  1075. ISR (TIMER0_COMP_vect)
  1076. // timer 1ms
  1077. {
  1078. nb_ms2++;
  1079. if (nb_ms2 >= 1000)
  1080. {
  1081. nb_ms2=0;
  1082. Event_1s();
  1083. }
  1084. }
  1085.  
  1086.  
  1087.  
  1088. void detection_niveau_eau(void) // j'ai supprimé la detection du niveau2 (3/4 de cuve, c'est trop)
  1089. {
  1090. if ((PIND & 0b00100000) == 0)
  1091. {
  1092. strcpy(TXTniv, "Lo");
  1093. NIV1 = true;
  1094. NIV2 = false;
  1095. }
  1096. else
  1097. {
  1098. NIV1 = false;
  1099. NIV2 = false;
  1100. strcpy(TXTniv, "--");
  1101. }
  1102. }
  1103.  
  1104.  
  1105.  
  1106. void eteint_toutes_LED(void)
  1107. {
  1108. PORTA |= 0b00001000; // RAZ des deux CD4017 (éteint tout because les Q0 ne sont pas câblés)
  1109. _delay_us(1);
  1110. PORTA &= 0b11110111;
  1111. _delay_us(1);
  1112. }
  1113.  
  1114.  
  1115. void allume_LED(uint8_t num) // num in [0..17]
  1116. {
  1117. uint8_t n;
  1118. PORTA |= 0b00001000; // RAZ des deux CD4017 (éteint tout because les Q0 ne sont pas câblés)
  1119. _delay_us(1);
  1120. PORTA &= 0b11110111;
  1121. _delay_us(1);
  1122.  
  1123. num++;
  1124.  
  1125. if ((num > 0) && (num<19))
  1126. {
  1127. if (num < 10)
  1128. {
  1129. for (n=1; n<=num; n++)
  1130. //for n:= 1 to num do
  1131. {
  1132. PORTA |= 0b00010000; // clk du premier cd4017
  1133. _delay_us(1);
  1134. PORTA &= 0b11101111;
  1135. _delay_us(1);
  1136. }
  1137. }
  1138. else
  1139. {
  1140. for (n=10; n<=num; n++)
  1141. {
  1142. PORTA |= 0b00100000; // clk du second cd4017
  1143. _delay_us(1);
  1144. PORTA &= 0b11011111;
  1145. _delay_us(1);
  1146. }
  1147. }
  1148. }
  1149. }
  1150.  
  1151.  
  1152.  
  1153.  
  1154. void affiche_temperature(void)
  1155. {
  1156. uint8_t t1;
  1157.  
  1158. GetADC();
  1159. acqui_ADC = acqui_ADC >> 2; //décallage à droite de 2 bits; 8 bits au lieu de 10 de resolution
  1160. T = (3500 / acqui_ADC) - 11; // voir feuille de calcul Ooo
  1161.  
  1162. lcd_gotoxy(8, 3);
  1163. if ((T > 0) && (T < 100))
  1164. {
  1165. t1 = T; // conversion float -> entier
  1166. lcd_puts("T=");
  1167. lcd_aff_nb (t1, 2, 0, 0 );
  1168. lcd_puts(" ");
  1169. }
  1170. }
  1171.  
  1172.  
  1173.  
  1174. void change_SENS(uint8_t ocr2_i)
  1175. {
  1176. memo_stop_imps = stop_imps;
  1177. stop_imps = true;
  1178. _delay_ms(1000);
  1179.  
  1180. if (relais1 && !relais2)
  1181. {
  1182. relais1_off();
  1183. _delay_ms(300);
  1184. relais2_on();
  1185. }
  1186. else if (relais2 && !relais1)
  1187. {
  1188. relais2_off();
  1189. _delay_ms(300);
  1190. relais1_on();
  1191. }
  1192. else if (!relais1 && !relais2) { relais1_on(); } // si aucun
  1193.  
  1194. else if (relais1 && relais2) { relais2_off(); } // si les deux
  1195.  
  1196.  
  1197. _delay_ms(400);
  1198. vitesse_mini(ocr2_i); // pour repartir lentement avec le couple souhaité
  1199. stop_imps = memo_stop_imps; //on ne remet en marche que si le moteur tournait déjà lors de l'appel de la fonction
  1200.  
  1201. TimeOUT_sens = false;
  1202. temps_ch_sens = 0;
  1203. }
  1204.  
  1205.  
  1206.  
  1207. void Affiche_temps(uint16_t nb_secondes)
  1208. {
  1209. uint8_t h, mn, sec;
  1210. uint16_t R1;
  1211. // char signe;
  1212.  
  1213. h = nb_secondes / 3600; // transcodage float -> integer A VERIFIER
  1214. R1 = nb_secondes % 3600;
  1215. mn = R1 / 60; // transcodage float -> integer A VERIFIER
  1216. sec = R1 % 60;
  1217. lcd_gotoxy_clrEOL(13,0);
  1218. lcd_aff_nb (mn, 2, 0, 1 );
  1219. lcd_puts(":");
  1220. lcd_aff_nb (sec, 2, 0, 1 );
  1221. }
  1222.  
  1223.  
  1224. void AFFICHAGES(void) // permsise toutes les secondes par le flag affi_requis.
  1225. // le flag affi_requis est positionné par la fonction "Event_1s()"
  1226. {
  1227.  
  1228. affi_requis = false;
  1229. if (lavage) { Affiche_temps(tps_lavage_max - temps_lavage); }
  1230. if (chauffage) { Affiche_temps(temps_chauffage_max - temps_chauffage); }
  1231. if (brassage) { Affiche_temps(temps_brassage_max - temps_brassage); }
  1232.  
  1233. lcd_gotoxy(13, 3); if (chauffage) { lcd_puts("CH"); } else {lcd_puts(" "); }
  1234.  
  1235. lcd_gotoxy(2, 3); lcd_puts(TXTniv);
  1236.  
  1237. //------------------------------------------------------------------------------
  1238. if (rincage) {Affiche_temps(tps_rincage_max - temps_rincage);}
  1239. //------------------------------------------------------------------------------
  1240. if (purge) {Affiche_temps(tps_purge_max - temps_purge);}
  1241. //------------------------------------------------------------------------------
  1242. if (defoulage) { Affiche_temps(tps_defoul_max - temps_defoul);}
  1243. //------------------------------------------------------------------------------
  1244. if (essorage) { Affiche_temps(tps_essr_max - temps_essorage);}
  1245. //------------------------------------------------------------------------------
  1246. if (TimeOUT_sens)
  1247. {
  1248. TimeOUT_sens = false;
  1249. if ((!chauffage) && (!brassage)) change_SENS(OCRdemar);
  1250. }
  1251. }
  1252.  
  1253.  
  1254. void demarrage(uint8_t sens, uint8_t ocr2_i)
  1255. {
  1256. stop_imps = true; // pas de conduction du triac pendant la commutation des relais
  1257. _delay_ms(300);
  1258.  
  1259. if (sens == 0)
  1260. {
  1261. relais2_off();
  1262. _delay_ms(300);
  1263. relais1_on();
  1264. _delay_ms(300);
  1265. }
  1266. else if (sens == 1)
  1267. {
  1268. relais1_off();
  1269. _delay_ms(300);
  1270. relais2_on();
  1271. _delay_ms(300);
  1272. }
  1273.  
  1274. temps_ch_sens = 0;
  1275. vitesse_mini(ocr2_i); // pour partir lentement
  1276. stop_imps = false; // conduction du triac: mise en route du moteur
  1277. _delay_ms(1000); // demarrage franc forcé sans asservissement de vitesse
  1278. }
  1279.  
  1280.  
  1281. void asservissement_vitesse(uint16_t P_cons_i)
  1282. {
  1283. float distance;
  1284. if (((periode > P_cons_i + 10) || (periode ==0)) && (OCR2 > OCRmin) )
  1285. {
  1286. OCR2_real -= 0.01; //accelere
  1287. }
  1288. if (((periode < P_cons_i - 10) && (periode !=0)) && (OCR2 < OCRmax) )
  1289. {
  1290. OCR2_real += 0.01; //ralentit
  1291. }
  1292. OCR2 = OCR2_real;
  1293. }
  1294.  
  1295.  
  1296.  
  1297. void LAVER(uint16_t tps)
  1298. //tps = duree de lavage en secondes
  1299. {
  1300. lavage = true;
  1301.  
  1302. if (tps > 30*60) { tps = 30*60; } // 30mn max (securite)
  1303. tps_lavage_max = tps; // en secondes
  1304.  
  1305. lcd_gotoxy_clrEOL(0,1);
  1306. if(prelavage==true)
  1307. {
  1308. lcd_puts("PRE");
  1309. }
  1310. lcd_puts("LAVAGE ");
  1311. lcd_puts(Nom_prg1);
  1312. lcd_gotoxy_clrEOL(0,2); lcd_puts(Nom_prg2);
  1313. affiche_temperature(); //mesure ET affichage de la temperature (en position 8,3)
  1314.  
  1315. lcd_gotoxy_clrEOL(10,2); lcd_puts("bcl lav");
  1316.  
  1317. //----------------------------- BOUCLE LAVAGE ----------------------------------
  1318.  
  1319. timeOUT_lavage = false;
  1320. temps_lavage = 0; // le temps est incrementé par la procedure RTCtickMinute
  1321. sens_enable = true;
  1322. demarrage(0, OCRdemar);
  1323. do
  1324. {
  1325. detection_bouton_ROUGE();
  1326. detection_bouton_VERT();
  1327. detection_niveau_eau();
  1328.  
  1329. if (!NIV1)
  1330. {// si le niveau baisse, on complete;
  1331. remplissage_NIV1(30);
  1332. demarrage(0, OCRdemar);
  1333. sens_enable = true;
  1334. lcd_gotoxy_clrEOL(0,1); lcd_puts("LAVAGE "); lcd_puts(Nom_prg1);
  1335. }
  1336. asservissement_vitesse(P_cons_lav);
  1337.  
  1338. _delay_us(25);
  1339.  
  1340. if (affi_requis) { AFFICHAGES(); }
  1341. } while (!timeOUT_lavage && !vert);
  1342.  
  1343. vert = false;
  1344. //-------------------------------- FIN LAVAGE ----------------------------------
  1345.  
  1346. CHAUFFAGE_off();
  1347. chauffe_enable = false;
  1348.  
  1349. // lcd_gotoxy_clrEOL(0,0);
  1350. // lcd_gotoxy(3, 0);
  1351. // lcd_puts("fin lavage");
  1352.  
  1353. vitesse_mini(OCRmax);
  1354. sens_enable = false;
  1355. stop_imps = true;
  1356. _delay_ms(1000);
  1357. relais1_off();
  1358. relais2_off();
  1359. lavage = false;
  1360. lcd_clrscr();
  1361. }
  1362.  
  1363.  
  1364.  
  1365. void DEFOULER(void)
  1366. {
  1367. uint8_t n;
  1368. lcd_clrscr();
  1369. CHAUFFAGE_off();
  1370. EV2_off();
  1371. lcd_gotoxy_clrEOL(0,1);
  1372. lcd_puts("DEFOULAGE");
  1373. defoulage = true;
  1374. sens_enable = false;
  1375.  
  1376. demarrage(0, OCRdemar);
  1377.  
  1378. for (n=1; n<5; n++)
  1379. {
  1380. timeOUT_defoul = false;
  1381. temps_defoul = 0;
  1382. do
  1383. {
  1384. asservissement_vitesse(1200);
  1385. _delay_us(20);
  1386. } while (!timeOUT_defoul);
  1387.  
  1388. if (n < 4) { change_SENS(OCRdemar); }
  1389. }
  1390. vitesse_mini(OCRmax);
  1391. stop_imps = true;
  1392. _delay_ms(300);
  1393. relais1_off();
  1394. relais2_off();
  1395. defoulage = false;
  1396. lcd_gotoxy_clrEOL(0,1);
  1397. }
  1398.  
  1399.  
  1400. void ESSORER(void)
  1401. {
  1402. PORTA |= 0b01000000; // allume LED essorage
  1403. lcd_clrscr();
  1404. accelere = false;
  1405. // offset_OCR2 = 0;
  1406. CHAUFFAGE_off();
  1407. EV2_off();
  1408. lcd_gotoxy_clrEOL(0,1);
  1409. lcd_puts("ESSORAGE");
  1410.  
  1411. POMPE_on();
  1412. sens_enable = false;
  1413. demarrage(0, OCRdemar);
  1414.  
  1415.  
  1416. if (tps_essr_max > 5*60) { tps_essr_max = 5*60;} // securite
  1417. temps_essorage = 0;
  1418. essorage = true;
  1419.  
  1420. lcd_gotoxy_clrEOL(11,3);
  1421. lcd_puts("bcl ess");
  1422. // mdelay(1000);
  1423.  
  1424. timeOUT_ess = false;
  1425. accelere = true; // add_F_ess sera incremente chaque seconde par RTCTickSecond
  1426.  
  1427. // baseOCR2 = 130;
  1428. // offset_OCR2 = 0;
  1429.  
  1430. vitesse_mini(OCRdemar);
  1431. P_cons_ess = 1500; // vitesse tres lente au depart pour defouler
  1432. stop_imps = false;
  1433.  
  1434. //------------------------- boucle essorage ------------------------------------
  1435. do
  1436. {
  1437. detection_bouton_ROUGE();
  1438. detection_bouton_VERT();
  1439.  
  1440. if (vert)
  1441. { // coup d'accélération pour sauter manuellement la résonance
  1442. vert = false;
  1443. temps_essorage += 10;
  1444. }
  1445.  
  1446. asservissement_vitesse(P_cons_ess);
  1447. _delay_us(20);
  1448.  
  1449. if (affi_requis) { AFFICHAGES();}
  1450. } while (!timeOUT_ess);
  1451.  
  1452.  
  1453. vert = false;
  1454. //------------------------------------------------------------------------------
  1455. PORTA &= 0b10111111; // eteint LED essorage
  1456. lcd_clrscr();
  1457. lcd_puts("FIN ESSORAGE");
  1458.  
  1459. stop_imps = true;
  1460. vitesse_mini(OCRmax);
  1461.  
  1462. _delay_s(1);
  1463. relais1_off();
  1464. _delay_s(1);
  1465. relais2_off();
  1466. _delay_s(1);
  1467.  
  1468. _delay_s(15); // 15s de vidange supplementaires à la fin
  1469. POMPE_off();
  1470.  
  1471. vidange = false;
  1472. defoulage = false;
  1473. essorage = false;
  1474.  
  1475. lcd_gotoxy(0,1);
  1476. lcd_puts("Lessive terminee");
  1477.  
  1478. allume_LED(16);
  1479. while (1)
  1480. {
  1481. detection_bouton_ROUGE();
  1482. }
  1483. }
  1484.  
  1485.  
  1486.  
  1487. void VIDANGER(void)
  1488. {
  1489. lcd_gotoxy_clrEOL(0,1);
  1490. lcd_puts("VIDANGE");
  1491.  
  1492. chauffe_enable = false;
  1493. CHAUFFAGE_off();
  1494. vidange = true;
  1495.  
  1496. lcd_gotoxy_clrEOL(0,2);
  1497. lcd_puts("Pompe en marche");
  1498.  
  1499. POMPE_on();
  1500. affi_requis = false;
  1501.  
  1502. do
  1503. {
  1504. detection_bouton_ROUGE();
  1505. detection_niveau_eau();
  1506.  
  1507. if (affi_requis) // 1 fois par seconde
  1508. {
  1509. affi_requis = false;
  1510. lcd_gotoxy(2, 3);
  1511. lcd_puts( TXTniv);
  1512. }
  1513. } while (NIV1 || NIV2);
  1514.  
  1515.  
  1516. //octet_IR = 255;
  1517. // à partir de cet instant il faut encore au minimum 16s pour vider la cuve
  1518. // On fait donc tourner la pompe 20s supplémentaires
  1519. lcd_gotoxy_clrEOL(0,1);
  1520. lcd_puts("VIDANGE +");
  1521. lcd_gotoxy(2, 3);
  1522. lcd_puts(TXTniv);
  1523. _delay_s(20);
  1524.  
  1525. POMPE_off();
  1526. lcd_gotoxy_clrEOL(0,1);
  1527. vidange = false;
  1528. }
  1529.  
  1530.  
  1531. void remplissage_NIV1(uint16_t tps_plus) // par EV2
  1532. {
  1533. remplissage = true;
  1534. lcd_gotoxy_clrEOL(0,1);
  1535. lcd_puts("EAU");
  1536.  
  1537. vitesse_mini(OCRmax);
  1538. stop_imps = true;
  1539. sens_enable = false;
  1540. relais1_off();
  1541. relais2_off();
  1542. EV2_on();
  1543.  
  1544. do
  1545. {
  1546. detection_bouton_ROUGE();
  1547. detection_bouton_VERT();
  1548. detection_niveau_eau();
  1549.  
  1550. if (affi_requis) {AFFICHAGES();} // 1 fois par seconde
  1551.  
  1552. lcd_gotoxy(2, 3);
  1553. lcd_puts(TXTniv);
  1554. } while (!NIV1 && !NIV2 && !vert); // oui, NIV2 convient bien entendu.
  1555.  
  1556. vert = false;
  1557. if (octet_IR == 12) { PAUSER("3"); }
  1558. octet_IR = 255;
  1559. lcd_gotoxy_clrEOL(0,2);
  1560.  
  1561. lcd_puts("Remplissage +"); // un peu plus, pour eviter d'en reprendre un verre 10 fois de suite
  1562. _delay_s(tps_plus);
  1563.  
  1564. EV2_off();
  1565. lcd_clrscr();
  1566. remplissage = false;
  1567. }
  1568.  
  1569.  
  1570.  
  1571. void RINCER(uint8_t num_rincage)
  1572. {
  1573.  
  1574. rincage = true;
  1575. lcd_gotoxy_clrEOL(0,1);
  1576. lcd_puts("RINCAGE ");
  1577. lcd_aff_nb (num_rincage, 1, 0, 0 );
  1578. affiche_temperature(); //mesure ET affichage de la temperature (en position 8,3)
  1579.  
  1580. periode_ch_sens = 10;
  1581. chauffe_enable = false;
  1582. CHAUFFAGE_off();
  1583. temps_rincage = 0;
  1584.  
  1585. sens_enable = true;
  1586. demarrage(0, OCRdemar);
  1587.  
  1588. //---------------------------- boucle rincage ----------------------------------
  1589.  
  1590. lcd_gotoxy_clrEOL(11,3);
  1591. lcd_puts("bcl rin");
  1592.  
  1593. timeOUT_rincage = false;
  1594.  
  1595. do
  1596. {
  1597. detection_bouton_ROUGE();
  1598. detection_bouton_VERT();
  1599. detection_niveau_eau();
  1600. if (!NIV1)
  1601. {
  1602. remplissage_NIV1(30);
  1603. sens_enable = true;
  1604. demarrage(0, OCRdemar);
  1605. } // si le niveau baisse, on complete;
  1606.  
  1607. stop_imps = false;
  1608.  
  1609. asservissement_vitesse(P_cons_lav);
  1610. _delay_us(20);
  1611.  
  1612. if (affi_requis && !vert) { AFFICHAGES();}
  1613.  
  1614. } while (!timeOUT_rincage && !vert);
  1615.  
  1616. vert = false;
  1617. //------------------------------------------------------------------------------
  1618. vitesse_mini(OCRmax);
  1619. stop_imps = true;
  1620. sens_enable = false;
  1621.  
  1622. lcd_gotoxy_clrEOL(0,2);
  1623. lcd_puts("fin rincage");
  1624.  
  1625. _delay_s(1);
  1626. relais1_off();
  1627. relais2_off();
  1628. _delay_s(1);
  1629. rincage = false;
  1630. lcd_clrscr();
  1631.  
  1632. }
  1633.  
  1634.  
  1635. void PURGER(void) // mini essorage à la fin de la vidange afin de purger l'eau (et la lessive) du linge
  1636. {
  1637. // offset_OCR2:= 0;
  1638. CHAUFFAGE_off();
  1639. EV2_off();
  1640. lcd_gotoxy_clrEOL(0,1);
  1641. lcd_puts("PURGE");
  1642. POMPE_on();
  1643.  
  1644. sens_enable = false;
  1645. demarrage(0, OCRdemar);
  1646.  
  1647. temps_purge = 0;
  1648. P_cons_purge = 1500; // sera recalculé chaque seconde pour accélérer voir ligne 2088 (in fonction Event_1s)
  1649. purge = true;
  1650.  
  1651. //------------------------- boucle "esso-purge" --------------------------------
  1652. lcd_gotoxy_clrEOL(11,3);
  1653. lcd_puts("bcl purg");
  1654.  
  1655. timeOUT_purge = false;
  1656. stop_imps = false;
  1657. do
  1658. {
  1659. detection_bouton_ROUGE();
  1660. detection_bouton_VERT();
  1661. asservissement_vitesse(P_cons_purge);
  1662. _delay_us(20);
  1663.  
  1664. if (affi_requis) { AFFICHAGES();}
  1665. } while (!timeOUT_purge && !vert);
  1666.  
  1667. vert = false;
  1668. //------------------------------------------------------------------------------
  1669. stop_imps = true;
  1670. vitesse_mini(OCRdemar);
  1671.  
  1672. _delay_ms(1000);
  1673. relais1_off();
  1674. relais2_off();
  1675. _delay_ms(1000);
  1676.  
  1677. _delay_ms(10000); // 10s de vidange supplementaires à la fin
  1678. POMPE_off();
  1679. stop_imps = true;
  1680.  
  1681. vidange = false;
  1682. defoulage = false;
  1683. purge = false;
  1684. lcd_clrscr();
  1685. }
  1686.  
  1687.  
  1688.  
  1689.  
  1690.  
  1691. uint8_t regulation_TEMPERATURE(void)
  1692. // cette fonction est appellée uniquement par la fonction "affichages" chaque seconde (ligne 1232)
  1693. // si chauffe_enable == true
  1694. // allume le chauffage si la température est trop basse sinon l'éteint
  1695. {
  1696. if (Temperat_max > 80) { Temperat_max = 80;} // securite
  1697.  
  1698. affiche_temperature(); //mesure ET affichage de la temperature
  1699.  
  1700. if (T < (Temperat_max) ) // alors il faut chauffer!
  1701. {
  1702. CHAUFFAGE_on();
  1703. return 1;
  1704. }
  1705. else
  1706. {
  1707. CHAUFFAGE_off();
  1708. return 0;
  1709. }
  1710. return 2;
  1711. }
  1712.  
  1713.  
  1714. void CHAUFFER(void)
  1715. {
  1716. uint8_t chauffe;
  1717. uint8_t sens = 0;
  1718. if (Prg == froid) return;
  1719.  
  1720. lcd_gotoxy_clrEOL(0,1); lcd_puts("CHAUFFAGE "); lcd_puts(Nom_prg1);
  1721. affiche_temperature(); //mesure ET affichage de la temperature (en position 8,3)
  1722. stop_imps = true;
  1723. _delay_ms(1000);
  1724. relais1_off();
  1725. relais2_off();
  1726.  
  1727. do
  1728. {
  1729. // -------------------------------- CHAUFFAGE 60s ------------------------------
  1730. if ((NIV1 || NIV2) ) { chauffe_enable = true; } // CHAUFFAGE
  1731. else
  1732. {
  1733. chauffe_enable = false;
  1734. CHAUFFAGE_off();
  1735. return;
  1736. }
  1737. lcd_gotoxy_clrEOL(0,2); lcd_puts("boucle de chauffage");
  1738. timeOUT_chauffage = false;
  1739. temps_chauffage = 0;
  1740. do
  1741. { // on chauffe pendant 60s
  1742. detection_bouton_ROUGE();
  1743. detection_bouton_VERT();
  1744. chauffe = regulation_TEMPERATURE();
  1745. _delay_ms(50);
  1746. if (affi_requis) { AFFICHAGES(); }
  1747. } while ((!timeOUT_chauffage) && (chauffe == 1) && !vert);
  1748.  
  1749. vert = false;
  1750.  
  1751. CHAUFFAGE_off();
  1752.  
  1753. // -------------------------------- BRASSAGE ---------------------------------
  1754. if (chauffe == 1)
  1755. {
  1756. brassage = true;
  1757. lcd_gotoxy_clrEOL(0,2); lcd_puts("boucle de brassage");
  1758. temps_brassage_max = 8; // en secondes
  1759. timeOUT_brassage = false;
  1760. temps_brassage = 0; // le temps est incrementé par la procedure RTCtickMinute
  1761. sens_enable = false;
  1762. sens = 1-sens;
  1763. demarrage(sens, OCRdemar);
  1764. do
  1765. {
  1766. detection_bouton_ROUGE();
  1767. detection_bouton_VERT();
  1768. asservissement_vitesse(P_cons_lav);
  1769. _delay_us(25);
  1770. if (affi_requis) { AFFICHAGES(); }
  1771. } while (!timeOUT_brassage && !vert);
  1772.  
  1773. vert = false;
  1774.  
  1775. vitesse_mini(OCRmax);
  1776. stop_imps = true;
  1777. _delay_ms(1000);
  1778. relais1_off();
  1779. relais2_off();
  1780. brassage = false;
  1781. }
  1782. // ----------------------------------------------------------------------------
  1783. } while (chauffe == 1);
  1784.  
  1785. lcd_clrscr();
  1786. }
  1787.  
  1788.  
  1789.  
  1790.  
  1791.  
  1792. void choix_programme(void)
  1793. {
  1794. cli();
  1795. lcd_clrscr();
  1796. lcd_gotoxy(0, 0); lcd_puts("==== PROGRAMME: ====");
  1797. lcd_gotoxy(0, 1); lcd_puts("1:COUL-40 2:COUL-30");
  1798. lcd_gotoxy(0, 2); lcd_puts("3:LAINE-30 4:FROID ");
  1799. lcd_gotoxy(0, 3); lcd_puts("5:RAPIDE ");
  1800.  
  1801. do
  1802. {
  1803. detection_bouton_ROUGE();
  1804. interroge_IR();
  1805. } while ( (octet_IR!=1)&&(octet_IR!=2)&&(octet_IR!=3)&&(octet_IR!=4)&&(octet_IR!=5)&&(octet_IR!=12) );
  1806.  
  1807. switch (octet_IR)
  1808. {
  1809. case 1:
  1810. {
  1811. Prg = couleur;
  1812. strcpy(Nom_prg1, "Couleur40");
  1813. Temperat_max = 40;
  1814. duree_lavage = 15*60;
  1815. nb_rincage_max = 4;
  1816. tps_essr_max = 3*60;
  1817. }
  1818. break;
  1819.  
  1820. case 2:
  1821. {
  1822. Prg = blanc;
  1823. strcpy(Nom_prg1, "Couleur30");
  1824. Temperat_max = 30;
  1825. duree_lavage = 15*60;
  1826. nb_rincage_max = 4;
  1827. tps_essr_max = 3*60;
  1828. }
  1829. break;
  1830.  
  1831. case 3:
  1832. {
  1833. Prg = laine;
  1834. strcpy(Nom_prg1, "Laine");
  1835. Temperat_max = 30;
  1836. duree_lavage = 5*60;
  1837. nb_rincage_max = 4;
  1838. tps_essr_max = 1*60;
  1839. }
  1840. break;
  1841.  
  1842. case 4:
  1843. {
  1844. Prg = froid;
  1845. strcpy(Nom_prg1, "A froid");
  1846. Temperat_max = 0;
  1847. duree_lavage = 15*60;
  1848. nb_rincage_max = 4;
  1849. tps_essr_max = 2*60;
  1850. }
  1851. break;
  1852.  
  1853. case 5:
  1854. {
  1855. Prg = rapide;
  1856. strcpy(Nom_prg1, "Rapide");
  1857. Temperat_max = 0;
  1858. duree_lavage = 2*60;
  1859. nb_rincage_max = 2;
  1860. tps_essr_max = 1*60;
  1861. }
  1862. break;
  1863.  
  1864.  
  1865. case 12:
  1866. {
  1867. PAUSER("8");
  1868. }
  1869. break;
  1870. }
  1871. lcd_clrscr();
  1872. lcd_puts(Nom_prg1);
  1873. lcd_puts(" ");
  1874. lcd_aff_nb(Temperat_max, 2,0,0);
  1875. lcd_puts("deg ");
  1876. lcd_gotoxy(0, 1);
  1877. lcd_puts("5 prem. mn froid +");
  1878. lcd_gotoxy(0, 2);
  1879. lcd_puts("lavage ");
  1880. lcd_aff_nb(duree_lavage / 60, 2,0,0);
  1881. lcd_puts(" mn");
  1882.  
  1883. lcd_gotoxy(0, 3);
  1884. lcd_aff_nb (nb_rincage_max, 1, 0, 0 );
  1885. lcd_puts(" rincages ");
  1886. _delay_s(6);
  1887. lcd_clrscr();
  1888. temps_total = 0;
  1889. sei();
  1890. }
  1891.  
  1892.  
  1893. void numero_15(void) // ESSORAGE
  1894. {
  1895. numero = 15;
  1896. allume_LED(numero);
  1897. lcd_gotoxy(0, 0);
  1898. lcd_puts("numero ");
  1899. lcd_aff_nb (numero, 2, 0, 0 );
  1900.  
  1901. VIDANGER();
  1902. PURGER();
  1903. lcd_clrscr();
  1904. lcd_gotoxy(0, 0); lcd_puts("5 pour essorer");
  1905. lcd_gotoxy(0, 1); lcd_puts("bouton rouge = PAUSE");
  1906. while (octet_IR != 5)
  1907. {
  1908. detection_bouton_ROUGE();
  1909. interroge_IR();
  1910. }
  1911. DEFOULER();
  1912. ESSORER();
  1913. lcd_clrscr();
  1914. PAUSER("5");
  1915. }
  1916.  
  1917.  
  1918. void numero_14(void) // RINCAGE 4 facultatif
  1919. {
  1920. numero = 14;
  1921. allume_LED(numero);
  1922. lcd_gotoxy(0, 0);
  1923. lcd_puts("numero ");
  1924. lcd_aff_nb (numero, 2, 0, 0 );
  1925. RINCER(4);
  1926. num_requis = 15;
  1927. }
  1928.  
  1929.  
  1930. void numero_13(void)
  1931. {
  1932. numero = 13;
  1933. allume_LED(numero);
  1934. lcd_gotoxy(0, 0);
  1935. lcd_puts("numero ");
  1936. lcd_aff_nb (numero, 2, 0, 0 );
  1937. if (nb_rincage_max > 3)
  1938. {
  1939. remplissage_NIV1(45);
  1940. num_requis = 14;
  1941. } else {num_requis = 15;} // vers essorage
  1942. }
  1943.  
  1944.  
  1945. void numero_12(void)
  1946. {
  1947. numero = 12;
  1948. allume_LED(numero);
  1949. lcd_gotoxy(0, 0);
  1950. lcd_puts("numero ");
  1951. lcd_aff_nb (numero, 2, 0, 0 );
  1952. VIDANGER();
  1953. PURGER();
  1954. num_requis = 13;
  1955. }
  1956.  
  1957.  
  1958. void numero_11(void) // RINCAGE 3 facultatif
  1959. {
  1960. numero = 11;
  1961. allume_LED(numero);
  1962. lcd_gotoxy(0, 0);
  1963. lcd_puts("numero ");
  1964. lcd_aff_nb (numero, 2, 0, 0 );
  1965. RINCER(3);
  1966. num_requis = 12;
  1967. }
  1968.  
  1969.  
  1970. void numero_10(void)
  1971. {
  1972. numero = 10;
  1973. allume_LED(numero);