Machine CNC de phototraçage de typons par diode laser 405nm

Je vous décris ici ma réalisation (en cours) d'une petite CNC (Machine à commande numérique) de flashage par laser de typons pour la fabrication de circuits imprimés.


Attention : Ce projet peut comporter un danger. Selon la puissance et la longueur d’onde d’émission du laser, celui-ci peut représenter un réel danger pour la vue et provoquer des brûlures irréparables de la rétine. Le faisceau laser est dangereux dans l'axe, mais également en réflexion (sur une surface métallique par exemple). La rétine est irrémédiablement endommagée BIEN AVANT que le réflexe pupillaire n'ai pu intervenir. Les lunettes tintées "de protection" n'offrent qu'une protection (limitée) contre une diffusion du faisceau (si puissance faible, qq mW), mais PAS contre une réflexion. Les plus dangereux sont les lasers infra-rouge ou ultra-violet dont le rayon est invisible. Ce projet n’est donc présenté qu’à titre d’information. Voilà, il vous reste la possibilité de remplacer le laser par un stylo feutre "spécial circuit imprimé" ou une bonne LED + fibre optique (une "plume" optique).

Voici quelques photos de la machine proprement dite :
Cliquez sur une image ci-dessous pour visualiser l'album. Certaines sont commentées
Table des matières :
1 - Les grandes lignes du projet :
2 - Dessin du circuit imprimé : Le logiciel kicad
3 - Exportation du tracé au format gerber depuis Kicad
4 - Le fichier gerber obtenu :
5 - Les drivers pour moteur pas à pas : EasyDriver et carte Arduino Mega2560
6 - Le film photosensible à coller sur le cuivre :
7 - Ecriture du programme
8 - Principe du calcul des déplacement
9 - suite du calcul
10 - Le schéma :
11 - Le firmware pour carte Mega2560
12 - Le programme de pilotage en C++ & Qt4 pour le PC :
13 - Le code source du soft en Qt4 :
14 - Documents :
15 - Passage à un Arduino Mega2560
16 - Premier tracé d'un circuit
17 - Les choses se précisent
18 - L'ATmega est content !
19 - Optimisation du tracé
20 - Optimisation AUTOMATIQUE
21 - Remplissage des pastilles
22 - Le laser a remplacé le stylo !
23 - Le même tracé laser vu à la loupe :
24 - Le laser bleu-violet est en place
25 - Premier essai de flashage du film en place sur le cuivre
26 - Vue de plus près...
27 - Détails :
28 - Essai d'élargissement des pistes par défocalisation du laser :
29 - Remplacement de la diode laser par un modèle de 50mW :
30 - Nous sommes sur la bonne voie
31 - La buse
32 - Le dernier problème... ?
33 - On touche au but...
34 - Flashage du film
35 - Réglage de la focalisation
36 - Parfait ?
37 - Procédons méthodiquement
38 - La méthode était la bonne !
39 - Le circuit imprimé gravé :
40 - Les principaux composants CMS sont soudés :
41 - Pilotage de la luminosité de la diode laser
42 - Image miroir & trous débouchés
43 - Calcul du raccourcissement des pistes
44 - Résultat gravé :
45 - La platine driver terminée, opérationnelle
46 - Pilotage de la hauteur du laser
47 - ...et largeurs des pistes obtenues
48 - Pilotage de la luminosité du laser en fonction des largeurs de pistes
49 - Réalisation de la carte mère
50 - Test de la carte mère
51 - Flashage d'un circuit mixte (classique + cms) + plans de masse
52 - Flashage virtuel sur SDcard

1 Les grandes lignes du projet :

10 octobre 2014:

La table sur laquelle sera fixé le circuit se déplacera en x, et le laser la surplombant en y. Les déplacements seront réalisés par des moteurs pas-à-pas piloté par un arduino (et firmware open source) + interface moteurs.

Un logiciel perso (Open source) en C++ Qt4 interprétera le contenu d'un fichier vectoriel "gerber" obtenu directement avec le logiciel libre Open source Kicad de conception de circuits imprimés.

Une protection (écran) sérieuse contre les réflexions du laser (bleu-violet, dans le domaine visible donc) sera prévue dès le départ.

Le typon sera en fait directement un "negative dry film photoresist for PCB" laminé à chaud sur le cuivre de la plaque du circuit imprimé.

Le révélateur n'est autre que du carbonate de calcium (Na2CO3 = cristaux de soude = Lessive St Marc) vendus parfois à prix d'or pour cette utilisation. Attention : ne pas confondre avec la soude caustique (NaOH) dangereuse.

Cette machine offrant une précision de 1/100mm pour les déplacements du laser devrait permettre de pister directement des boîtiers SMD TQFP 48 au pas de 0.5mm et toute la cms 0805 voire 0603 tout en buvant le café.


2 Dessin du circuit imprimé : Le logiciel kicad

Je l'utilise sous Linux Mint17. Voici enfin une liste d'astuces que j'ai rédigée au fur et à mesure de mon utilisation de ce logiciel, depuis plusieurs années :

3 Exportation du tracé au format gerber depuis Kicad

Remarque : Il convient de placer "l'origine des coordonnées de perçage" (c'est dans le menu "Placer") dans le coin en bas à gauche du circuit afin que toutes les coordonnées des pistes et des pastilles soient positives.

4 Le fichier gerber obtenu :


Nous utiliserons directement le fichier gerber, optimisé pour le photo-traçage des circuits imprimés. Il décrit l'allumage, l'extinction, et le déplacement d'un spot lumineux de forme ronde ou rectangulaire le long de l'axe des pistes. Simple et efficace !

La piste, un moment envisagée, du passage par un fichier g-code (adapté aux machines CNC de détourage ) est abandonnée au profit de l'utilisation directe du fichier gerber. Le logiciel d'interprétation gerger ? je vais l'écrire moi-même.

Comme on peut le voir sur l'extrait ci-dessus, le fichier greber est un fichier texte, vectoriel, de description du tracé. La première partie du fichier définit des formes de bases (cercles de différents diamètres, carrés... nommées "apertures") puis vient la liste des opérations à effectuer qui sont essentiellement de trois sortes :
  • Déplacements de la plume sans rien tracer
  • Flashage des pastilles (par positionnement d'une forme de base à un endroit précis)
  • Tracés des pistes (par déplacement d'une forme de base, un cercle à priori...)
Dans la pratique c'est le rayon laser qui effectuera ces opérations sur la surface photosensible du film.


5 Les drivers pour moteur pas à pas : EasyDriver et carte Arduino Mega2560

Les drivers pour moteur pas à pas : (projet open source) J'ai choisi la carte Mega2560 pour son nombre important de Timers 16 bits indépendants et de ports d'E/S. J'ajouterai qu'il faut commander les entrées "enable" des cartes EasyDriver afin de couper le courant dans les moteurs lorsqu'ils sont à l'arrêt.

6 Le film photosensible à coller sur le cuivre :

Il s'agit de film NEGATIF : Le partie qui sera exposée aux UV (par le rayon laser qui trace directement les pistes) reste sur le cuivre, les surfaces non exposées seront dissoutes par le révélateur. En anglais vous devez trouver dans la description quelque chose comme ça :

"Negative acting (Means UV exposed area of film will stay on board) photoresist"

Je vous laisse deviner où l'on peut se le procurer.

Certains vendeurs de précisent pas si le film proposé est négatif ou positif, donc attention !

Le film en question est constitué de trois couches, seule celle prise en sandwich au centre est photosensible, les deux autres à l'extérieur sont des protections.

  • TRAVAILLER DANS LE NOIR ou en lumière rouge. Il faut tout d'abord retirer une des protections en la séparant des deux autres couches à l'aide de deux morceaux de ruban adhésif.
  • Ensuite placer la surface sensible qui n'est plus protégée sur le cuivre préalablement dégraissé , séché, (nickel !)
  • puis passer le tout dans une plastifieuse (éventuellement bricolée afin qu'elle chauffe suffisamment, 80 à 100 °C, je n'ai pas eu besoin de modifier la mienne, le circuit ressort à 84°C en trois passages).
  • Retirer la seconde couche de protection en tirant avec un bout de scotch dans un coin.
  • Ensuite insoler aux UV à travers un masque ou insoler directement au rayon laser 405nm (bleu-violet)
  • développer dans de la lessive St Marc (carbonate de calcium (Na2CO3 = "cristaux de soude" + eau tiède, 10g de cristaux dans un grand verre d'eau) - La partie non exposée du film va se barrer. Aider le cas échéant après une ou deux minutes avec une brosse à dents douce. Travailler en lumière rouge si possible.
  • rincer et sécher au sèche cheveux. Vérifier en pleine lumière et avec une bonne loupe (compte-fils par exemple).
Voici les documents qui vous expliquent tout ça mieux que moi (en anglais)

7 Ecriture du programme

6 novembre 2014:
Je suis en train d'écrire le programme en Qt4 (C++) qui analyse les fichiers gerber et qui envoie les commandes à la carte Arduino Mega2560.

Dans un premier temps je me suis intéressé à l'ordre dans lequel le tracé des pistes apparaît dans le fichier gerber. Voici ce que ça donne (en vidéo).

Il va falloir optimiser ça en ordonnant les lignes du fichier (1 ligne = 1 segment ou 1 pastille) afin de minimiser les déplacements inutiles de la plume. Au moins rassembler les différents segments d'un même "net", ce qui n'est pas le cas dans le fichier produit par Kicad.

Traceur Gerber from Silicium628 on Vimeo.



Voici ce qui fonctionne actuellement :
  • L'analyse des lignes gerber est ok, ça ne pose pas de problème particulier
  • Le programme en Qt4 dialogue correctement avec la carte Arduino en USB
  • La carte Arduino pilote correctement les drivers "EasyDriver"
Donc les choses avancent. Je vous tiens au courant.

8 Principe du calcul des déplacement

9 nov 2014

9 suite du calcul

Je travaille sur l'électronique (ajout de détecteurs de fin de course, sous forme d'optocoupleurs IR) ainsi que sur les softs (Qt4 pour le PC et C++ pour la carte Arduino). Je publierai tout ça très bientôt. Je viens de recevoir la diode laser, je vais donc pouvoir tester le flashage.

En attendant je vous donne une aperçu de mes cogitations: Il va falloir utiliser des timers 16bits afin d'obtenir une grande précision dans les déplacements. Problème : l'ATmega328 de la carte Arduino UNO ne possède qu'un seul timer 16 bits (le « timer1 »). Donc soit on utilise une carte plus performante (Mega2560 qui possède 4 timers 16 bits indépendants) soit on simule deux timers 16 bits logiciellement (par deux compteurs (de type uint16_t)incrémentés par l'interruption du timer.

10 Le schéma :

Comme vous pouvez le voir, je vais en fait utiliser une carte Mega2560. J'explique pourquoi plus bas, par ordre chronologique.

vendredi 14 novembre 2014:
La conception et la mise au point de la CNC me dévore (presque) tout mon temps libre, mais c'est passionnant !! Les choses avancent rapidement, tant côté mécanique qu'électronique et programmation (PC en Qt4 et Arduino en C++, oui plus+ plus+, il est en effet tout a fait possible de faire de la programmation orientée objet avec les Arduino, en fait avec le compilateur avr-gcc et donc de créer des objets ("class" en C++), ce que j'ai fait, et ça décuple la puissance de la partie logicielle ainsi que sa lisibilité).

Bien entendu je publierai tout ça en intégralité.

11 Le firmware pour carte Mega2560

CODE SOURCE en C++ pour l'Arduino
  1. /***************************
  2. gerber.ccp
  3. pour carte Arduino Mega2560
  4. pilote deux (ou trois) moteurs pas-a-pas d'une photoflasheuse + diode laser
  5. liaison USB au PC
  6. par Silicium628
  7. logiciel Libre Open Source
  8. ****************************/
  9.  
  10.  
  11. /****************************
  12. PRINCIPE DE LA MESURE DE POSITION
  13.  
  14. les moteurs pas-à-pas utilisés pour les déplacement en X et Y sont de modèles 200 pas/tour (1.8 deg/ pas)
  15.  
  16. moteur1.steps_par_tour = 200;
  17. moteur1.tours_par_mm = 2; // pas-de-vis 0.5mm (pour un diamètre M3)
  18. moteur1.impuls_par_step = 2; // de par la configuration de la carte "EasyDriver"
  19.  
  20. calcul du nb d'impulsions par 1/100mm :
  21.  
  22. 2 imp/pas * 200 pas/T * 2 T/mm = 800 imp/mm
  23. 800 imp/mm = 8 impulsions /centième de mm
  24.  
  25. Ce nombre 8 est un chiffre rond, un entier, ce qui va nous simplifier la vie !
  26.  
  27. si nous utilisons des "long" (long int = 32 bits = 4 octets, soit -2 147 483 648 à 2 147 483 647) pour compter ces impulsions
  28. nous pourrons controler les déplacements sur une distance de +/-2 147 483 647 / 800 = 2684354 mm = 2684 m = +/-2.7 km... ça devrait le faire !!
  29. remarque1 : l'utilisation de uint16_t (16 bits) = +/-32768 ne permettrait des déplacements que sur 32768/800 = +/-40mm ce qui n'est pas suffisant, la machine
  30. est prévue pour graver des circuits de 100*100mm
  31. remarque2 : des uint24_t (3 octets soit +/- 20m) conviendraient, mais c'est typiquement le truc à ne pas faire pour des tas de raisons (alignement sur avr 8 bits)
  32. qui provoquent la chute prématurée des cheveux.
  33.  
  34. *****************************/
  35.  
  36. // #include "WProgram.h"
  37. // #include <avr/power.h>
  38.  
  39. #include <Arduino.h>
  40. #include <avr/delay.h>
  41. #include <HardwareSerial.h>
  42. #include "../lib/step_motor6.cpp" // lib perso
  43.  
  44. #define bit_LED_rouge 0b00100000; // sur PORTA
  45. #define bit_LED_verte 0b01000000; // sur PORTA
  46. #define bit_buzzer 0b10000000; // sur PORTA
  47.  
  48. //#define bit_LED_blanche1 0b01000000; // sur PORTC - sert de stroboscope moteur1 (pour contrôle visuel de la position angulaire du moteur)
  49. //#define bit_LED_blanche2 0b10000000; // sur PORTC - sert de stroboscope moteur2 (pour contrôle visuel de la position angulaire du moteur)
  50.  
  51. #define bit_LASER 0b01000000; // sur PORTL
  52. #define bit_pointage_LASER 0b10000000; // sur PORTL - allume la diode laser avec une très faible intensité pour faire un pointage visuel
  53.  
  54.  
  55. const char *version = "18.2";
  56.  
  57.  
  58. String inputString = ""; // a string to hold incoming data
  59. String outputString = "";
  60. boolean stringComplete = false; // whether the string is complete
  61. char inChar;
  62.  
  63. /**
  64. struct aperture
  65. {
  66.   char forme; // = 'R' ou 'C'
  67.   uint16_t x;
  68.   uint16_t y; // peut eventuellement etre utilisé aussi dans le cas d'un cercle pour définir une éllipse...
  69. }
  70.   cette structure est utilisée par le soft en Qt4. Ici on va faire autrement, avec un tableau...
  71. **/
  72.  
  73. uint16_t apertures[40][3]; // apertures[i][0] -> x ; apertures[i][1] -> y; (x et y ne sont pas des positions mais des dimensions); apertures[i][2] -> 'R' ou 'C'
  74. uint8_t num_aperture;
  75. long ax, ay; // pour les dimensions des apertures; ce type "long" est rendu nécessire pour l'emploi d'un passage de paramètre par adresse dans la fonction "decode_xy_A()"
  76. char type_ap;
  77. uint8_t digits_ap[2];
  78.  
  79. Step_Motor moteur1; // moteur X (déplacements de la table)
  80. Step_Motor moteur2; // moteur Y (déplacements sur la potence)
  81. //Step_Motor moteur3; // = Z (déplacements verticaux de la plume (stylo ou focalisation du laser)) -> remplacé par un servo
  82. uint8_t etat_laser; // eteint=0 ; allumé=1;
  83. uint8_t blocage_laser=1;
  84. uint8_t n_octet;
  85. uint8_t etat_FC_x1, etat_FC_x2, etat_FC_y1, etat_FC_y2, etat_FC_z1;
  86. uint8_t fdc_envoi_fait =0;
  87. uint16_t cpt1=0;
  88.  
  89. uint16_t compteur1;
  90. uint16_t compteur2;
  91. uint16_t periode1;
  92. uint16_t periode2;
  93.  
  94. float fpx; // facteur periode x
  95. float fpy; // facteur periode y
  96.  
  97. uint16_t ocr3a_min; // pour moteur1
  98. uint16_t ocr3a_depart; // pour moteur1
  99. uint16_t ocr4a_min; // pour moteur2
  100. uint16_t ocr4a_depart; // pour moteur2
  101.  
  102. uint16_t base_ocr; // sera décrémenté par l'INT pour accélérer les 2 moteurs
  103. uint16_t base_ocr_depart; // determine la vitesse de rotation à la mise en rotation. La vitesse augmentera ensuite
  104. uint16_t base_ocr_min; // determine la vitesse max de rotation permise, voir les fonctions "ISR(TIMER3_COMPA_vect)" et "ISR(TIMER4_COMPA_vect)"
  105. uint16_t base_ocr_min2; // determine la vitesse max de rotation permise lors des "goto zero" et "goto safe pos"
  106.  
  107. uint8_t pas_mot1_demande; // drapeau permettant de déplacer le traitement de interruptions moteur dans vers la boucle principale, afin d'éviter les collisions d'interruption.
  108. uint8_t pas_mot2_demande;
  109.  
  110. uint8_t mm_par_s;
  111. uint8_t mm_par_s_max;
  112.  
  113. /*************************************************
  114. rappel1 :
  115. vis au pas de 0.5mm -> 2 tours /mm
  116. 2 imp/pas * 200 pas/tour * 2 tours/mm = 800 imp/mm
  117. 800 imp/mm = 8 impulsions /centième de mm
  118. **************************************************
  119. rappel2 :
  120. long = entier signé codé sur 32 bits = 4 octets
  121. **************************************************/
  122.  
  123. long x0, y0; // position actuelle en nb/impulsions moteur (plus exactement impulsions vers EasyDriver). (8 impulsions = 1/100 mm)
  124. //long x1, y1; // position à atteindre en nb/impulsions moteur (plus exactement impulsions vers EasyDriver). (8 impulsions = 1/100 mm)
  125. long d_impuls_x, d_impuls_y; // distances à parcourir en nb d'impulsions
  126.  
  127. /*
  128. Mémorisation numérique du tracé pour contôle sans tracé physique:
  129. la fréquence max envoyée aux cartes EasyDriver en vitesse rapide est = 2500Hz
  130. Si l'on veut mémoriser toutes les positions parcourues, chaque position étant définie par 2 x 4 octets = 8 octets,
  131. il faut 2500*8 = 20 000 octets/s (=160 kbits/s) (on voit déjà que la transmission à 115200 bauds ne suffit pas si l'on veut envoyer le résultat au PC en temps réel)
  132. si on veut mémoriser 1/2h de tracé, il faut 20 kB/s * 1800s = 36MB. -> la RAM du Mega2560 = 8kB soit 4500 fois moins !!! juste de quoi mémoriser 0,4s de tracé.
  133. utiliser un processeur ARM ? un Raspberry Pi2 quad core ?
  134. J'envisage une acquisition externe par un second ATmega connecté sur les sorties des signaux, qui mémoriserait dans une SDcard.
  135. */
  136.  
  137. long diff_x;
  138. long diff_y;
  139. int16_t erreur_X = 0; // en nb d'impulsions. Peut varier entre -200 et +200 (pour 0 à 360° d'angle moteur). Doit être = 0 si pas d'erreur.
  140. int16_t erreur_Y = 0; // en nb d'impulsions. Peut varier entre -200 et +200 (pour 0 à 360° d'angle moteur). Doit être = 0 si pas d'erreur.
  141.  
  142.  
  143. uint8_t largeur_plume = 5;
  144.  
  145. uint8_t digits_X[4];
  146. uint8_t digits_Y[4];
  147. uint8_t n;
  148. uint16_t nb_operations = 0;
  149.  
  150. uint8_t goto_en_cours_xy = 0; // dans le plan horizontal
  151. uint8_t goto_en_cours_z = 0; // concerne la hauteur de la plume
  152.  
  153. uint8_t raz_demande = 0;
  154. uint8_t acceleration_permise = 0;
  155. char msg_ret_gto[3]; // permet à la fonction goto d'envoyer plusieurs types de message en retour vers le PC, suivant la nature de son appel
  156.  
  157.  
  158. int16_t table_sinus[1024];
  159.  
  160.  
  161. void init_ports (void) // ports perso
  162. // 0 = entree, 1=sortie ; les 1 sur les pins en entrees activent les R de Pull Up (tirage à VCC)
  163. {
  164.  
  165.  
  166. PORTA = 0b00000000;
  167. DDRA = 0b11111111; // affichage LCD (ecran Nokia 5110) sur bits 0..4 + LEDS + Buzzer
  168.  
  169. PORTB = 0b00000000;
  170. DDRB = 0b11111111; // PB4 = OC2A = sortie PWM du Timer2 utilisé pour piloter la luminosité du laser
  171.  
  172. PORTC = 0b00000000;
  173. DDRC = 0b11111111; // PC0 et PC1 -> enables des moteurs ; PC6 et PC7 -> LEDS blanches stroboscopiques
  174.  
  175. PORTD = 0b00000000;
  176. DDRD = 0b11111100; // PD0 = entrée (=INT0) ; PD1 = entrée (=INT1)
  177.  
  178. PORTG = 0b00000000;
  179. DDRG = 0b11111111;
  180.  
  181. PORTK= 0b00000000; // ne PAS activer les R de Pull Up (tirage à VCC) sinon risque de ne pas detecter le rayon IR
  182. DDRK = 0b11100000; // entré des fin de course
  183.  
  184. PORTL= 0b00000000;
  185. DDRL = 0b11111111; // commandes des 2 moteurs (X, Y), de la diode laser et sortie PWM pour servomoteur(PL4)
  186. }
  187.  
  188.  
  189.  
  190. /**
  191. Info pour le Timer2 (8bits) : (Pb : on utilise ici les timers 3 et 4 (16 bits) )
  192. 20.4.2 (page:172 du datasheet ATmega2560)
  193.  
  194. Clear Timer on Compare Match (CTC) Mode
  195. In Clear Timer on Compare or CTC mode (WGM22:0 = 2), the OCR2A Register is used to manipulate the counter
  196. resolution. In CTC mode the counter is cleared to zero when the counter value (TCNT2) matches the OCR2A. The
  197. OCR2A defines the top value for the counter, hence also its resolution. This mode allows greater control of the
  198. compare match output frequency
  199. **/
  200.  
  201. /**
  202. Pour les timers 16 bits(3 et 4...) voir le tableau p:145
  203. Il faut mettre le bit WGMn2 à 1
  204. Pb: où est ce bit ???
  205. panique à bord...
  206. Voir le grand tableau "Register Summary" p:399
  207. ce qui permet de le localiser dans le registre TCCRnB - voir page 156
  208. **/
  209.  
  210.  
  211. /**
  212. void int_EXT_setup()
  213. {
  214. // voir 15. External Interrupts p:109
  215.  
  216.  
  217. // EICRA |= 0b00001010; // bits[1,0] = 10 -> int0 sur front descendant; bits[3,2] = 10 -> int1 sur front descendant; - p: 110
  218. // EICRA |= 0b00000101; // bits[1,0] = 10 -> int0 ; bits[3,2] = 10 -> int1 ; Any edge of INTn generates asynchronously an interrupt request - p: 110
  219. EICRA |= 0b00001111; //The rising edge of INTn generates asynchronously an interrupt request
  220. //je choisis "Any edge of INTn generates asynchronously an interrupt request" pour éviter de déclencher sur le mauvais sur rebonds.
  221. EIMSK |= 0b00000011; // bit[0]=1 -> INT0 enable ; bit[1]=1 -> INT1 enable - parag 15.2.3 EIMSK - p:111
  222. }
  223. **/
  224.  
  225.  
  226.  
  227. void timer2_setup()
  228. {
  229. // génère un signal PWM (luminosité du laser) - sortie sur PB4 (OC2A)
  230.  
  231. cli();
  232. //mode Fast PWM - voir p:184
  233. // WGM2 [2,1,0] = 011
  234. // WGM2[1,0] sont les bits [1,0] du registre TCCR2A - voir p:182
  235. /**
  236. Il faut mettre le bit WGM22 à 0
  237. Pb: où est ce bit ??? panique à bord...
  238. Voir le grand tableau "Register Summary" p:401
  239. ce qui permet de le localiser dans le registre TCCR2B et nous renvoie à la page 185
  240. WGM22 est donc le bit 3 du registre TCC2B
  241. * */
  242. // COM2A[1,0] = 1,0 - voir p:183 non inverting mode
  243. // COM2A[1,0] sont les bits [7,6] de TCCR2A - p:401 et p:182
  244. // sortie du signal sur pin OC2A ( pin PB4 = pin 23 du Mega2560)
  245. TCCR2A |= 0b10000011;
  246. TCCR2B = 0b11110010; // bit WGM22=1 et prescaler = 1/8 voir Table 20-9. (Clock Select Bit Description) p:185
  247.  
  248. OCR2A = 50;
  249. sei();
  250. }
  251.  
  252.  
  253.  
  254. void timer3_setup()
  255. // Pour générer les pas du moteur1 (axe X = déplacements de la table)
  256. {
  257. cli();
  258. TIMSK3 = 0b00000010; // Bit 1 – OCIE3A: Timer/Counter1, Output Compare A Match Interrupt Enable - p:161
  259.  
  260. TCCR3A = 0b00000000; // p:154
  261. TCCR3B = 0b00001010; // prescaler = 1/8 - CTC mode - p:156 et tableau p:157
  262.  
  263. OCR3A = ocr3a_depart; // compare match register - valeur la plus faible possible afin d'augmenter la fréquence primaire
  264. sei();
  265. }
  266.  
  267.  
  268. void timer4_setup()
  269. {
  270. // Pour générer les pas du moteur2 ((axe Y = déplacements ddu laser sur le portique)
  271.  
  272. cli();
  273. TIMSK4 = 0b00000010; // Bit 1 – OCIE4A: Timer/Counter3, Output Compare A Match Interrupt Enable
  274.  
  275. TCCR4A = 0b00000000; // p:154
  276. TCCR4B = 0b00001010; // prescaler = 1/8 - CTC mode - p:156 et tableau p:157
  277.  
  278. OCR4A = ocr4a_depart; // compare match register - valeur la plus faible possible afin d'augmenter la fréquence primaire
  279. sei();
  280. }
  281.  
  282.  
  283. void timer5_setup()
  284. {
  285. //pour piloter le servomoteur (type micro servo C141 Graupner) (hauteur du laser = réglage de la focalisation -> largeur du trait)
  286. // génère un signal PWM - sortie sur PL4 (OC5B)
  287. // mode15 = fast PWM - WGM[3,2,1,0] = 1111 - voir p:145
  288. // WGM[1,0] sont les bits [1,0] de TCCR5A - p:154
  289. // WGM[3,2] sont les bits [4,3] de TCCR5B - p:156
  290.  
  291. cli();
  292.  
  293. TIMSK5 = 0b00000000; // p:162
  294. // TCCR5A = (TCCR5A & 0xCC) | _BV(COM5B1) | _BV(WGM10); // fast PWM 8-bit, sortie sur pin OC5b
  295.  
  296. //mode7 = Fasr PWM, 10 bits -> WGM[2,1,0] = 111
  297. TCCR5A = 0b00100011;
  298. // bits[5,4] = COM5B[1,0] = compare output mode = 10 select-> canal B (sortie sur pin OC5b) - p:144, 146, 154, 155
  299. // bits[1,0] = WGM[1,0] = 11 -> Clear OCnA/OCnB/OCnC on compare match, set OCnA/OCnB/OCnC at BOTTOM (non-inverting mode) - p:154 et p:155 - et tableau des modes p:145
  300.  
  301. TCCR5B = 0b00001100; // prescaler = 1/256 - tableau p:157
  302. // bit[4,3] = WGM[3,2]
  303. // bit[2,1,0] = CS[2,1,3] (clock selection)
  304.  
  305. TCCR5C = 0;
  306.  
  307. OCR5B = 140; // largeur impulsion min=50 ; max=145 -> [0,8ms..2,4ms]
  308. sei();
  309. }
  310.  
  311.  
  312.  
  313. void beep()
  314. {
  315. uint8_t n;
  316. for (n=0; n<255; n++)
  317. {
  318. PORTA ^= bit_buzzer;
  319. _delay_us(300);
  320. }
  321. }
  322.  
  323.  
  324. void n_beep(uint8_t n)
  325. {
  326. uint8_t i;
  327. for (i=0; i<n; i++)
  328. {
  329. beep();
  330. _delay_ms(50);
  331. }
  332. }
  333.  
  334.  
  335. void laser_on()
  336. {
  337. if (blocage_laser == 0)
  338. {
  339. PORTL |= bit_LASER;
  340. etat_laser=1;
  341. }
  342. }
  343.  
  344.  
  345. void laser_off()
  346. {
  347. PORTL &= ~bit_LASER;
  348. etat_laser=0;
  349. }
  350.  
  351.  
  352. void laser_bloque()
  353. {
  354. laser_off();
  355. etat_laser=0;
  356. blocage_laser=1;
  357. }
  358.  
  359. void laser_debloque()
  360. {
  361. laser_off();
  362. etat_laser=0;
  363. blocage_laser=0;
  364. }
  365.  
  366.  
  367. void laser_set_lum(uint8_t lum)
  368. {
  369. OCR2A = lum;
  370. }
  371.  
  372.  
  373. void laser_set_Z(uint16_t z)
  374. {
  375. OCR5B = z;
  376. }
  377.  
  378.  
  379.  
  380. uint16_t calcul_rapide_periode_x(uint16_t base)
  381. {
  382. float px;
  383. px = 1000.0 * (float)base * fpx;
  384. if (px > 0xFFFF) {px = 0xFFFF;}
  385. return (int) px;
  386. }
  387.  
  388.  
  389. uint16_t calcul_rapide_periode_y(uint16_t base)
  390. {
  391. float py;
  392. py = 1000.0 * (float)base * fpy;
  393. if (py > 0xFFFF) {py = 0xFFFF;}
  394. return (int) py;
  395. }
  396.  
  397.  
  398. /**
  399. ISR(INT0_vect )
  400. {
  401. // interruption externe déclenchée par le disque à fente sur l'axe moteur X + opto-switch
  402. PORTA ^= bit_LED_verte;
  403. if(moteur1.get_sens() == 0) { erreur_X = 226 - moteur1.position_impuls % 400; } else { erreur_X = 189 - moteur1.position_impuls % 400; } // 18 = largeur fente...
  404. }
  405. **/
  406.  
  407.  
  408. /**
  409. ISR(INT1_vect )
  410. {
  411. // interruption externe déclenchée par le disque à fente sur l'axe moteur Y + opto-switch
  412. PORTA ^= bit_LED_verte;
  413. if(moteur2.get_sens() == 0) { erreur_Y = 211 - moteur2.position_impuls % 400; } else { erreur_Y = 198 - moteur2.position_impuls % 400; } // 18 = largeur fente...
  414. }
  415. **/
  416.  
  417.  
  418.  
  419.  
  420.  
  421. /**
  422. Le code exécuté par la RA1 du flag 'pas_mot1_demande' sera executé dans la boucle principale et/ou dans les boucles des goto_xy, mais pas dans l'interruption elle-même
  423. ceci afin d'éviter les problèmes de collision d'interruption
  424. Ces interruptions (qui codent des 'cli durant leur exécution' interdisant l'autre int) peuvent ainsi rendre la main le plus rapidement possible
  425. voir les fonctions 'pas_mot1' et 'pas_mot2'
  426. **/
  427.  
  428. ISR(TIMER3_COMPA_vect) // MOTEUR 1
  429. {
  430. if (moteur1.get_marche() == 1) { pas_mot1_demande +=1; }
  431. }
  432.  
  433.  
  434. ISR(TIMER4_COMPA_vect) // MOTEUR 2
  435. {
  436. if (moteur2.get_marche() == 1) { pas_mot2_demande +=1; }
  437. }
  438.  
  439.  
  440.  
  441. /*
  442. ISR(TIMER5_COMPA_vect)
  443. {
  444.  
  445.  
  446. }
  447. */
  448.  
  449.  
  450. int calcul_periode_deplacement(long x1_i, long y1_i, long x2_i, long y2_i)
  451. {
  452. float dx, dy, dx2, dy2, v0, px, py, dt; // vx, vy,
  453.  
  454. v0=1;
  455.  
  456. if (x2_i >= x1_i) { dx=x2_i-x1_i; moteur1.set_sens(0); } else { dx=x1_i-x2_i; moteur1.set_sens(1); }
  457. if (y2_i >= y1_i) { dy=y2_i-y1_i; moteur2.set_sens(0); } else { dy=y1_i-y2_i; moteur2.set_sens(1); }
  458.  
  459. if ( (x2_i == x1_i) && (y2_i == y1_i) ) // les points sont confondus, le ds est nul
  460. {
  461. OCR3A = ocr3a_depart;
  462. OCR4A = ocr4a_depart;
  463. return(1); // pour éviter les divisions par zéro plus bas
  464. }
  465.  
  466. dx2=dx*dx; // dx²
  467. dy2=dy*dy; // dy²
  468. dt = (sqrt(dx2+dy2))/v0;
  469.  
  470. //vx= dx/dt;
  471. //vy= dy/dt;
  472.  
  473. px = 600000.0 * ((float) mm_par_s_max / (float) moteur1.impuls_par_mm) * dt/dx; // 400000.0
  474. py = 600000.0 * ((float) mm_par_s_max / (float) moteur2.impuls_par_mm) * dt/dy; // 400000.0
  475.  
  476. if (px > 0xFFFF) {px = 0xFFFF;}
  477. if (py > 0xFFFF) {py = 0xFFFF;}
  478.  
  479. OCR3A = (int) px;
  480. OCR4A = (int) py;
  481.  
  482. return(0);
  483. }
  484.  
  485.  
  486.  
  487. void envoi_FDC()
  488. {
  489. Serial.println("FIN DE COURSE");
  490. }
  491.  
  492.  
  493.  
  494. int lecture_fins_de_course_xy() // xy, et pas z
  495. {
  496. // lecture de l'etat des capteurs (optiques) de fin de course et activations des blocages logiciels correspondants
  497. etat_FC_x1 = PINK & moteur1.bit_finCourse1; if (etat_FC_x1 != 0) { moteur1.set_stop_sens1(1); } else { moteur1.set_stop_sens1(0); }
  498. etat_FC_x2 = PINK & moteur1.bit_finCourse2; if (etat_FC_x2 != 0) { moteur1.set_stop_sens2(1); } else { moteur1.set_stop_sens2(0); }
  499.  
  500. etat_FC_y1 = PINK & moteur2.bit_finCourse1; if (etat_FC_y1 != 0) { moteur2.set_stop_sens1(1); } else { moteur2.set_stop_sens1(0); }
  501. etat_FC_y2 = PINK & moteur2.bit_finCourse2; if (etat_FC_y2 != 0) { moteur2.set_stop_sens2(1); } else { moteur2.set_stop_sens2(0); }
  502.  
  503. //etat_FC_z1 = PINK & moteur3.bit_finCourse1; if (etat_FC_z1 != 0) { moteur3.set_stop_sens2(1); } else { moteur3.set_stop_sens2(0); }
  504.  
  505. //if ((etat_FC_x1 != 0)||(etat_FC_x2 != 0)||(etat_FC_y1 != 0)||(etat_FC_y2 != 0)||(etat_FC_z1 != 0))
  506. if ((etat_FC_x1 != 0)||(etat_FC_x2 != 0)||(etat_FC_y1 != 0)||(etat_FC_y2 != 0))
  507. {
  508. if ( ((PORTA & 32) == 0) && (fdc_envoi_fait == 0) )
  509. {
  510. envoi_FDC();
  511. fdc_envoi_fait = 1;
  512. } // si la led était éteinte, on signale le changement d'état au soft Qt4 ;
  513. // REMARQUE on lit l'état d'un port conf en sortie, ce qui est tout à fait possible, on lit ce qu'on y a écrit précédemment...
  514.  
  515. PORTA |= bit_LED_rouge;
  516. return 1;
  517. }
  518. else
  519. {
  520. PORTA &= ~bit_LED_rouge;
  521. fdc_envoi_fait == 0;
  522. }
  523. return 0;
  524. }
  525.  
  526.  
  527.  
  528. void pas_mot1()
  529. {
  530. // la fréquence max du signal envoyé à la carte EasyDriver (lors d'un goto_origine par exemple) est de 2500Hz.
  531.  
  532. if (acceleration_permise ==1)
  533. {
  534. if (OCR3A > ocr3a_min)
  535. {
  536. compteur1++;
  537. compteur1=0;
  538. OCR3A -=1;
  539. }
  540. }
  541. cli();
  542. moteur1.step();
  543. sei();
  544.  
  545. //if ((goto_en_cours_xy == 1) && ( moteur1.get_compteur_impuls() >= d_impuls_x )) {moteur1.set_marche(0); } // ARRET
  546. //if (moteur1.position_impuls % 400 == 0 ) {PORTC |= bit_LED_blanche1; } else {PORTC &= ~bit_LED_blanche1; }
  547.  
  548. }
  549.  
  550.  
  551. void pas_mot2()
  552. {
  553. if (acceleration_permise ==1)
  554. {
  555. if (OCR4A > ocr4a_min)
  556. {
  557. compteur2++;
  558. compteur2=0;
  559. OCR4A -=1;
  560. }
  561. }
  562. cli();
  563. moteur2.step();
  564. sei();
  565.  
  566. //if ((goto_en_cours_xy == 1) && ( moteur2.get_compteur_impuls() >= d_impuls_y )) {moteur2.set_marche(0); }
  567. //if (moteur2.position_impuls % 400 == 0 ) {PORTC |= bit_LED_blanche2; } else {PORTC &= ~bit_LED_blanche2; }
  568. }
  569.  
  570.  
  571.  
  572. void envoi_PRET(long xi, long yi)
  573. {
  574. // ATTENTION : cette fonction envoi le signal qui déclenche en retour l'envoi de la commande suivante par le prog Qt4.
  575. // Donc ne pas l'appeler inconsidérement ! en particulier pas avant que l'éxécution de la commande en cours soit terminée.
  576. // en particulier pas dans une sous-fonction de la commande en cours (comme "laser_set_lum" par exemple)
  577.  
  578. unsigned char r ;
  579. // char msg_position[20]="0123456789012345678"; // 19 car max pour un string20
  580. char msg_position[20]="X+0000Y+0000 PRET "; // 19 car max pour un string20
  581. char signe_x, signe_y;
  582.  
  583. int i, fdc;
  584. long valeur;
  585.  
  586. fdc = lecture_fins_de_course_xy();
  587.  
  588. msg_position[0]='X';
  589. if (xi >=0) {valeur = xi/8; signe_x ='+';} else {valeur = -xi/8; signe_x ='-';}
  590. msg_position[1]=signe_x;
  591. for (i=0; i<4; i++)
  592. {
  593. r=48 + valeur % 10; // modulo (reste de la division)
  594. valeur /= 10; // quotient
  595. msg_position[5-i]=r;
  596. }
  597.  
  598. msg_position[7]='Y';
  599. if (yi >=0) {valeur = yi/8; signe_y ='+';} else {valeur = -yi/8; signe_y ='-';}
  600. msg_position[7]=signe_y;
  601. for (i=0; i<4; i++)
  602. {
  603. r=48 + valeur % 10; // modulo (reste de la division)
  604. valeur /= 10; // quotient
  605. msg_position[11-i]=r;
  606. }
  607.  
  608. if (fdc == 1)
  609. {
  610. msg_position[11]=' '; msg_position[12]='F'; msg_position[13]='I'; msg_position[14]='N'; msg_position[15]='C';
  611. }
  612.  
  613. nb_operations ++;
  614. _delay_ms(300);
  615. Serial.println(msg_position);
  616. }
  617.  
  618.  
  619. void envoi_diff_xy()
  620. {
  621. unsigned char r ;
  622. // char msg_erreur[20]="0123456789012345678"; // 19 car max pour un string20
  623. char msg_diff[20]="difX= 000 difY= 000"; // 19 car max pour un string20
  624. char signe_x, signe_y;
  625.  
  626. int i;
  627. uint16_t valeurX, valeurY;
  628.  
  629. valeurX = abs(diff_x);
  630. if (diff_x >=0) {valeurX = diff_x; signe_x ='+';} else {valeurX = -diff_x; signe_x ='-';}
  631. msg_diff[5]=signe_x;
  632. for (i=0; i<3; i++)
  633. {
  634. r=48 + valeurX % 10; // modulo (reste de la division)
  635. valeurX /= 10; // quotient
  636. msg_diff[8-i]=r;
  637. }
  638.  
  639. valeurY = abs(diff_y);
  640. if (diff_y >=0) {valeurY = diff_y; signe_y ='+';} else {valeurY = -diff_y; signe_y ='-';}
  641. msg_diff[15]=signe_y;
  642. for (i=0; i<3; i++)
  643. {
  644. r=48 + valeurY % 10; // modulo (reste de la division)
  645. valeurY /= 10; // quotient
  646. msg_diff[18-i]=r;
  647. }
  648.  
  649. _delay_ms(100);
  650. Serial.println(msg_diff);
  651.  
  652. }
  653.  
  654.  
  655.  
  656. void envoi_pos()
  657. {
  658. unsigned char r ;
  659. // char msg_erreur[20]="0123456789012345678"; // 19 car max pour un string20
  660. char msg_pos[20]="-------------------"; // 19 car max pour un string20
  661.  
  662. int i;
  663. long valeurX, valeurY;
  664.  
  665. valeurX = moteur1.position_impuls;
  666. for (i=0; i<10; i++)
  667. {
  668. r=48 + valeurX % 10; // modulo (reste de la division)
  669. valeurX /= 10; // quotient
  670. msg_pos[10-i]=r;
  671. }
  672. /*
  673. valeurY = moteur2.position_impuls;
  674. for (i=0; i<3; i++)
  675. {
  676. r=48 + valeurY % 10; // modulo (reste de la division)
  677. valeurY /= 10; // quotient
  678. msg_pos[18-i]=r;
  679. }
  680. */
  681. _delay_ms(100);
  682. Serial.println(msg_pos);
  683.  
  684. }
  685.  
  686.  
  687. void test_fin_goto(long xi, long yi)
  688. {
  689. //uint8_t n;
  690. // teste si la destination est atteinte, si oui stoppe le ou les moteurs.
  691. // la valeur du "msg_ret_gto" déterminera plus précisément le comportement de cette fonction
  692.  
  693. // if ((goto_en_cours_xy == 1) && ( moteur1.get_compteur_impuls() >= d_impuls_x )) {moteur1.set_marche(0); }
  694. // if ((goto_en_cours_xy == 1) && ( moteur2.get_compteur_impuls() >= d_impuls_y )) {moteur2.set_marche(0); }
  695.  
  696.  
  697. if (moteur1.get_sens() == 0) { if (moteur1.position_impuls >= xi) { moteur1.set_marche(0); } }
  698. else { if (moteur1.position_impuls <= xi) { moteur1.set_marche(0); } }
  699.  
  700. if (moteur2.get_sens() == 0) { if (moteur2.position_impuls >= yi) { moteur2.set_marche(0); } }
  701. else { if (moteur2.position_impuls <= yi) { moteur2.set_marche(0); } }
  702.  
  703.  
  704. if ((goto_en_cours_xy == 1) && (moteur1.get_marche() == 0) && (moteur2.get_marche() == 0) )
  705. { // FIN DU GOTO si LES DEUX coordonnées x ET y sont atteintes.
  706.  
  707. goto_en_cours_xy = 0;
  708. laser_off();
  709.  
  710.  
  711. //POUR TEST ***********************************************************
  712. // envoi_pos(); // test ok, les coordonnées sont bonne, pourtant il manque des impulsion lors de déplacements doubles (les 2 mot en marche) vers l'origine
  713. //**********************************************************************
  714.  
  715. x0 = moteur1.position_impuls;
  716. y0 = moteur2.position_impuls;
  717.  
  718. if (raz_demande)
  719. {
  720. moteur1.RAZ_pos();
  721. moteur2.RAZ_pos();
  722. x0=0; y0=0;
  723. raz_demande = 0;
  724. }
  725.  
  726. //----------------------------------------------------------------------
  727. if ( (msg_ret_gto[0]=='T') && (msg_ret_gto[1]=='S') && (msg_ret_gto[2]=='G') ) // fin du tracé de segment
  728. {
  729. laser_off();
  730.  
  731. _delay_ms(10); // frein (immobilisation le courant est maintenu sans impulsions)
  732. moteur1.disable(); // stop courant
  733. moteur2.disable();
  734.  
  735. envoi_PRET(x0, y0);
  736. }
  737. //----------------------------------------------------------------------
  738. if (msg_ret_gto[0]=='L') // fin du tracé demandé en local
  739. {
  740. _delay_ms(10); // frein (immobilisation, le courant est maintenu sans impulsions)
  741. moteur1.disable(); // stop courant
  742. moteur2.disable();
  743. }
  744. //----------------------------------------------------------------------
  745. if (msg_ret_gto[0]=='S') // fin du tracé de segment sans delai de freinage (pour tracer les nombreux segments des pastilles rondes)
  746. {
  747. ;
  748. }
  749.  
  750. //----------------------------------------------------------------------
  751. if ( (msg_ret_gto[0]=='-') && (msg_ret_gto[1]=='X') && (msg_ret_gto[2]=='Y') )
  752. {
  753. _delay_ms(5);
  754. envoi_PRET(x0, y0);
  755. } // fin du goto plume levée
  756.  
  757. //----------------------------------------------------------------------
  758. if ( (msg_ret_gto[0]=='Z') && (msg_ret_gto[1]=='0') && (msg_ret_gto[2]=='0') ) // fin du goto ZERO (origine XY)
  759. {
  760. laser_off();
  761. n_beep(3);
  762. moteur1.disable(); // stop courant
  763. moteur2.disable();
  764. envoi_PRET(x0, y0);
  765. }
  766. //----------------------------------------------------------------------
  767. if (msg_ret_gto[0]=='P') // fin du tracé d'une pastille
  768. {
  769. laser_off();
  770.  
  771. _delay_ms(10); // frein (immobilisation le courant est maintenu sans impulsions)
  772. moteur1.disable(); // stop courant
  773. moteur2.disable();
  774. envoi_PRET(x0, y0);
  775. }
  776. }
  777.  
  778. }
  779.  
  780.  
  781.  
  782.  
  783. void goto_xy(long xi, long yi)
  784. {
  785. acceleration_permise = 0;
  786. int r = calcul_periode_deplacement(x0, y0, xi, yi); // fixe également le sens de rotation
  787.  
  788. // remarque :labs est la version pour les entiers "long" de abs.
  789. // d_impuls_x = labs(xi-x0); // longueur du segment en x. Non signé. servira à détecter la fin du trajet. précis à 1 impulsion près, soit (1/100mm)/8
  790. // d_impuls_y = labs(yi-y0); // longueur du segment en y. Non signé. servira à détecter la fin du trajet.
  791.  
  792. // moteur1.RAZ_compteur_impuls(); // servira à mesurer la distance parcourue exactement à une impulsion près.
  793. // moteur2.RAZ_compteur_impuls();
  794.  
  795. moteur1.enable();
  796. moteur2.enable();
  797. moteur1.set_marche(1);
  798. moteur2.set_marche(1);
  799.  
  800. goto_en_cours_xy = 1;
  801.  
  802. while (goto_en_cours_xy == 1)
  803. {
  804. lecture_fins_de_course_xy();
  805. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; _delay_us(1);} // rotation de 1 pas du moteur1 (x)
  806. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; _delay_us(1);} // rotation de 1 pas du moteur2 (y)
  807. test_fin_goto(xi, yi); // le goto s'arretera lorsque position_impuls == (xi, yi)
  808. }
  809. }
  810.  
  811.  
  812.  
  813. void X_plus_mm(long valeur)
  814. {
  815. long n, n_max;
  816.  
  817. n_max = moteur1.impuls_par_mm * valeur;
  818.  
  819. moteur1.set_sens(0);
  820. moteur1.enable();
  821. for (n=0; n<n_max; n++)
  822. {
  823. lecture_fins_de_course_xy();
  824. moteur1.step();
  825. _delay_us(1200);
  826. }
  827. moteur1.disable();
  828.  
  829. x0 = moteur1.position_impuls;
  830. y0 = moteur2.position_impuls;
  831. envoi_PRET(x0, y0);
  832. }
  833.  
  834.  
  835. void X_moins_mm(long valeur)
  836. {
  837. long n, n_max;
  838.  
  839. n_max = moteur1.impuls_par_mm * valeur;
  840.  
  841. moteur1.set_sens(1);
  842. moteur1.enable();
  843. for (n=0; n<n_max; n++)
  844. {
  845. lecture_fins_de_course_xy();
  846. moteur1.step();
  847. _delay_us(1200);
  848. }
  849. moteur1.disable();
  850.  
  851. x0 = moteur1.position_impuls;
  852. y0 = moteur2.position_impuls;
  853. envoi_PRET(x0, y0);
  854. }
  855.  
  856.  
  857. void rotX_n_pas(long valeur)
  858. {
  859. long n, n_max;
  860.  
  861. n_max = valeur;
  862. moteur1.set_sens(1);
  863. moteur1.enable();
  864.  
  865. for (n=0; n<n_max; n++)
  866. {
  867. lecture_fins_de_course_xy();
  868. moteur1.step();
  869. _delay_us(1200);
  870. }
  871. moteur1.disable();
  872. }
  873.  
  874.  
  875. void rotY_n_pas(long valeur)
  876. {
  877. long n, n_max;
  878.  
  879. n_max = valeur;
  880.  
  881. moteur2.set_sens(0);
  882. moteur2.enable();
  883.  
  884. for (n=0; n<n_max; n++)
  885. {
  886. lecture_fins_de_course_xy();
  887. moteur2.step();
  888. _delay_us(1800);
  889. }
  890. moteur2.disable();
  891. }
  892.  
  893.  
  894. void Y_plus_mm(uint8_t valeur)
  895. {
  896. uint16_t n, n_max;
  897.  
  898. n_max = moteur2.impuls_par_mm * valeur;
  899.  
  900. moteur2.set_sens(0);
  901. moteur2.enable();
  902. for (n=0; n<n_max; n++)
  903. {
  904. lecture_fins_de_course_xy();
  905. moteur2.step();
  906. _delay_us(1200);
  907. }
  908. moteur2.disable();
  909.  
  910. x0 = moteur1.position_impuls;
  911. y0 = moteur2.position_impuls;
  912. _delay_ms(100);
  913. envoi_PRET(x0, y0);
  914.  
  915. }
  916.  
  917.  
  918. void Y_moins_mm(uint8_t valeur)
  919. {
  920. uint16_t n, n_max;
  921.  
  922. n_max = moteur2.impuls_par_mm * valeur;
  923.  
  924. moteur2.set_sens(1);
  925. moteur2.enable();
  926. for (n=0; n<n_max; n++)
  927. {
  928. lecture_fins_de_course_xy();
  929. moteur2.step();
  930. _delay_us(1200);
  931. }
  932. moteur2.disable();
  933.  
  934. x0 = moteur1.position_impuls;
  935. y0 = moteur2.position_impuls;
  936. _delay_ms(100);
  937. envoi_PRET(x0, y0);
  938.  
  939. }
  940.  
  941.  
  942.  
  943.  
  944.  
  945.  
  946. void envoi_nombre(uint16_t valeur) // valeur = 0..9999
  947. {
  948. // char msg_nbr[20]="0123456789012345678"; // 19 car max pour un string20
  949. char msg_nbr[20]=" "; // 19 car max pour un string20
  950.  
  951. uint8_t i, r;
  952. for (i=0; i<4; i++)
  953. {
  954. r=48 + valeur % 10; // modulo (reste de la division)
  955. valeur /= 10; // quotient
  956. msg_nbr[5-i]=r;
  957. }
  958. _delay_ms(300);
  959. Serial.println(msg_nbr);
  960. }
  961.  
  962.  
  963. /**
  964. void envoi_texte(char *txt, int lg) // txt = 19 caract max
  965. {
  966. // char msg_nbr[20]="0123456789012345678"; // 19 car max pour un string20
  967. char msg_txt[20]=" "; // 19 car max pour un string20
  968.  
  969. uint8_t i;
  970. for (i=0; i<=lg; i++)
  971. {
  972. msg_txt[i]=txt[i];
  973. }
  974. Serial.println(msg_txt);
  975. _delay_ms(300);
  976. }
  977. **/
  978.  
  979.  
  980.  
  981. void ajout_aperture(uint8_t num, char type)
  982. {
  983. if (num < 40)
  984. {
  985. apertures [num][0] = ax;
  986. apertures [num][1] = ay;
  987. apertures [num][2] = type; // "C" ou "R" ou "O"
  988. }
  989. envoi_PRET(x0, y0);
  990.  
  991. }
  992.  
  993.  
  994.  
  995. void RAZ_POS()
  996. {
  997. moteur1.RAZ_pos();
  998. moteur2.RAZ_pos();
  999. x0=0;
  1000. y0=0;
  1001. }
  1002.  
  1003.  
  1004. void STOP()
  1005. {
  1006. laser_off();
  1007. moteur1.set_marche(0);
  1008. moteur2.set_marche(0);
  1009. moteur1.disable(); // stop courant
  1010. moteur2.disable();
  1011. //PORTA &= ~bit_LED_verte;
  1012. goto_en_cours_xy = 0; // le cas échéant...
  1013. envoi_PRET(x0, y0);
  1014. }
  1015.  
  1016.  
  1017.  
  1018. void rotation_2k_pi()
  1019. {
  1020. // fait tourner les axes pour les orienter toujours à 2k pi près (pour test visuel de dérives éventuelles de positions)
  1021. // rappel : 2pi radians = 1 tour = 400 pas.
  1022. long n0;
  1023. long n, n_max;
  1024.  
  1025. n0 = moteur1.position_impuls;
  1026. n_max = 400 - (n0 % 400); // modulo (reste de la division)
  1027.  
  1028. moteur1.set_sens(0);
  1029. moteur1.enable();
  1030. for (n=0; n<n_max; n++)
  1031. {
  1032. lecture_fins_de_course_xy();
  1033. moteur1.step();
  1034. _delay_us(2000);
  1035. }
  1036. moteur1.disable();
  1037.  
  1038. n0 = moteur2.position_impuls;
  1039. n_max = 400- (n0 % 400); // modulo (reste de la division)
  1040.  
  1041. moteur2.set_sens(0);
  1042. moteur2.enable();
  1043. for (n=0; n<n_max; n++)
  1044. {
  1045. lecture_fins_de_course_xy();
  1046. moteur2.step();
  1047. _delay_us(2000);
  1048. }
  1049. moteur2.disable();
  1050. beep();
  1051. x0 = moteur1.position_impuls;
  1052. y0 = moteur2.position_impuls;
  1053. _delay_ms(500); // temps d'observation visuelle.
  1054. }
  1055.  
  1056.  
  1057.  
  1058.  
  1059. void mesure_erreurs()
  1060. {
  1061. uint16_t n;
  1062. inputString="";
  1063.  
  1064. laser_off();
  1065. erreur_X=0;
  1066. erreur_Y=0;
  1067. Serial.println("rot (mesure ERR)");
  1068.  
  1069. // rotation X jusqu'à détection de la fente du disque sur arbre moteur X
  1070. moteur1.set_sens(0);
  1071. moteur1.enable();
  1072. while ((PIND & 0b00000001) != 0 )
  1073. {
  1074. lecture_fins_de_course_xy();
  1075. moteur1.step();
  1076. _delay_ms(1);
  1077. }
  1078. moteur1.disable();
  1079. _delay_ms(50);
  1080.  
  1081. //rotation X supplémentaire de 1,5 tours
  1082. moteur1.enable();
  1083. for (n=0; n<600; n++) // 400 impuls/tour -> 200 impl = 1/2 tour
  1084. {
  1085. lecture_fins_de_course_xy();
  1086. moteur1.step();
  1087. _delay_ms(1);
  1088. }
  1089. moteur1.disable();
  1090. _delay_ms(50);
  1091.  
  1092. //----------------------------------------------------------------------
  1093. // rotation Y jusqu'à détection de la fente du disque sur arbre moteur Y
  1094. moteur2.set_sens(0);
  1095. moteur2.enable();
  1096. while ((PIND & 0b00000010) != 0 )
  1097. {
  1098. lecture_fins_de_course_xy();
  1099. moteur2.step();
  1100. _delay_ms(1);
  1101. }
  1102. moteur2.disable();
  1103. _delay_ms(50);
  1104.  
  1105. //rotation Y supplémentaire de 1,5 tours
  1106. moteur2.enable();
  1107. for (n=0; n<600; n++) // 400 impuls/tour -> 200 impl = 1/2 tour
  1108. {
  1109. lecture_fins_de_course_xy();
  1110. moteur2.step();
  1111. _delay_ms(1);
  1112. }
  1113. moteur2.disable();
  1114. _delay_ms(50);
  1115. //beep();
  1116.  
  1117. // envoi_erreur();
  1118. _delay_ms(50);
  1119. x0 = moteur1.position_impuls;// parce que la lecture a fait tourner les moteurs
  1120. y0 = moteur2.position_impuls;
  1121. envoi_PRET(x0, y0);
  1122. }
  1123.  
  1124. /**
  1125. void correction_erreurX()
  1126. {
  1127. _delay_ms(100);
  1128. rotX_n_pas_sans_compter(erreur_X); // correctionX
  1129. Serial.println("correctionX");
  1130. _delay_ms(100);
  1131. erreur_X =0;
  1132. //mesure_erreurs();
  1133. }
  1134. **/
  1135.  
  1136. /**
  1137. void correction_erreurY()
  1138. {
  1139. _delay_ms(100);
  1140. rotY_n_pas_sans_compter(erreur_Y); // correctionY
  1141. Serial.println("correctionY");
  1142. _delay_ms(100);
  1143. erreur_Y =0;
  1144. //mesure_erreurs();
  1145. }
  1146. **/
  1147.  
  1148.  
  1149. //GHA0195YA0600
  1150. //SXA0572YA0381XB1143YB0381D27
  1151. void decode_xy_A(long *x, long *y) // retourne des valeurs numériques (en 1/100mm) de la partie numerique qui suit le "XA" et le "YA" dans le message recu
  1152. {
  1153. for (n=0; n<4; n++)
  1154. {
  1155. digits_X[n]=inputString[n+3]-48;
  1156. digits_Y[n]=inputString[n+9]-48;
  1157. }
  1158. *x =(long) 8 * ((long)digits_X[3]+(long)10*digits_X[2]+(long)100*digits_X[1]+(long)1000*digits_X[0]); // 8 -> parceque 8 imps /100eme de mm
  1159. *y =(long) 8 * ((long)digits_Y[3]+(long)10*digits_Y[2]+(long)100*digits_Y[1]+(long)1000*digits_Y[0]);
  1160. }
  1161.  
  1162.  
  1163.  
  1164. //SXA0572YA0381XB1143YB0381D27
  1165. void decode_xy_B(long *x, long *y) // retourne des valeurs numériques (en nb impulsions) de la partie numerique qui suit le "XB" et le "YB"
  1166. {
  1167. for (n=0; n<4; n++)
  1168. {
  1169. digits_X[n]=inputString[n+15]-48;
  1170. digits_Y[n]=inputString[n+21]-48;
  1171. }
  1172. *x = (long) 8 * (digits_X[3]+(long)10*digits_X[2]+(long)100*digits_X[1]+(long)1000*digits_X[0]);
  1173. *y = (long) 8 * (digits_Y[3]+(long)10*digits_Y[2]+(long)100*digits_Y[1]+(long)1000*digits_Y[0]);
  1174. }
  1175.  
  1176.  
  1177. //XN000000
  1178. //LA000000
  1179. void decode_6_digits(long *x) // retourne des valeurs numériques [0..1E6] de la partie numérique qui débute à la position 2
  1180. {
  1181. uint8_t digits[6];
  1182. for (n=0; n<6; n++)
  1183. {
  1184. digits[n]=inputString[n+2]-48;
  1185. }
  1186. *x = digits[5]+(long)10*digits[4]+(long)100*digits[3]+(long)1000*digits[2]+(long)10000*digits[1]+(long)100000*digits[0];
  1187. }
  1188.  
  1189.  
  1190.  
  1191. uint8_t decode_num_aperture()
  1192. {
  1193. /*
  1194.  * Les formats de reception et d'utilisation des apertures sont volontairement similaires :
  1195. MXA1234YA1234XB0000YB0000D12R
  1196. PXA2149YA0411XB0000YB0000D13
  1197. */
  1198. uint8_t num_ap;
  1199.  
  1200. for (n=0; n<2; n++)
  1201. {
  1202. digits_ap[n]= inputString[n+26]-48;
  1203. }
  1204. num_ap = digits_ap[1]+10*digits_ap[0];
  1205. return num_ap;
  1206. }
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212. void tracer_segment() // trace le segment
  1213. {
  1214. uint16_t d; // largeur x en 1/100mm
  1215. float z1, lum1;
  1216. long xi, yi;
  1217.  
  1218. decode_xy_A(&xi, &yi); // coorgonnées du début du segment
  1219.  
  1220. d = (apertures[num_aperture][0]) /8; // largeur x en 1/100mm le /8 because dimensions memorisées en nb de pas moteur. voir la fonction decode_xy_A() (1/100mm = 8 pas)
  1221.  
  1222. /**
  1223. z = [50..145] . attention z=50 -> presque au contact
  1224. LARGEUR DES PISTES :
  1225. z = 80 -> ultrafines (avec lum = 20) pour d=0
  1226. z = 145 -> 2mm (avec lum = 200) pour d >= 200 (2mm)
  1227. **/
  1228.  
  1229. z1 = 80.0 + (float)d * 65.0/200.0;
  1230. if (z1>145.0) {z1 = 145.0;}
  1231. laser_set_Z((uint16_t)z1);
  1232.  
  1233. /**
  1234. lum = [0..250]
  1235. voir le fichier "platine_laser.ods"
  1236. -pistes ultra-fines -> lum = 20 ou moins (5) dans le cas de pastilles cms proches (circuits intégrés smd)
  1237. -pistes largeur mx (2mm) -> lum = 250 (à voir)
  1238. **/
  1239.  
  1240. lum1 = 20.0 + (z1-80.0) * 3.53; // 3.53 = dy/dx = (250-20)/(145-80) = 230/65;
  1241. if (lum1 < 20.0){lum1 = 20.0;}
  1242. if (lum1 > 250.0) {lum1 = 250.0;}
  1243. laser_set_lum((uint16_t)lum1);
  1244.  
  1245.  
  1246. laser_off();
  1247.  
  1248. msg_ret_gto[0]='L'; // demandé en local
  1249. goto_xy(xi, yi); // GOTO au début du segment
  1250.  
  1251. while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); } // attend la fin du premier déplacement plume levée vers l'origine du segment
  1252.  
  1253. decode_xy_B(&xi, &yi); // coordonnées de l'extrémité du segment
  1254.  
  1255. msg_ret_gto[0]='T'; msg_ret_gto[1]='S'; msg_ret_gto[2]='G';
  1256.  
  1257. laser_on();
  1258.  
  1259. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); } // trace le segment
  1260. laser_off();
  1261. }
  1262.  
  1263.  
  1264.  
  1265. int tracer_pastille_ronde(uint16_t rayon) // rayon en nb d'implulsions
  1266. {
  1267. // par segments de droite juxtaposés
  1268. long centre_x, centre_y;
  1269. long xi, yi;
  1270. float rayon_i; // rayon des cercles concentrique qui constitueront la pastille. rayon_i sera diminué à chaque tour.
  1271. float largeur_trait, rt;
  1272. float x, y;
  1273. uint16_t n, i;
  1274. int8_t stop;
  1275.  
  1276. largeur_trait = 8 * 15.0; // "8*" because 8 pas/mm
  1277.  
  1278. rayon_i = rayon;
  1279. // rt = (8*25) + largeur_trait; // rayon du trou; "8*" because 8 pas/mm
  1280. // rt = 400; // trous trops grands
  1281. rt = 300;
  1282.  
  1283. if (rayon < 100 ) {rt=0;} // ne pas percer les très petites pastilles qui sont des raccordements de pistes
  1284.  
  1285. laser_set_Z(80);
  1286. laser_set_lum(10); // 40
  1287.  
  1288. centre_x = x0;
  1289. centre_y = y0;
  1290.  
  1291. n = 0;
  1292. stop = 0;
  1293. while ((n<12) && (stop == 0))
  1294. {
  1295. //d= n * largeur_trait;
  1296. //if (d > (ax/1.5) || d > (ay/1.5))
  1297. if ( (rt>0) && (rayon_i < rt)) { stop=1; }
  1298. else
  1299. {
  1300. for (i=0; i<=180; i++) // tracé d'un cercle_i constitué par 180 minuscules segments
  1301. {
  1302. x = rayon_i * cos(2.0 * M_PI * i / 180.0);
  1303. y = rayon_i * sin(2.0 * M_PI * i / 180.0);
  1304. xi = centre_x + (long) round(x);
  1305. yi = centre_y + (long) round(y);
  1306.  
  1307. msg_ret_gto[0]='S'; // demandé en local et sans frein
  1308.  
  1309. if (i>=1) {laser_on();} // le premier déplacement, lui, du centre vers la circonférence, n'a pas été tracé
  1310.  
  1311. goto_xy(xi, yi); // trace la pastille - ce goto est effectué par les INT des timers 3 et 4. Il est terminé par le "test_fin_goto"
  1312. while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1313. }
  1314. rayon_i -= largeur_trait;
  1315. if (rayon_i < 0) {stop=1; }
  1316. }
  1317. n++;
  1318. }
  1319.  
  1320. xi = centre_x;
  1321. yi = centre_y;
  1322. msg_ret_gto[0]='P';
  1323.  
  1324. //affleure_plume();
  1325. laser_off();
  1326.  
  1327. goto_xy(xi, yi); // retour au centre, non tracé
  1328.  
  1329. }
  1330.  
  1331.  
  1332.  
  1333. /**
  1334.  
  1335. void tracer_pastille_ronde2(uint16_t rayon) // rayon en nb d'implulsions
  1336. {
  1337. // par calcul direct des équations paramétriques du cercle
  1338. long centre_x, centre_y;
  1339. uint8_t n;
  1340. uint8_t stop;
  1341. uint16_t i, j, j_max, k;
  1342. uint16_t c1, d1, rt, largeur_plume;
  1343. float f1, f2, f3;
  1344.  
  1345. rt = 200; // 200 rayon du trou (à ajuster)
  1346. largeur_plume = 100; // 150 ( 100..200, 300 pour tests visuels ) (à ajuster)
  1347.  
  1348. //long x_min, x_max, dx; // pour mesurer le diametre obtenu (en phase de tests)
  1349. //x_min=100000;
  1350. //x_max=-100000;
  1351.  
  1352. laser_set_Z(80); // trace fine
  1353. laser_set_lum(20); // 40
  1354.  
  1355. centre_x = x0;
  1356. centre_y = y0;
  1357.  
  1358. msg_ret_gto[0]='L'; // demandé en local
  1359.  
  1360. // ici on se trouve au centre du cercle
  1361. // on va se rendre en un point du cercle, plume levée, sans tracer.
  1362.  
  1363. c1 = rayon; // pour le cercle extérieur. Décroit ensuite pour les cercles intérieurs de remplissage de la pastille
  1364. if (c1<(8*50)) {rt=0;} // ne pas percer les très petites pastilles qui sont des raccordements de pistes
  1365.  
  1366. x1 = centre_x-c1;
  1367. y1 = centre_y;
  1368.  
  1369. goto_xy(); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(); }
  1370.  
  1371.   n=0;
  1372. stop=0;
  1373. while ((n<12) && (stop == 0))
  1374. {
  1375. if (c1 < rt) { stop=1; }
  1376. else
  1377. {
  1378. // ici on se trouve sur le cercle on peut commencer le tracé
  1379. OCR3A = 16000; // valeur "très grande"
  1380. OCR4A = 16000;
  1381. moteur1.set_marche(2); // cette valeur >1 sera traitée différemment par l'interruption ISR(TIMER3_COMPA_vect) (c.a.d. disable test de fin de course dans cette INT)
  1382. moteur1.enable();
  1383. moteur2.set_marche(2);
  1384. moteur2.enable();
  1385.  
  1386. laser_on();
  1387.  
  1388. k=0;
  1389. for(i=0; i<1023; i++)
  1390. {
  1391. f1 = (float) i;
  1392. f2 = sin(2.0 * M_PI * f1/1023.0); // b1 = [0..1]
  1393. if (f2!=0) {f3 = 1200/f2; } else { f3 = 1e6;} // c1 = [1000..>>]
  1394. if (f2>0) { moteur1.set_sens(0); d1 = (uint16_t) f3; } else { moteur1.set_sens(1); d1= (uint16_t) (-1 * f3);}
  1395. OCR3A = d1;
  1396.  
  1397. f2 = cos(2.0 * M_PI * f1/1023.0);
  1398. if (f2!=0) { f3 = 1200/f2; } else { f3 = 1e6;}
  1399. if (f3>0) { moteur2.set_sens(0); d1 = (uint16_t) f3; } else { moteur2.set_sens(1); d1= (uint16_t) (-1 * f3);}
  1400. OCR4A = d1;
  1401.  
  1402. //if (x_min > moteur1.position_impuls) {x_min = moteur1.position_impuls;} // pour mesurer le diametre obtenu (en phase de tests)
  1403. //if (x_max < moteur1.position_impuls) {x_max = moteur1.position_impuls;}
  1404. //dx = (x_max - x_min);
  1405.  
  1406. j_max = c1/3; // la valeur 28 a été déduite empiriquement de la mesure du diamètre du tracé obtenu, je le calculerai strictement
  1407. for (j=0; j<j_max; j++)
  1408. {
  1409. _delay_us(10); // le diam du cercle (en mm) = environ (la valeur du delai en ms + 0.32) * 560 /800
  1410. }
  1411. }
  1412. n++;
  1413. moteur1.set_marche(0);
  1414. moteur2.set_marche(0);
  1415. _delay_ms(10); // frein (immobilisation, le courant est maintenu sans impulsions)
  1416.  
  1417. //rotX_n_pas_sans_compter(erreur_X); // correction erreur sans envoi de message USB
  1418. //rotY_n_pas_sans_compter(erreur_Y);
  1419.  
  1420. if (c1 > (100+50))
  1421. { // déplacement vers le début du cercle (concentrique et plus petit) suivant
  1422. laser_off();
  1423. c1 -= largeur_plume;
  1424. x1 = centre_x -c1;
  1425. y1 = centre_y;
  1426. msg_ret_gto[0]='L'; // demandé en local
  1427. goto_xy(); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(); }
  1428. }
  1429. else { stop=1; }
  1430. }
  1431. }
  1432.  
  1433. // la droite (rayon/c1) ne passe pas exactement par 0 mais est... bien droite. (voir tableau sous Libre Office Calc)
  1434. // le cercle a une longueur de 1024 * ds
  1435. // remarque : ds = dx_max = dy_max. Le calcul est donc simple et évite de résoudre une intégrale. Le diamètre est = 1024 * ds / pi.
  1436. // dx_max est la distance parcourue pendant 1 pas de cette boucle par l'envoi d'impls par l'int ISR(TIMER3_COMPA_vect) à la freq max (c.a.d periode min = 1200)
  1437.  
  1438. moteur1.set_marche(0);
  1439. moteur2.set_marche(0);
  1440.  
  1441. _delay_us(10);
  1442. moteur1.disable();
  1443. moteur2.disable();
  1444. laser_off();
  1445.  
  1446. // ici on se trouve sur un cercle, on va retourner au centre
  1447. x1 = centre_x;
  1448. y1 = centre_y+n;
  1449. msg_ret_gto[0]='P';
  1450.  
  1451. goto_xy();
  1452.  
  1453. // dx /=10;
  1454. // envoi_nombre(dx); // pour mesurer le diametre obtenu (en phase de tests)
  1455. }
  1456.  
  1457. */
  1458.  
  1459.  
  1460. int tracer_pastille_rectangulaire(uint16_t ax_i, uint16_t ay_i)
  1461. {
  1462. // ax_i et ay_i sont les dimensions de la pastille
  1463. long centre_x, centre_y;
  1464. long xi, yi;
  1465. float x, y;
  1466. float largeur_trait, d; // epaisseur du trait
  1467. int8_t n;
  1468.  
  1469. laser_set_Z(80);
  1470. laser_set_lum(5); // 40
  1471.  
  1472. largeur_trait = 8.0 * 7.5;
  1473.  
  1474. ax_i -= largeur_trait; // pour retrécir le rectangle extérieur de la largeur du trait
  1475. ay_i -= largeur_trait; // pour retrécir le rectangle extérieur
  1476.  
  1477. centre_x = x0;
  1478. centre_y = y0;
  1479.  
  1480. msg_ret_gto[0]='L'; // demandé en local
  1481.  
  1482. // ici on se trouve au centre de la pastille
  1483. // on va se rendre à un coin, plume levée, sans tracer.
  1484.  
  1485. xi = centre_x -ax_i;
  1486. yi = centre_y -ay_i;
  1487. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1488.  
  1489. // ici on se trouve au premier coin, on commence le tracé
  1490.  
  1491.  
  1492. n=0; // au départ n=0 ne retrécit pas la pastille de la largeur du trait, mais cela a été fait ci-dessus au préalable.
  1493. while (n<12)
  1494. {
  1495. d= n * largeur_trait;
  1496. if ((d < ax_i) && (d < ay_i))
  1497. {
  1498. xi = centre_x +ax_i -d;
  1499. yi = centre_y -ay_i +d;
  1500. laser_on();
  1501. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1502.  
  1503. xi = centre_x +ax_i -d;
  1504. yi = centre_y +ay_i -d;
  1505. laser_on();
  1506. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1507.  
  1508. xi = centre_x -ax_i +d;
  1509. yi = centre_y +ay_i -d;
  1510. laser_on();
  1511. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1512.  
  1513. xi = centre_x -ax_i +d;
  1514. yi = centre_y -ay_i +d;
  1515. laser_on();
  1516. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1517. }
  1518. n++;
  1519. }
  1520.  
  1521. //affleure_plume();
  1522. laser_off();
  1523.  
  1524. xi = centre_x;
  1525. yi = centre_y;
  1526. msg_ret_gto[0]='P';
  1527. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); } // retour au centre
  1528.  
  1529. }
  1530.  
  1531.  
  1532.  
  1533. void tracer_carre()
  1534. {
  1535. long centre_x, centre_y;
  1536. long xi, yi;
  1537. long x, y, c;
  1538.  
  1539.  
  1540. c = 8 * 200.0;
  1541.  
  1542. centre_x = x0;
  1543. centre_y = y0;
  1544.  
  1545. msg_ret_gto[0]='L'; // demandé en local
  1546.  
  1547. // ici on se trouve au centre du carré
  1548. // on va se rendre à un coin, plume levée, sans tracer.
  1549.  
  1550. xi = centre_x -c;
  1551. yi = centre_y -c;
  1552. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1553.  
  1554. // ici on se trouve au premier coin, on commence le tracé
  1555.  
  1556. xi = centre_x +c;
  1557. yi = centre_y -c;
  1558. laser_on();
  1559. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1560.  
  1561. xi = centre_x +c;
  1562. yi = centre_y +c;
  1563. laser_on();
  1564. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1565.  
  1566. xi = centre_x -c;
  1567. yi = centre_y +c;
  1568. laser_on();
  1569. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1570.  
  1571. xi = centre_x -c;
  1572. yi = centre_y -c;
  1573. laser_on();
  1574. goto_xy(xi, yi); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xi, yi); }
  1575.  
  1576. //affleure_plume();
  1577. laser_off();
  1578.  
  1579. xi = centre_x;
  1580. yi = centre_y;
  1581. msg_ret_gto[0]='P';
  1582. goto_xy(xi, yi); // retour au centre
  1583.  
  1584. }
  1585.  
  1586.  
  1587.  
  1588.  
  1589. void X_plus()
  1590. {
  1591. char inChar2;
  1592. String inputString2 = "";
  1593. uint8_t stringComplete2 = 0;
  1594.  
  1595. acceleration_permise = 1;
  1596. OCR3A = ocr3a_depart;
  1597. OCR4A = ocr4a_depart;
  1598. moteur1.enable();
  1599. moteur1.set_sens(0);
  1600. moteur1.set_marche(1);
  1601.  
  1602. uint8_t sortir = 0;
  1603. lecture_fins_de_course_xy();
  1604. while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
  1605. {
  1606. lecture_fins_de_course_xy();
  1607.  
  1608. while( Serial.available() && ( stringComplete2 == 0) )
  1609. {
  1610. inChar2 = (char)Serial.read(); inputString2 += inChar2; if (inChar2 == '\n')
  1611. {
  1612. stringComplete2 = 1;
  1613. }
  1614. }
  1615. if (stringComplete2 == 1)
  1616. {
  1617. if (inputString2[0] == 'A')
  1618. {
  1619. Serial.println("R: STOP2");
  1620. sortir =1;
  1621. }
  1622. inputString2 = "";
  1623. stringComplete2 = 0;
  1624. }
  1625.  
  1626. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
  1627. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
  1628. }
  1629. moteur1.disable();
  1630. envoi_PRET(x0, y0);
  1631.  
  1632. }
  1633.  
  1634.  
  1635. void X_moins()
  1636. {
  1637. char inChar2;
  1638. String inputString2 = "";
  1639. uint8_t stringComplete2 = 0;
  1640.  
  1641. OCR3A = ocr3a_depart;
  1642. OCR4A = ocr4a_depart;
  1643. acceleration_permise = 1;
  1644. moteur1.set_sens(1);
  1645. moteur1.enable();
  1646. moteur1.set_marche(1);
  1647.  
  1648. uint8_t sortir = 0;
  1649. lecture_fins_de_course_xy();
  1650. while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
  1651. {
  1652. lecture_fins_de_course_xy();
  1653.  
  1654. while( Serial.available() && ( stringComplete2 == 0) )
  1655. {
  1656. inChar2 = (char)Serial.read();
  1657. inputString2 += inChar2;
  1658. if (inChar2 == '\n')
  1659. {
  1660. stringComplete2 = 1;
  1661. }
  1662. }
  1663. if (stringComplete2 == 1)
  1664. {
  1665. if (inputString2[0] == 'A')
  1666. {
  1667. Serial.println("R: STOP2");
  1668. sortir =1;
  1669. }
  1670. inputString2 = "";
  1671. stringComplete2 = 0;
  1672. }
  1673.  
  1674. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
  1675. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
  1676. }
  1677. moteur1.set_marche(0);
  1678. moteur1.disable();
  1679. envoi_PRET(x0, y0);
  1680. }
  1681.  
  1682.  
  1683. void Y_plus()
  1684. {
  1685. char inChar2;
  1686. String inputString2 = "";
  1687. uint8_t stringComplete2 = 0;
  1688.  
  1689. OCR3A = ocr3a_depart;
  1690. OCR4A = ocr4a_depart;
  1691. acceleration_permise = 1;
  1692. moteur2.set_sens(0);
  1693. periode2=36;
  1694. moteur2.enable();
  1695. moteur2.set_marche(1);
  1696.  
  1697. uint8_t sortir = 0;
  1698. lecture_fins_de_course_xy();
  1699. while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
  1700. {
  1701. lecture_fins_de_course_xy();
  1702.  
  1703. while( Serial.available() && ( stringComplete2 == 0) )
  1704. {
  1705. inChar2 = (char)Serial.read();
  1706. inputString2 += inChar2;
  1707. if (inChar2 == '\n')
  1708. {
  1709. stringComplete2 = 1;
  1710. }
  1711. }
  1712. if (stringComplete2 == 1)
  1713. {
  1714. if (inputString2[0] == 'A')
  1715. {
  1716. Serial.println("R: STOP2");
  1717. sortir =1;
  1718. }
  1719. inputString2 = "";
  1720. stringComplete2 = 0;
  1721. }
  1722.  
  1723. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
  1724. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
  1725. }
  1726. moteur2.set_marche(0);
  1727. moteur2.disable();
  1728. envoi_PRET(x0, y0);
  1729. }
  1730.  
  1731.  
  1732. int Y_moins()
  1733. {
  1734. char inChar2;
  1735. String inputString2 = "";
  1736. uint8_t stringComplete2 = 0;
  1737.  
  1738. OCR3A = ocr3a_depart;
  1739. OCR4A = ocr4a_depart;
  1740. acceleration_permise = 1;
  1741. moteur2.set_sens(1);
  1742. periode2=36;
  1743. moteur2.enable();
  1744. moteur2.set_marche(1);
  1745.  
  1746. uint8_t sortir = 0;
  1747. lecture_fins_de_course_xy();
  1748. while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
  1749. {
  1750. lecture_fins_de_course_xy();
  1751.  
  1752. while( Serial.available() && ( stringComplete2 == 0) )
  1753. {
  1754. inChar2 = (char)Serial.read();
  1755. inputString2 += inChar2;
  1756. if (inChar2 == '\n')
  1757. {
  1758. stringComplete2 = 1;
  1759. }
  1760. }
  1761. if (stringComplete2 == 1)
  1762. {
  1763. if (inputString2[0] == 'A')
  1764. {
  1765. Serial.println("R: STOP2"); sortir =1;
  1766. }
  1767. inputString2 = "";
  1768. stringComplete2 = 0;
  1769. }
  1770.  
  1771. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
  1772. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
  1773. }
  1774. moteur1.set_marche(0);
  1775. moteur2.disable();
  1776. envoi_PRET(x0, y0);
  1777. }
  1778.  
  1779.  
  1780.  
  1781.  
  1782.  
  1783. int goto_Safe_POS()
  1784. {
  1785. char inChar2;
  1786. String inputString2 = "";
  1787. uint8_t stringComplete2 = 0;
  1788.  
  1789. // déplacement en vitesse rapide jusqu'aux arrêts fin de course, puis positionnement précis
  1790. laser_off();
  1791. laser_set_Z(140); // position haute
  1792.  
  1793. acceleration_permise = 1;
  1794.  
  1795. OCR3A = ocr3a_depart;
  1796. OCR4A = ocr4a_depart;
  1797.  
  1798. moteur1.enable();
  1799. moteur1.set_sens(0);
  1800. moteur1.set_marche(1);
  1801.  
  1802. moteur2.enable();
  1803. moteur2.set_sens(0);
  1804. moteur2.set_marche(1);
  1805.  
  1806. uint8_t sortir = 0;
  1807. lecture_fins_de_course_xy();
  1808. while ( ((etat_FC_x2 == 0) || (etat_FC_y2 == 0) ) && (sortir==0) )
  1809. {
  1810. lecture_fins_de_course_xy();
  1811.  
  1812. while( Serial.available() && ( stringComplete2 == 0) )
  1813. {
  1814. inChar2 = (char)Serial.read();
  1815. inputString2 += inChar2;
  1816. if (inChar2 == '\n')
  1817. {
  1818. stringComplete2 = 1;
  1819. }
  1820. }
  1821. if (stringComplete2 == 1)
  1822. {
  1823. if (inputString2[0] == 'A')
  1824. {
  1825. Serial.println("R: STOP2");
  1826. sortir =1;
  1827. }
  1828. inputString2 = "";
  1829. stringComplete2 = 0;
  1830. }
  1831.  
  1832. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
  1833. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
  1834. }
  1835.  
  1836. moteur1.disable();
  1837. moteur2.disable();
  1838. envoi_PRET(x0, y0);
  1839. return(0);
  1840. }
  1841.  
  1842.  
  1843.  
  1844. int goto_ZERO(long xi, long yi) // goto vers zéro mécanique (définit par les fin de course) + valeur de la marge envoyée par le PC
  1845. {
  1846. char inChar3;
  1847. String inputString3 = "";
  1848. uint8_t stringComplete3 = 0;
  1849.  
  1850. //----------------------------------------------------------------------
  1851. // déplacement en vitesse rapide jusqu'aux arrêts fin de course, puis positionnement précis
  1852. laser_off();
  1853. laser_set_Z(140); // position haute
  1854.  
  1855. acceleration_permise = 1;
  1856.  
  1857. OCR3A = ocr3a_depart;
  1858. OCR4A = ocr4a_depart;
  1859.  
  1860. moteur1.enable();
  1861. moteur1.set_sens(1);
  1862. moteur1.set_marche(1);
  1863.  
  1864. moteur2.enable();
  1865. moteur2.set_sens(1);
  1866. moteur2.set_marche(1);
  1867.  
  1868. uint8_t sortir3 = 0;
  1869. lecture_fins_de_course_xy();
  1870. while ( ((etat_FC_x1 == 0) || (etat_FC_y1 == 0) ) && (sortir3==0) )
  1871. {
  1872. lecture_fins_de_course_xy();
  1873.  
  1874. while( Serial.available() && ( stringComplete3 == 0) )
  1875. {
  1876. inChar3 = (char)Serial.read();
  1877. inputString3 += inChar3;
  1878. if (inChar3 == '\n')
  1879. {
  1880. stringComplete3 = 1;
  1881. }
  1882. }
  1883. if (stringComplete3 == 1)
  1884. {
  1885. if (inputString3[0] == 'A')
  1886. {
  1887. Serial.println("R: STOP3");
  1888. sortir3 =1;
  1889. }
  1890. inputString3 = "";
  1891. stringComplete3 = 0;
  1892. }
  1893.  
  1894. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
  1895. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
  1896. }
  1897.  
  1898. if (sortir3 == 1)
  1899. {
  1900. moteur1.disable();
  1901. moteur2.disable();
  1902. envoi_PRET(x0, y0);
  1903. return 1;
  1904. }
  1905. Serial.println("R: marge");
  1906.  
  1907.  
  1908. RAZ_POS(); // ICI : REFERENCE ABSOLUE DES POSITIONS PROVISOIRE (pour pouvoir rejoindre le pt de départ du tracé (valeur de marge envoyée par la commande))
  1909.  
  1910. // goto vers valeur envoyée par la commande
  1911. acceleration_permise = 0;
  1912. base_ocr = 500;
  1913. calcul_periode_deplacement(0, 0, 100, 100);
  1914.  
  1915. msg_ret_gto[0]='Z'; msg_ret_gto[1]='0'; msg_ret_gto[2]='0';
  1916. goto_xy(xi, yi);
  1917.  
  1918. while (goto_en_cours_xy == 1)
  1919. {
  1920. lecture_fins_de_course_xy();
  1921. test_fin_goto(xi, yi);
  1922. if (pas_mot1_demande > 0) {pas_mot1(); pas_mot1_demande--; }
  1923. if (pas_mot2_demande > 0) {pas_mot2(); pas_mot2_demande--; }
  1924. }
  1925. _delay_ms(100);
  1926.  
  1927. moteur1.disable();
  1928. moteur2.disable();
  1929. RAZ_POS(); // ICI : REFERENCE ABSOLUE DES POSITIONS DEFINITIVE
  1930. envoi_PRET(x0, y0);
  1931. return(0);
  1932.  
  1933. }
  1934.  
  1935.  
  1936.  
  1937.  
  1938. /**
  1939. void init_table_sinus()
  1940. {
  1941. uint16_t n;
  1942. float a;
  1943. for(n=0; n<1023; n++)
  1944. {
  1945. a = (float) n;
  1946. table_sinus[n] = 16383.0 * sin(2.0 * M_PI * a/1023.0);
  1947. }
  1948. }
  1949. **/
  1950.  
  1951.  
  1952.  
  1953.  
  1954. void test()
  1955. {
  1956. //tracer_pastille_ronde(8*75);
  1957. /* goto_xy(800* 10, 800* 10);
  1958. goto_xy(800* 3, 800* 5);
  1959. goto_xy(800* 7, 800* 2);
  1960. goto_xy(800* 12, 800* 4);
  1961. goto_xy(800* 20, 800* 20);
  1962. goto_xy(800* 5, 800* 8);
  1963. goto_xy(800* 1, 800* 6);
  1964. goto_xy(800* 4, 800* 17);
  1965. goto_xy(800* 2, 800* 7);
  1966. goto_xy(800* 6, 800* 14);
  1967.  
  1968. */
  1969.  
  1970.  
  1971. goto_xy(800*1, 1*800);
  1972. goto_xy(800*1, 5*800);
  1973. goto_xy(800*8, 5*800);
  1974. goto_xy(800*8, 2*800);
  1975. goto_xy(800*10, 2*800);
  1976. goto_xy(800*10, 3*800);
  1977. goto_xy(800*7, 3*800);
  1978. goto_xy(800*7, 4*800);
  1979. goto_xy(800*3, 4*800);
  1980. goto_xy(800*3, 1*800);
  1981. goto_xy(800*5, 1*800);
  1982. goto_xy(800*1, 6*800);
  1983. goto_xy(800*5, 6*800);
  1984. goto_xy(800*5, 4*800);
  1985. goto_xy(800*5, 3*800);
  1986.  
  1987. tracer_pastille_ronde(400);
  1988.  
  1989.  
  1990. /*
  1991.  uint8_t n;
  1992. goto_xy(800*1, 1*800);
  1993. for (n=1; n<=10; n++)
  1994. {
  1995. goto_xy(800*1, 5*800);
  1996. goto_xy(800*6, 5*800);
  1997. goto_xy(800*6, 1*800);
  1998. goto_xy(800*1, 1*800);
  1999. }
  2000. */
  2001.  
  2002.  
  2003. }
  2004.  
  2005.  
  2006.  
  2007.  
  2008.  
  2009. void setup()
  2010. {
  2011. // CLKPR = 0b10000000;
  2012. // CLKPR = 0b00000000;
  2013.  
  2014. init_ports();
  2015.  
  2016. laser_off();
  2017.  
  2018. // int_EXT_setup(); // desable (inutile depuis que les moteurs ne "glissent" plus )
  2019.  
  2020. timer2_setup();
  2021. timer3_setup();
  2022. timer4_setup();
  2023. timer5_setup();
  2024.  
  2025. // init_table_sinus(); <- ***************************** A VOIR !!! *************************
  2026.  
  2027. // lcd_init(); // voir l'attribution des bits dans le ficher LCD_5110-b28b.h - Note: j'ai supprimé l'affichage LCD.
  2028.  
  2029.  
  2030.  
  2031. // ==== Le port est défini dans le step_motor4.h ========
  2032. moteur1.bit_ENABLE = 0b00000001; // X
  2033. moteur2.bit_ENABLE = 0b00000010; // Y
  2034.  
  2035. // ==== Le port est défini dans le step_motor4.h ========
  2036. moteur1.bit_finCourse1 = 0b00000001; // X
  2037. moteur1.bit_finCourse2 = 0b00000010; // X
  2038.  
  2039. moteur2.bit_finCourse1 = 0b00000100; // Y
  2040. moteur2.bit_finCourse2 = 0b00001000; // Y
  2041.  
  2042. // ==== Le port est défini dans le step_motor4.h ========
  2043. moteur1.bit_DIR = 0b00000001; // X
  2044. moteur1.bit_STEP = 0b00000010; // X
  2045.  
  2046. moteur2.bit_DIR = 0b00000100; // Y
  2047. moteur2.bit_STEP = 0b00001000; // Y
  2048.  
  2049. // =====================================================
  2050.  
  2051. mm_par_s_max = 2; // par défaut
  2052. mm_par_s = mm_par_s_max;
  2053.  
  2054. moteur1.steps_par_tour = 200;
  2055. moteur1.tours_par_mm = 2; // pas-de-vis 0.5mm (pour un diamètre M3)
  2056. moteur1.impuls_par_step = 2; // de par la configuration de la carte "EasyDriver"
  2057.  
  2058. moteur2.steps_par_tour = 200;
  2059. moteur2.tours_par_mm = 2;
  2060. moteur2.impuls_par_step = 2;
  2061.  
  2062. ocr3a_min = 800; // pour moteur1 800
  2063. ocr3a_depart = 2000; // pour moteur1 1300
  2064.  
  2065. ocr4a_min = 800; // pour moteur2 800
  2066. ocr4a_depart = 2000; // pour moteur2 2000
  2067.  
  2068. base_ocr_depart = 3000; // 3000 determine la vitesse de rotation (basse) appliquée lors de la mise en rotation
  2069. base_ocr_min = 500; // determine la vitesse max de rotation permise, voir les fonctions "ISR(TIMER3_COMPA_vect)" et "ISR(TIMER4_COMPA_vect)"
  2070. base_ocr_min2 = 300; // determine la vitesse max de rotation permise lors des "goto zero" et "goto safe pos"
  2071.  
  2072.  
  2073. moteur1.init(); // calcule les autres paramètres...
  2074. moteur2.init(); // calcule les autres paramètres...
  2075.  
  2076. n_octet=0;
  2077.  
  2078. Serial.begin(9600); // 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200
  2079.  
  2080. uint16_t x2, y2, p1, p2;
  2081.  
  2082. x0=0;
  2083. y0=0;
  2084. x2=100;
  2085. y2=100;
  2086. calcul_periode_deplacement(x0, y0, x2, y2);
  2087.  
  2088. moteur1.RAZ_pos();
  2089. moteur2.RAZ_pos();
  2090.  
  2091. for (int i=0; i<40; i++) { apertures[i][2] = 'x'; }
  2092. //apertures[23][2] = 'R'; // pour test
  2093.  
  2094. sei();
  2095.  
  2096. laser_off();
  2097. laser_set_lum(40);
  2098. laser_set_Z(145);
  2099.  
  2100. _delay_ms(100);
  2101. Serial.println("Mega2560 INIT");
  2102. _delay_ms(100);
  2103. beep();
  2104. _delay_ms(100);
  2105. beep();
  2106. envoi_PRET(x0, y0);
  2107. }
  2108.  
  2109.  
  2110.  
  2111.  
  2112. void loop() // BOUCLE PRINCIPALE
  2113. {
  2114. // ne pas inclure de tempo dans cette boucle principale sous peine de perdre la précision des positions de fin de goto, et donc la précision de position de la plume !
  2115.  
  2116. long xil, yil;
  2117. lecture_fins_de_course_xy();
  2118. // test_fin_goto(); // stope le cas échéant le goto en cours
  2119.  
  2120. /**
  2121. if (pas_mot1_demande > 0) // traitement moteur1 demandé par l'interruption timer3
  2122. {
  2123. pas_mot1();
  2124. pas_mot1_demande--;
  2125. }
  2126.  
  2127. if (pas_mot2_demande > 0) // traitement moteur2 demandé par l'interruption timer4
  2128. {
  2129. pas_mot2();
  2130. pas_mot2_demande--;
  2131. }
  2132. **/
  2133.  
  2134. cpt1++;
  2135. if ((cpt1 >= 1000) && (goto_en_cours_xy == 0))
  2136. {
  2137. cpt1=0;
  2138. }
  2139.  
  2140. if (goto_en_cours_xy == 0)
  2141. {
  2142. uint8_t n;
  2143.  
  2144. stringComplete = false;
  2145. while( Serial.available() && ( stringComplete == false) )
  2146. {
  2147. inChar = (char)Serial.read();
  2148. inputString += inChar;
  2149. if (inChar == '\n') { stringComplete = true;}
  2150. }
  2151.  
  2152.  
  2153. if (stringComplete == true)
  2154. {
  2155. // decodage du message reçu par USB
  2156. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2157. if (inputString[0] == 'A') // STOP
  2158. {
  2159. Serial.println("R: STOP");
  2160. STOP();
  2161. inputString="";
  2162. stringComplete = false;
  2163. }
  2164. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2165. if (inputString[0] == 'T')
  2166. {
  2167. if (inputString[1] == 'E') // TEST
  2168. {
  2169. test();
  2170. inputString="";
  2171. stringComplete = false;
  2172. }
  2173. }
  2174. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2175. if (inputString[0] == 'Z') // LASER ON/OFF
  2176. {
  2177. if (inputString[1] == '1') // allume LASER
  2178. {
  2179. laser_on();
  2180. inputString="";
  2181. stringComplete = false;
  2182. }
  2183.  
  2184. if (inputString[1] == '0') // éteint LASER
  2185. {
  2186. laser_off();
  2187. inputString="";
  2188. stringComplete = false;
  2189. }
  2190.  
  2191. if (inputString[1] == 'B') // BLOCAGE LASER
  2192. {
  2193. Serial.println("Blocage laser");
  2194. laser_bloque();
  2195. inputString="";
  2196. stringComplete = false;
  2197. }
  2198.  
  2199. if (inputString[1] == 'D') // DEBLOCAGE LASER
  2200. {
  2201. laser_debloque();
  2202. inputString="";
  2203. stringComplete = false;
  2204. }
  2205. }
  2206.  
  2207.  
  2208. if (inputString[0] == 'L')
  2209. {
  2210. if (inputString[1] == 'U') // intensité luminosité laser
  2211. {
  2212. long LU;
  2213. decode_6_digits(&LU);
  2214. laser_set_lum((uint8_t)LU);
  2215. inputString="";
  2216. stringComplete = false;
  2217. }
  2218. if (inputString[1] == 'Z') // Hauteur du laser
  2219. {
  2220. long LZ;
  2221. decode_6_digits(&LZ);
  2222. laser_set_Z((uint16_t)LZ); // remarque: le timer5 est configuré en mode "fast PWM 10 bits"
  2223. inputString="";
  2224. stringComplete = false;
  2225. }
  2226. if (inputString[1] == 'E') // lire erreur de position xy
  2227. {
  2228. mesure_erreurs();
  2229. envoi_PRET(x0,y0);
  2230. inputString="";
  2231.  
  2232. }
  2233. }
  2234. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2235. if (inputString[0] == 'X') // déplacements en X
  2236. {
  2237. moteur1.set_marche(0);
  2238. if (inputString[1] == 'P') // X Plus
  2239. {
  2240. Serial.println("R: X+");
  2241. inputString="";
  2242. X_plus();
  2243. }
  2244. if (inputString[1] == 'M') // X Moins
  2245. {
  2246. Serial.println("R: X-");
  2247. inputString="";
  2248. X_moins();
  2249. }
  2250. if (inputString[1] == 'N') // rotation de N pas du moteur X (pour tester des moteurs)
  2251. {
  2252. Serial.println("R: XN");
  2253. long P;
  2254. decode_6_digits(&P);
  2255. rotX_n_pas(P);
  2256. inputString="";
  2257. }
  2258. if (inputString[1] == '1') {Serial.println("R: X+1"); X_plus_mm(1); inputString="";}
  2259. if (inputString[1] == '2') {Serial.println("R: X+10"); X_plus_mm(10); inputString=""; }
  2260. if (inputString[1] == '3') {Serial.println("R: X-1"); X_moins_mm(1); inputString="";}
  2261. if (inputString[1] == '4') {Serial.println("R: X-10"); X_moins_mm(10); inputString="";}
  2262.  
  2263. }
  2264.  
  2265. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2266. if (inputString[0] == 'Y') // déplacement en Y
  2267. {
  2268. moteur2.set_marche(0);
  2269. if (inputString[1] == 'P') // Y Plus
  2270. {
  2271. Serial.println("R: Y+");
  2272. inputString="";
  2273. Y_plus();
  2274. }
  2275. if (inputString[1] == 'M') // Y Moins
  2276. {
  2277. Serial.println("R: Y-");
  2278. inputString="";
  2279. Y_moins();
  2280. }
  2281. if (inputString[1] == 'N') // rotation de N pas du moteur Y (pour tester des moteurs)
  2282. {
  2283. Serial.println("R: YN");
  2284. long P;
  2285. decode_6_digits(&P);
  2286. rotY_n_pas(P);
  2287. inputString="";
  2288. }
  2289. if (inputString[1] == '1') {Serial.println("R: Y+1"); Y_plus_mm(1); inputString="";}
  2290. if (inputString[1] == '2') {Serial.println("R: Y+10"); Y_plus_mm(10); inputString=""; }
  2291. if (inputString[1] == '3') {Serial.println("R: Y-1"); Y_moins_mm(1); inputString="";}
  2292. if (inputString[1] == '4') {Serial.println("R: Y-10"); Y_moins_mm(10); inputString="";}
  2293. }
  2294.  
  2295. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2296. if (inputString[0] == 'P') // TRACER PASTILLE à partir d'une ligne de commande reçue
  2297. {
  2298. if (inputString[1] == 'X') // en x,y
  2299. {
  2300. laser_off();
  2301.  
  2302. decode_xy_A(&xil, &yil);
  2303. num_aperture = decode_num_aperture();
  2304.  
  2305. ax = (apertures[num_aperture][0] /2); // dimension x (rayon = diam/2) - épaisseur de la trace
  2306. if (ax > largeur_plume) {ax -= largeur_plume;} else {ax = 0;}
  2307.  
  2308. ay = (apertures[num_aperture][1] /2);
  2309. if (ay > largeur_plume) {ay -= largeur_plume;} else {ay = 0;}
  2310.  
  2311. type_ap = apertures[num_aperture][2]; // -> 'R' ou 'C' ou 'O'
  2312.  
  2313. msg_ret_gto[0]='R'; msg_ret_gto[1]=' '; msg_ret_gto[2]=' ';
  2314.  
  2315. goto_xy(xil, yil); // goto vers l'emplacement de la pastille à tracer
  2316. while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }
  2317.  
  2318. if ((type_ap == 'R') or (type_ap == 'O')) { tracer_pastille_rectangulaire(ax, ay); } // les pastilles ovales seront tracées rectangulaires...
  2319. // todo : écrire une fonction qui trace une pastille ovale
  2320. if (type_ap == 'C') { tracer_pastille_ronde(ax); }
  2321.  
  2322. inputString="";
  2323. }
  2324.  
  2325.  
  2326. if (inputString[1] == '1') // PASTILLE rectangulaire là où on se trouve
  2327. {
  2328. Serial.println("R: PST ici");
  2329. tracer_pastille_rectangulaire(8*200, 8*200); // 8 (impls/100eme de mm) x 200 (100eme de mm); -> 1600 impulsions
  2330. inputString="";
  2331. }
  2332.  
  2333. if (inputString[1] == 'R') // PASTILLE ronde là où on se trouve
  2334. {
  2335. Serial.println("R: PST ici");
  2336. decode_xy_A(&ax, &ay);
  2337. tracer_pastille_ronde(8 * ax/2); // le diametre est transmis par le PC, on va tracer le rayon.
  2338. inputString="";
  2339. }
  2340. }
  2341.  
  2342. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2343. if (inputString[0] == 'R')
  2344. {
  2345. if (inputString[1] == 'P')
  2346. {
  2347. Serial.println("R: RAZ POS");
  2348. RAZ_POS();
  2349. inputString="";
  2350. }
  2351. if (inputString[1] == 'K')
  2352. {
  2353. Serial.println("R: Rot 2kPi");
  2354. rotation_2k_pi();
  2355. inputString="";
  2356. }
  2357. }
  2358.  
  2359. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2360. if (inputString[0] == 'S') // TRACER SEGMENT
  2361. {
  2362. Serial.println("R: TRACER segment");
  2363. if (inputString[1] == 'X')
  2364. {
  2365. num_aperture = decode_num_aperture();
  2366. tracer_segment();
  2367. inputString="";
  2368. }
  2369. if (inputString[1] == '1') // segment là où on se trouve
  2370. {
  2371. Serial.println("R: SEG ici");
  2372. xil=x0 + (8 * 1000); // 10.00 mm
  2373. yil=y0;
  2374. msg_ret_gto[0]='S'; msg_ret_gto[1]='1';
  2375. laser_on();
  2376. goto_xy(xil, yil); // trace le segment
  2377. inputString="";
  2378. }
  2379. }
  2380. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2381. if (inputString[0] == 'C')
  2382. {
  2383. if (inputString[1] == '1')
  2384. {
  2385. Serial.println("R: carre ici");
  2386. tracer_carre();
  2387. inputString="";
  2388. }
  2389. /**
  2390. if (inputString[1] == 'E')
  2391. {
  2392. correction_erreurX();
  2393. correction_erreurY();
  2394. inputString="";
  2395. envoi_PRET(x0,y0);
  2396. }
  2397. **/
  2398. }
  2399. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2400. if (inputString[0] == 'H') // TRACER mire pour la mise au point
  2401. {
  2402. Serial.println("R: TRACER MIRE");
  2403. if (inputString[1] == '1')
  2404. {
  2405. for (n=0; n<3; n++)
  2406. {
  2407. Y_plus_mm(5);
  2408.  
  2409. moteur1.RAZ_pos();
  2410. moteur2.RAZ_pos();
  2411. x0=0;
  2412. y0=0;
  2413.  
  2414. xil=8*(x0+1000); // 10.00 mm
  2415. yil=8*(y0);
  2416. laser_on();
  2417. goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
  2418.  
  2419. tracer_pastille_rectangulaire(8*200, 8*200);
  2420.  
  2421. xil=8*(x0+1000); // 10.00 mm
  2422. yil=8*y0;
  2423. laser_on();
  2424. goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
  2425.  
  2426. tracer_pastille_ronde(8*200);
  2427.  
  2428. xil=8*(x0+1000); // 10.00 mm
  2429. yil=8*y0;
  2430. laser_on();
  2431. goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
  2432.  
  2433. tracer_pastille_ronde(8*200);
  2434.  
  2435. xil=8*(x0-3000); // 30.00 mm
  2436. yil=8*y0;
  2437. laser_off();
  2438. goto_xy(xil, yil); while (goto_en_cours_xy == 1) { lecture_fins_de_course_xy(); test_fin_goto(xil, yil); }// trace un segment
  2439.  
  2440. }
  2441. inputString="";
  2442. }
  2443.  
  2444. }
  2445.  
  2446. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  2447. if (inputString[0] == 'G') // GOTO ( DEPLACEMENT laser éteint / plume levée)
  2448. {
  2449. laser_off();
  2450. if (inputString[1] == 'X')
  2451. {
  2452. Serial.println("R: GOTO");
  2453. decode_xy_A(&xil, &yil);
  2454. msg_ret_gto[0]='-'; msg_ret_gto[1]='X'; msg_ret_gto[2]='Y';
  2455. OCR3A = 1000; // pour moteur1
  2456. OCR4A = 1500; // pour moteur2
  2457. goto_xy(xil, yil);
  2458. inputString="";
  2459.  
  2460. }
  2461. if (inputString[1] == 'S')
  2462. {
  2463. Serial.println("R: goto SAFE POS");
  2464. goto_Safe_POS();
  2465. inputString="";
  2466. }
  2467. if (inputString[1] == 'H')
  2468. {
  2469. Serial.println("R: GOTO ZERO XYZ");
  2470. decode_xy_A(&xil, &yil);
  2471. goto_ZERO(xil, yil);
  2472. inputString="";
  2473. }
  2474. }
  2475.  
  2476. // -------------------- AJOUT APERTURES à la liste -----------------------------------------------------------------------------------------------
  2477.  
  2478. if (inputString[0] == 'M')
  2479. {
  2480. laser_off();
  2481. //PORTA &= ~bit_LED_verte;
  2482. Serial.println("R: +ap ");
  2483. _delay_ms(300);
  2484. if (inputString[1] == 'X')
  2485. {
  2486. decode_xy_A(&ax, &ay); // attention : ici il ne s'agit pas de la position de l'objet mais de ses dimensions (qui sont codées de la même façon au même endroit dans la ligne)
  2487. type_ap = inputString[28]; // "C" ou "R" ou "O"
  2488. num_aperture = decode_num_aperture();
  2489. ajout_aperture(num_aperture, type_ap);
  2490. inputString="";
  2491. }
  2492. inputString="";
  2493. }
  2494. }
  2495. // ---------------------------------------------------------------------------------------------------------------------------------------------------
  2496.  
  2497. //x0 = moteur1.position_impuls;
  2498. //y0 = moteur2.position_impuls;
  2499. }
  2500. else
  2501. { // ICI goto en cours -> procédures au ralenti pour minimiser les ressources nécessaires afin de laisser le max pour la détection de position de fin de goto
  2502.  
  2503. /**
  2504. if(Serial.available())
  2505. {
  2506. Serial.readBytes(inputString, 1);
  2507. if (inputString[0] == 'A') // STOP !
  2508. {
  2509. moteur1.set_marche(0);
  2510. moteur2.set_marche(0);
  2511. //PORTA &= ~bit_LED_verte;
  2512. goto_en_cours_xy = 0; // le cas échéant...
  2513. Serial.println("--R: STOP **");
  2514. }
  2515. }
  2516. calcul_x0_y0();
  2517. }
  2518. **/
  2519.  
  2520. }
  2521. }
  2522.  
  2523.  
  2524.  

La class step_motor




C'est un objet perso (Silicium628, code libre et open source).
CODE SOURCE en C++ pour l'Arduino
  1. /*
  2.   step_motor5.cpp
  3.   Cree par Silicium628, 09 nov 2014
  4.   version 3.1
  5.   code free Open source
  6. */
  7.  
  8. #include "Arduino.h"
  9. #include "step_motor5.h"
  10.  
  11.  
  12. Step_Motor::Step_Motor()
  13. {
  14.  
  15. }
  16.  
  17. void Step_Motor::init()
  18. {
  19. marche=0;
  20. sens=0;
  21. disable();
  22. steps_par_mm = steps_par_tour * tours_par_mm;
  23. impuls_par_mm = steps_par_mm * impuls_par_step;
  24. }
  25.  
  26.  
  27. void Step_Motor::set_marche(uint8_t valeur)
  28. {
  29. marche = valeur;
  30.  
  31. }
  32.  
  33.  
  34. uint8_t Step_Motor::get_marche()
  35. {
  36. return marche;
  37. }
  38.  
  39.  
  40. void Step_Motor::enable()
  41. {
  42. PORT_moteur_enable &= ~bit_ENABLE;
  43. }
  44.  
  45.  
  46. void Step_Motor::disable()
  47. {
  48. PORT_moteur_enable |= bit_ENABLE;
  49. }
  50.  
  51.  
  52. void Step_Motor::RAZ_pos()
  53. {
  54. position_impuls=0;
  55. compteur_impuls=0;
  56. }
  57.  
  58.  
  59. void Step_Motor::RAZ_compteur_impuls()
  60. {
  61. compteur_impuls =0;
  62. }
  63.  
  64.  
  65. long Step_Motor::get_compteur_impuls()
  66. {
  67. return compteur_impuls;
  68. }
  69.  
  70.  
  71. void Step_Motor::step()
  72. {
  73. if ( ((sens == 1) && (stop_sens1 == 0) ) || ((sens == 0) && (stop_sens2 == 0) ) )
  74. {
  75. PORT_step |= bit_STEP; // RA1
  76. if (sens == 0) { position_impuls += 1; } else { position_impuls -= 1; } //cette ligne fait également office de tempo pour la largeur de l'impulsion
  77. compteur_impuls++;
  78. PORT_step &= ~bit_STEP; // RAZ
  79. }
  80. }
  81.  
  82.  
  83. void Step_Motor::set_sens(uint8_t valeur)
  84. {
  85. sens = valeur;
  86. if(sens == 0) {PORT_dir |= bit_DIR; } else {PORT_dir &= ~bit_DIR;}
  87. }
  88.  
  89.  
  90. void Step_Motor::set_stop_sens1(uint8_t valeur)
  91. {
  92. stop_sens1 = valeur;
  93. }
  94.  
  95.  
  96. void Step_Motor::set_stop_sens2(uint8_t valeur)
  97. {
  98. stop_sens2 = valeur;
  99. }
  100.  
  101.  
  102. uint8_t Step_Motor::get_sens()
  103. {
  104. return sens;
  105. }
  106.  



CODE SOURCE en C++ pour l'Arduino
  1. /*
  2.   step_motor5.h
  3.   Cree par Silicium628, 9 nov 2014
  4.   code free Open source
  5. */
  6.  
  7. #ifndef STEP_MOTOR4_H
  8. #define STEP_MOTOR4_H
  9.  
  10.  
  11. // ces ports doivent correspondre à la configuration matérielle. On peut les changer ici.
  12. #define PORT_moteur_enable PORTC
  13. #define PORT_fin_de _course PORTK
  14. #define PORT_step PORTL
  15. #define PORT_dir PORTL
  16.  
  17.  
  18. class Step_Motor
  19. {
  20. private :
  21.  
  22. uint8_t sens;
  23. uint8_t marche; // peut prendre les valeurs 0 et 1 mais aussi d'autres valeurs >1 correspondants à des modes de fonctionnement divers.
  24. long compteur_impuls; //32 bits (4 bytes) ; compte les impulsions recues. est incrémenté automatiquement. ne fait qu'augmenter qq soit le sens de rotation.
  25.  
  26.  
  27. public:
  28. Step_Motor();
  29.  
  30. uint8_t bit_ENABLE;
  31. uint8_t bit_finCourse1;
  32. uint8_t bit_finCourse2;
  33. uint8_t bit_STEP;
  34. uint8_t bit_DIR;
  35.  
  36. uint16_t steps_par_tour;
  37. uint8_t tours_par_mm;
  38. uint8_t impuls_par_step;
  39. uint16_t steps_par_mm;
  40. uint16_t impuls_par_mm;
  41.  
  42. uint8_t stop_sens1; // (fin de course)
  43. uint8_t stop_sens2; // (fin de course)
  44.  
  45. long position_impuls; //32 bits (4 bytes) ; nombre d'impulsions; automatiquement incrémenté ou décrémenté par la rotation
  46.  
  47. void init();
  48. void enable();
  49. void disable();
  50. void RAZ_pos();
  51. int32_t get_compteur_impuls();
  52. void RAZ_compteur_impuls();
  53. void step();
  54. void set_sens(uint8_t valeur); // valeur = 0 ou 1.
  55. void set_marche(uint8_t valeur); // valeur = 0 ou 1. (1 -> mise en marche si l'état du stop_sens le permet. 0 -> arret du moteur)
  56. uint8_t get_marche();
  57. uint8_t get_sens();
  58. void set_stop_sens1(uint8_t valeur); // valeur = 0 ou 1. (1->signifie arret du moteur, 0 -> remise en marche possible)
  59. void set_stop_sens2(uint8_t valeur);
  60. };
  61.  
  62.  
  63. #endif
  64.  

12 Le programme de pilotage en C++ & Qt4 pour le PC :

13 Le code source du soft en Qt4 :

CODE SOURCE en Qt4 : le fichier mainwindow.cpp
  1. /*
  2. Gerber
  3. Programme écrit par Silicium628
  4. ce logiciel est libre et open source
  5. */
  6.  
  7. /*
  8. Si le programme ne se lance pas (plante au démarrage), effacer le fichier ~home/.cnc_gerber/cnc_gerber.ini
  9. qui a sans doute été corrompu par un autre programme.
  10. */
  11.  
  12.  
  13.  
  14. #include "mainwindow.h"
  15. #include "math.h"
  16. #include <QFile>
  17. #include <QFileDialog>
  18. #include <QTextStream>
  19. #include <QDebug>
  20. #include "boutonled.cpp"
  21. #include "qled.cpp"
  22. #include <QMessageBox>
  23. #include <QTextCodec>
  24. #include <QTimer>
  25.  
  26. // #include <QMouseEvent>
  27.  
  28.  
  29. QString version = "18.3";
  30.  
  31.  
  32. QColor couleur_ecran = QColor::fromRgb(0x002020); // 0x001A00
  33.  
  34. QColor couleur_piste = QColor::fromRgb(0x999999); // non tracé
  35. QColor couleur_pisteT = QColor::fromRgb(0x1E90FF); // en cours de tracé
  36. QColor couleur_pisteC = QColor::fromRgb(0xFFFF00); // tracée
  37.  
  38. QColor couleur_pastille = QColor::fromRgb(0x999999);// // non tracée
  39. QColor couleur_pastilleT = QColor::fromRgb(0x1E90FF); // en cours de tracé
  40. QColor couleur_pastilleC = QColor::fromRgb(0xFFFF00); // tracée
  41.  
  42. QColor couleur_fait = QColor::fromRgb(255, 0, 0, 255);
  43. QColor couleur_envoye = QColor::fromRgb(0, 100, 0, 255);
  44. QColor couleur_pointage = QColor::fromRgb(0x7F7F7F);
  45. QColor couleur_milieu = QColor::fromRgb(255, 0, 0, 255);
  46. QColor couleur_DT = QColor::fromRgb(0, 255, 0, 255);
  47. QColor couleur_trou = QColor::fromRgb(0, 0, 0, 255);
  48. QColor couleur_texte = QColor::fromRgb(255, 255, 255, 255);
  49. QColor couleur_erreur = QColor::fromRgb(255, 255, 100, 255);
  50.  
  51. QBrush brush_pastille;
  52. QBrush brush_milieu;
  53. QBrush brush_DT;
  54. QBrush brush_trou;
  55.  
  56. QPen pen_piste(couleur_piste, 2, Qt::SolidLine);
  57. QPen pen_pastille(couleur_pastille, 1, Qt::SolidLine);
  58. QPen pen_trou(couleur_trou, 1, Qt::SolidLine);
  59. QPen pen_pointage(couleur_pointage, 1, Qt::SolidLine);
  60. QPen pen_milieu(couleur_milieu, 1, Qt::SolidLine);
  61. QPen pen_DT(couleur_DT, 1, Qt::SolidLine);
  62.  
  63. int x_scene, y_scene;
  64.  
  65. QStringList liste_gerber1;
  66. QList <Aperture> liste_apertures; //<aperture> désigne une structure déclarée dans le mainwindow.h
  67. QList <Element> liste_elements; // tous types confondus, segments et pastilles
  68. QList <Element> liste_elements_tries;
  69. QList <Element> liste_pastilles; // en vue de les "creuser" logiciellement (ici) en raccourcissant les segments qui y aboutissent
  70. QList <Element> liste_segments;
  71. QList <Element> liste_trous;
  72.  
  73. //QString dir_gerber;
  74. QString fileName_en_cours;
  75.  
  76. quint8 num_ap_use; // numéro de l'aperture en service lors de la phase de traçage
  77. QString s_aperture_use; // même chose en texte (D10, D11... etc)
  78.  
  79. quint16 num_ligne_en_cours1;
  80. quint16 num_ligne_en_cours3;
  81. quint16 num_ligne3;
  82. quint16 nb_lignes_envoyees =0;
  83. quint16 i_dess_tri;
  84. quint16 nb_erreurs =0;
  85. quint16 nb_pistes_nulles; // décrivant des déplacements ou des tracés de pste de longueur = 0
  86. quint16 nb_corrections =0;
  87.  
  88. quint16 num_element_proche_en_cours =0;
  89.  
  90. float zoom;
  91. float ech;
  92.  
  93.  
  94. qint16 Xcent, Ycent; // en 1/100 mm
  95. qint16 memo_X, memo_Y;
  96. QPointF pos_actuelle;
  97. qint16 X_max =0; // coordonné X max la plus grande parmis toutes celles de tous les éléments du circuit (servira à faire un miroir_x)
  98. qint16 Y_max =0; // coordonné Y max la plus grande parmis toutes celles de tous les éléments du circuit
  99.  
  100.  
  101. quint8 connect_ok =0;
  102. quint8 recu_PRET =0;
  103. quint8 flashage_en_cours = 0;
  104. quint8 simulation = 0;
  105. quint8 laser_on = 0; // allumage du laser en continu. POURS TESTS SEULEMENT !
  106. quint8 laser_bloque = 0; // empêche l'allumage du laser si =1 ; pour tests déplacements laser éteint
  107. quint8 trace_aspect_reel;
  108. quint8 findecourse = 0;
  109.  
  110. quint8 miroir=0;
  111. quint8 pastilles_creuses=0;
  112.  
  113. char buffer[100];
  114. QString msg ="";
  115.  
  116.  
  117. qreal sqr(qreal r1)
  118. {
  119. return r1 * r1;
  120. }
  121.  
  122.  
  123. QString valeur2txt4(int v1)
  124. {
  125. QString s;
  126. s.setNum(v1); // conversion num -> txt
  127. s = "0000"+s;
  128. s = s.right(4);
  129. return s;
  130. }
  131.  
  132.  
  133. QString valeur2txt2(int v1)
  134. {
  135. QString s;
  136. s.setNum(v1); // conversion num -> txt
  137. s = "00"+s;
  138. s = s.right(2);
  139. return s;
  140. }
  141.  
  142.  
  143.  
  144. MainWindow::MainWindow(QWidget *parent) :
  145. QMainWindow(parent)
  146. {
  147.  
  148. setupUi(this);
  149. setWindowTitle("Gerber Photoplotter v:" + version + " - Silicium628");
  150. window()->setGeometry(0,0,1279,1023);
  151.  
  152. scene1 = new SceneCliquable(this);
  153.  
  154. InitTable3();
  155. InitTable4();
  156. InitTable5();
  157.  
  158. brush_pastille.setColor(couleur_pastille);
  159. brush_pastille.setStyle(Qt::SolidPattern);
  160.  
  161. brush_milieu.setColor(couleur_milieu);
  162. brush_milieu.setStyle(Qt::SolidPattern);
  163.  
  164. brush_DT.setColor(couleur_DT);
  165. brush_DT.setStyle(Qt::SolidPattern);
  166.  
  167. brush_trou.setColor(couleur_trou);
  168. brush_trou.setStyle(Qt::SolidPattern);
  169.  
  170. pen_piste.setCapStyle(Qt::RoundCap); // extrémités des pistes arrondies - voir QPen dans la doc.
  171.  
  172. QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
  173.  
  174.  
  175. effacer_ecran(); // et crée les groupes héritiers de la scene ainsi que la connexion entre les clics et le slot ici concerné
  176.  
  177. BoutonLed1 = new QBoutonLed(frame_10);
  178. BoutonLed1->setGeometry(QRect(4, 4, 40, 40));
  179. BoutonLed1->setCouleur(QColor (0,255,0));
  180. connect(BoutonLed1, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed1_toggled(bool)));
  181.  
  182. BoutonLed2 = new QBoutonLed(frame_12);
  183. BoutonLed2->setGeometry(QRect(4, 4, 40, 40));
  184. BoutonLed2->setCouleur(QColor::fromRgb(0x1E90FF));
  185. connect(BoutonLed2, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed2_toggled(bool)));
  186.  
  187. trace_aspect_reel=1;
  188.  
  189. BoutonLed3 = new QBoutonLed(frame_3); // allumage laser
  190. BoutonLed3->setGeometry(QRect(4, 4, 40, 40));
  191. BoutonLed3->setCouleur(QColor::fromRgb(0x1E90FF));
  192. connect(BoutonLed3, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed3_toggled(bool)));
  193.  
  194. BoutonLed4 = new QBoutonLed(frame_17); // blocage laser
  195. BoutonLed4->setGeometry(QRect(4, 4, 40, 40));
  196. BoutonLed4->setCouleur(QColor::fromRgb(0xFF0000));
  197. connect(BoutonLed4, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed4_toggled(bool)));
  198.  
  199.  
  200. Led0 = new QLed(frame1); // Connexion USB ; verte = ok ; rouge = impossible
  201. Led0->setForme(1);
  202. Led0->setGeometry(QRect(4, 4, 40, 40));
  203. Led0->setCouleur(QColor (0,255,0));
  204. Led0->setEtat(0);
  205.  
  206. //=======================================================================================
  207. // jaune = Connexion USB établie, attente message bienvenue ; verte message "ATMEGA" reçu
  208. Led1 = new QLed(frame_4);
  209. Led1->setForme(1);
  210. Led1->setGeometry(QRect(4, 4, 40, 40));
  211. Led1->setCouleur(QColor (255,255,0));
  212. Led1->setEtat(0);
  213.  
  214. //=======================================================================================
  215. // envoi commande par USB ; jaune = message envoyé - verte = reçu réponse ("PRET")
  216. Led2 = new QLed(frame_6);
  217. Led2->setForme(1);
  218. Led2->setGeometry(QRect(4, 4, 40, 40));
  219. Led2->setCouleur(QColor (255,255,0));
  220. Led2->setEtat(0);
  221.  
  222. //=======================================================================================
  223. // VERTE ; allumée (verte) = flashage en cours
  224. Led3 = new QLed(frame_7);
  225. Led3->setForme(1);
  226. Led3->setGeometry(QRect(4, 4, 40, 40));
  227. Led3->setCouleur(QColor (0,255,0)); // VERTE
  228. Led3->setEtat(0);
  229.  
  230. //=======================================================================================
  231. // ROUGE, ronde ; allumée = FIN DE COURSE ACTIF !
  232. Led4 = new QLed(frame_11);
  233. Led4->setForme(2); // ronde
  234. Led4->setGeometry(QRect(4, 4, 40, 40));
  235. Led4->setCouleur(QColor (255,0,0)); // ROUGE
  236. Led4->setEtat(0);
  237.  
  238. //=======================================================================================
  239. Timer1 = new QTimer(this);
  240. connect(Timer1, SIGNAL(timeout()), this, SLOT(Timer1_clic()));
  241.  
  242. Timer2 = new QTimer(this);
  243. connect(Timer2, SIGNAL(timeout()), this, SLOT(Timer2_clic()));
  244.  
  245.  
  246. memo_X =0;
  247. memo_Y =0;
  248. num_ligne_en_cours1 = 0;
  249.  
  250. spinBox_zoom2->setValue(5);
  251.  
  252.  
  253. // QString filename = "./Fichiers_gerber/attenuateur-F_Cu.gtl";
  254. // QString filename = "./Fichiers_gerber/largeur_pistes-B_Cu.gbl";
  255. fileName_en_cours = "./Fichiers_gerber/largeur_pistes-F_Cu.gtl";
  256.  
  257. lecture_fichier_init();
  258.  
  259.  
  260. lineEdit_6->setText(fileName_en_cours);
  261.  
  262. int result = lire_fichier_gerber(fileName_en_cours);
  263.  
  264. if (result == 0)
  265. {
  266. analyse_fichier_gerber();
  267. //tout_decliquer();
  268. //dessiner_liste_elements_tries();
  269. classer_auto();
  270. trace_liste_apertures();
  271. on_BoutonLed2_toggled(true);
  272. BoutonLed2->setChecked(true);
  273. }
  274.  
  275. BoutonLed4->setChecked(1);
  276. }
  277.  
  278.  
  279.  
  280. MainWindow::~MainWindow()
  281. {
  282.  
  283. }
  284.  
  285.  
  286.  
  287.  
  288. void MainWindow::InitTable3()
  289. {
  290. QStringList liste_entetes;
  291. tableWidget_3->clear();
  292.  
  293. liste_entetes <<"CMD"<<"longueur";
  294.  
  295. tableWidget_3->setHorizontalHeaderLabels (liste_entetes);
  296. tableWidget_3->setColumnCount(2);
  297. tableWidget_3->setRowCount(1);
  298.  
  299. }
  300.  
  301.  
  302. void MainWindow::InitTable4()
  303. {
  304. QStringList liste_entetes;
  305. liste_entetes <<"CMD";
  306.  
  307. tableWidget_4->clear();
  308. tableWidget_4->setColumnCount(2);
  309. tableWidget_4->setRowCount(0);
  310. tableWidget_4->setHorizontalHeaderLabels (liste_entetes);
  311.  
  312. }
  313.  
  314.  
  315. void MainWindow::InitTable5()
  316. {
  317. QStringList liste_entetes;
  318.  
  319. tableWidget_5->clear();
  320. tableWidget_5->setColumnCount(2);
  321. tableWidget_5->setRowCount(0);
  322. tableWidget_5->setHorizontalHeaderLabels (liste_entetes);
  323.  
  324. }
  325.  
  326.  
  327.  
  328. void MainWindow::effacer_ecran()
  329. {
  330. scene1->clear();
  331. scene1 = new SceneCliquable(this);
  332. connect(scene1, SIGNAL(envoiPosition(int, int) ), this, SLOT (onReceptPos(int, int) ));
  333.  
  334. scene1->setBackgroundBrush(couleur_ecran);
  335. scene1->setSceneRect(-800,-1200,2000,2000); // plus grand que la partie affichée
  336. graphicsView1->setScene(scene1);
  337. graphicsView1->setGeometry(5,10,896,611); // POSITION et dimensions de l'écran
  338. graphicsView1->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
  339.  
  340. groupe_trace = new QGraphicsItemGroup();
  341. scene1->addItem(groupe_trace);
  342.  
  343. groupe_segments_faits = new QGraphicsItemGroup();
  344. scene1->addItem(groupe_segments_faits);
  345.  
  346. groupe_pastilles_faites = new QGraphicsItemGroup();
  347. scene1->addItem(groupe_pastilles_faites);
  348.  
  349. groupe_pointage = new QGraphicsItemGroup();
  350. scene1->addItem(groupe_pointage);
  351.  
  352. groupe_trous = new QGraphicsItemGroup();
  353. scene1->addItem(groupe_trous);
  354.  
  355. }
  356.  
  357.  
  358.  
  359. void MainWindow::effacer_pointage()
  360. {
  361. foreach( QGraphicsItem *item, groupe_pointage->childItems() )
  362. {
  363. delete item;
  364. }
  365. }
  366.  
  367.  
  368. void MainWindow::lecture_fichier_init()
  369. {
  370. QString line, tx1, tx2;
  371. int p2;
  372. tx1 = "";
  373.  
  374. QFile file1(QDir::homePath() + "/.cnc_gerber/cnc_gerber.ini");
  375.  
  376. if (file1.open(QIODevice::ReadOnly | QIODevice::Text))
  377. {
  378. QTextStream in(&file1);
  379. in.reset();
  380. while ( !in.atEnd() )
  381. {
  382. line = in.readLine();
  383. if (line.left(1) !="#")
  384. {
  385. if (line.indexOf("fileName_en_cours") != -1)
  386. {
  387. if ( (p2 = line.indexOf('=')) != -1)
  388. {
  389. line.remove(0,p2+1);
  390. fileName_en_cours = line;
  391. }
  392. }
  393. }
  394. }
  395. file1.close();
  396. } else { fileName_en_cours = ""; tx1 = "fichier .ini non trouve, ce n'est pas grave !"; }
  397.  
  398. if (tx1 !="")
  399. {
  400. QMessageBox msgBox;
  401. msgBox.setText(tx1);
  402. msgBox.exec();
  403. }
  404. // statusBar1->showMessage(tx1 + " "+ tx2);
  405. }
  406.  
  407.  
  408.  
  409. void MainWindow::enregistrer_fichier_init()
  410. {
  411. QDir dossierIni(QDir::homePath() + "/.cnc_gerber/");
  412. if (!dossierIni.exists())
  413.  
  414. {
  415. QMessageBox msgBox;
  416. msgBox.setText("Le repertoire : ~/" + dossierIni.dirName() + " n'existe pas, je vais le creer, et y placer le fichier de configuration 'cnc_gerber.ini' ");
  417. msgBox.exec();
  418. QDir dossierPerso(QDir::homePath());
  419. dossierPerso.mkdir(".cnc_gerber");
  420. }
  421.  
  422. QFile file1(QDir::homePath() + "/.cnc_gerber/cnc_gerber.ini");
  423. if (file1.open(QIODevice::WriteOnly | QIODevice::Text))
  424. {
  425. QTextStream out(&file1);
  426. QString V;
  427.  
  428. out << "# les lignes commeneant par # sont ignorees";
  429. out << '\n';
  430. out << "# Ce fichier est genere automatiquement par le programme";
  431. out << '\n';
  432. out << "#";
  433. out << '\n';
  434.  
  435. out << "fileName_en_cours=" << fileName_en_cours;
  436. out << '\n';
  437. }
  438. file1.close();
  439. }
  440.  
  441.  
  442.  
  443. int MainWindow::lire_fichier_gerber(QString nom_fichier1)
  444. {
  445. QFile file1(nom_fichier1);
  446.  
  447. if( !file1.exists() )
  448. {
  449. qDebug() << "Le fichier n'existe pas.";
  450. return 1;
  451. }
  452.  
  453. QString s1;
  454.  
  455. liste_gerber1.clear();
  456. listWidget_1->clear();
  457.  
  458. if (!file1.open(QIODevice::ReadOnly | QIODevice::Text)) return 1;
  459. QTextStream in1(&file1);
  460.  
  461. int num_ligne = 0;
  462. while ( !in1.atEnd() )
  463. {
  464. num_ligne++;
  465. s1.setNum(num_ligne);// conversion num -> txt
  466. QString line_i = in1.readLine();
  467. listWidget_1->addItem(s1+": "+line_i);
  468. liste_gerber1 << line_i;
  469. }
  470. file1.close();
  471. Btn_creuser_pastilles->setEnabled(true);
  472. checkBox_miroir->setChecked(false);
  473.  
  474.  
  475.  
  476. return 0;
  477.  
  478. }
  479.  
  480.  
  481.  
  482. void MainWindow::pointer(int i)
  483. { // à l'écran
  484.  
  485. QPoint M;
  486. Element element_i;
  487. element_i = liste_elements_tries[i];
  488. M = element_i.M;
  489.  
  490. effacer_pointage();
  491.  
  492. M.setY(-M.y());// symétrie verticale
  493. M /= ech;
  494.  
  495.  
  496. // trace ligne verticale
  497. QGraphicsLineItem *segment_pointage1 = new QGraphicsLineItem(groupe_pointage);
  498. segment_pointage1->setPen(pen_pointage);
  499. segment_pointage1->setLine(M.x()+1, -1000, M.x()+1, 1000); // le '+1' évite de masquer la couleur de l'élément pointé si très fin (=1 pixel)
  500.  
  501. // trace ligne horizontale
  502. QGraphicsLineItem *segment_pointage2 = new QGraphicsLineItem(groupe_pointage);
  503. segment_pointage2->setPen(pen_pointage);
  504. segment_pointage2->setLine(-1000, M.y()+1, 1000, M.y()+1);
  505. }
  506.  
  507.  
  508.  
  509. void MainWindow::tracer_mire_origine()
  510. { // à l'écran
  511. QPoint P;
  512.  
  513. P.setX(0);
  514. P.setY(0);
  515. P /= ech;
  516.  
  517.  
  518. QGraphicsLineItem *segment_pointage1 = new QGraphicsLineItem(groupe_pointage);
  519. segment_pointage1->setPen(pen_pointage);
  520. segment_pointage1->setLine(P.x()-10, P.x()-10, P.x()+10, P.x()+10);
  521.  
  522. QGraphicsLineItem *segment_pointage2 = new QGraphicsLineItem(groupe_pointage);
  523. segment_pointage2->setPen(pen_pointage);
  524. segment_pointage2->setLine(P.x()-10, P.x()+10, P.x()+10, P.x()-10);
  525. tracer_texte(-20, -20, "(x=0; y=0)");
  526.  
  527. }
  528.  
  529.  
  530.  
  531. void MainWindow::tracer_segment(QPoint A, QPoint B, qreal largeur, QColor couleur_i, QGraphicsItemGroup *groupe_i )
  532. { // à l'écran
  533.  
  534. QPoint M; // milieu
  535. QPoint DT; // deux tiers
  536.  
  537. QLine SEG;
  538.  
  539. A.setY(-A.y());// symétrie verticale
  540. B.setY(-B.y());
  541.  
  542. A /= ech;
  543. B /= ech;
  544.  
  545. SEG.setPoints(A,B);
  546.  
  547. M.setX((A.x()+B.x())/2);
  548. M.setY((A.y()+B.y())/2);
  549.  
  550. DT.setX( A.x()/3 + 2*B.x()/3 );
  551. DT.setY( A.y()/3 + 2*B.y()/3 );
  552.  
  553. largeur /= ech;
  554. if (largeur <1) {largeur = 1;}
  555.  
  556. QGraphicsLineItem *segment_trace = new QGraphicsLineItem(groupe_i);
  557. pen_piste.setWidth(largeur);
  558. pen_piste.setColor(couleur_i);
  559. segment_trace->setPen(pen_piste);
  560. segment_trace->setLine (SEG );
  561.  
  562.  
  563. QGraphicsEllipseItem *ellipse1 = new QGraphicsEllipseItem (groupe_i); // repere de selection au centre du segment
  564. pen_piste.setWidth(1);
  565. ellipse1->setPen(pen_milieu);
  566. ellipse1->setBrush(brush_milieu);
  567. ellipse1->setRect(M.x()-1, M.y()-1, 2, 2);
  568.  
  569. QGraphicsEllipseItem *ellipse2 = new QGraphicsEllipseItem (groupe_i); // repere au 2/3 du segment
  570. pen_piste.setWidth(1);
  571. ellipse2->setPen(pen_DT);
  572. ellipse2->setBrush(brush_DT);
  573. ellipse2->setRect(DT.x()-1, DT.y()-1, 2, 2);
  574. }
  575.  
  576.  
  577.  
  578. void MainWindow::tracer_pastille_rectangulaire(QPoint A, QPoint B, QColor couleur_i, QGraphicsItemGroup *groupe_i)
  579. { // à l'écran
  580. // A est le coin en bas à gauche, B est le coin en haut à droite
  581.  
  582. qreal w, h;
  583. qreal n;
  584. qreal x1, y1, x2, y2;
  585. qreal largeur_trait, d;
  586.  
  587. A.setY(-A.y());// symétrie verticale
  588. B.setY(-B.y());
  589.  
  590. A /= ech;
  591. B /= ech;
  592.  
  593. w = (A-B).x(); // largeur pastille
  594. h = (A-B).y(); // hauteur
  595.  
  596.  
  597. if(trace_aspect_reel == 0)
  598. {
  599. QGraphicsRectItem *rectangle = new QGraphicsRectItem(groupe_i);
  600. brush_pastille.setColor(couleur_i);
  601. rectangle->setBrush(brush_pastille);
  602. rectangle->setRect(A.x()-w/2, A.y()-h/2, w, h);
  603. }
  604.  
  605. if(trace_aspect_reel == 1)
  606. {
  607. largeur_trait = 10; // à transmettre par paramètre...
  608. largeur_trait /= ech;
  609.  
  610.  
  611. pen_piste.setWidth(largeur_trait);
  612. pen_piste.setColor(couleur_i);
  613.  
  614. n=0.5;
  615. int stop =0;
  616. while ((n<6) && (stop == 0))
  617. {
  618. d= 2 * n * largeur_trait;
  619. if (d > (-w/2) || d > (h/2)) {stop =1;}
  620.  
  621. //---------------------------------------------------------------------------------
  622. x1=A.x()-w/2 - d;
  623. y1=A.y()-h/2 + d;
  624. x2=A.x()+w/2 + d;
  625. y2=A.y()-h/2 + d;
  626.  
  627. QGraphicsLineItem *segment_trace1 = new QGraphicsLineItem(groupe_i);
  628. segment_trace1->setPen(pen_piste);
  629. segment_trace1->setLine (x1,y1,x2,y2);
  630. //---------------------------------------------------------------------------------
  631. x1=A.x()+w/2 + d;
  632. y1=A.y()-h/2 + d;
  633. x2=A.x()+w/2 + d;
  634. y2=A.y()+h/2 - d;
  635.  
  636. QGraphicsLineItem *segment_trace2 = new QGraphicsLineItem(groupe_i);
  637. segment_trace2->setPen(pen_piste);
  638. segment_trace2->setLine (x1,y1,x2,y2);
  639. //---------------------------------------------------------------------------------
  640.  
  641. x1=A.x()+w/2 + d;
  642. y1=A.y()+h/2 - d;
  643. x2=A.x()-w/2 - d;
  644. y2=A.y()+h/2 - d;
  645.  
  646. QGraphicsLineItem *segment_trace3 = new QGraphicsLineItem(groupe_i);
  647. segment_trace3->setPen(pen_piste);
  648. segment_trace3->setLine (x1,y1,x2,y2);
  649. //---------------------------------------------------------------------------------
  650.  
  651. x1=A.x()-w/2 - d;
  652. y1=A.y()+h/2 - d;
  653. x2=A.x()-w/2 - d;
  654. y2=A.y()-h/2 + d;
  655.  
  656. QGraphicsLineItem *segment_trace4 = new QGraphicsLineItem(groupe_i);
  657. segment_trace4->setPen(pen_piste);
  658. segment_trace4->setLine (x1,y1,x2,y2);
  659.  
  660. n++;
  661. }
  662. }
  663.  
  664. }
  665.  
  666.  
  667. void MainWindow::tracer_trou(QPoint A, quint16 diametre)
  668. { // à l'écran
  669. qreal x, y;
  670.  
  671. A.setY(-A.y());// symétrie verticale
  672. A /= ech;
  673.  
  674. x=A.x();
  675. y=A.y();
  676.  
  677. diametre /= ech;
  678.  
  679. QGraphicsEllipseItem *ellipse1 = new QGraphicsEllipseItem (groupe_trous); // PASTILLE
  680. ellipse1->setBrush(brush_trou);
  681.  
  682. ellipse1->setRect(x-diametre/2, y-diametre/2, diametre, diametre);
  683. }
  684.  
  685.  
  686.  
  687.  
  688. void MainWindow::tracer_pastille_ronde(QPoint A, QPoint B, QColor couleur_i, QGraphicsItemGroup *groupe_i)
  689. { // à l'écran
  690.  
  691. qreal w, h;
  692. qreal n;
  693. qreal x, y;
  694. qreal largeur_trait, d, rt;
  695.  
  696. rt = 80 / ech; // rayon du trou
  697.  
  698. A.setY(-A.y());// symétrie verticale
  699. B.setY(-B.y());// symétrie verticale
  700.  
  701. A /= ech;
  702. B /= ech;
  703.  
  704. w = A.x()-B.x();
  705. h = A.y()-B.y();
  706.  
  707. if (h<(100/ech)) {rt=0;} // ne pas percer les très petites pastilles qui sont des raccordements de pistes
  708.  
  709. brush_pastille.setColor(couleur_i);
  710.  
  711.  
  712. if(trace_aspect_reel == 0)
  713. {
  714. // trace un disque plein
  715. QGraphicsEllipseItem *ellipse1 = new QGraphicsEllipseItem (groupe_i); // PASTILLE
  716. ellipse1->setBrush(brush_pastille);
  717.  
  718. x=A.x()-w/2;
  719. y=A.y()-h/2;
  720.  
  721. ellipse1->setRect(x, y, w, h);
  722. }
  723.  
  724.  
  725. if(trace_aspect_reel == 1)
  726. {
  727. // trace des cercles concentriques avec l'épaisseur de la plume
  728. largeur_trait = 10; // à transmettre par paramètre...
  729. largeur_trait /= ech;
  730.  
  731. pen_piste.setWidth(largeur_trait);
  732. pen_piste.setColor(couleur_i);
  733.  
  734. n=0.5;
  735. int stop =0;
  736. while ((n<12) && (stop == 0))
  737. {
  738. d= 2.5 * n * largeur_trait;
  739.  
  740. // if (d > (-w/2) || d > (h/2)) {stop =1;}
  741. if ((h-d) < rt ) {stop =1;}
  742. //---------------------------------------------------------------------------------
  743.  
  744. QGraphicsEllipseItem *ellipse1 = new QGraphicsEllipseItem ();
  745. ellipse1->setPen(pen_piste);
  746.  
  747. x=A.x()-w/2;
  748. y=A.y()-h/2;
  749.  
  750. ellipse1->setRect(x-d/2, y+d/2, w+d, h-d);
  751. groupe_i->addToGroup(ellipse1);
  752.  
  753. //---------------------------------------------------------------------------------
  754.  
  755. n++;
  756. }
  757. }
  758. }
  759.  
  760.  
  761. void MainWindow::tracer_texte(int x, int y, QString texte_i)
  762. { // à l'écran
  763. y=-y;
  764.  
  765. x /= ech;
  766. y /= ech;
  767.  
  768. QGraphicsTextItem *gtexte = new QGraphicsTextItem(groupe_trace);
  769. gtexte->setDefaultTextColor(couleur_texte);
  770. gtexte->setPos(x,y);
  771. gtexte->setPlainText(texte_i);
  772. }
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779.  
  780. int MainWindow::dessine_1ligne_liste_triee(int i) // dessine à l'écran 1 ligne de la "liste_elements_tries"
  781. {
  782. QColor couleur1;
  783. char sorte_i;
  784. char forme_i;
  785. int clique_i;
  786. QPoint A, B, M, WH; // M : milieu de l'élément
  787. quint8 num_ap, w;
  788. Element element_i;
  789. Aperture aperture_i;
  790.  
  791. // liste_elements_i = *lst_elm;
  792. int i_max = liste_elements_tries.count();
  793. if (i>i_max) {return 1;}
  794. element_i = liste_elements_tries[i];
  795. sorte_i = element_i.sorte;
  796. clique_i = element_i.clique;
  797.  
  798. A = element_i.A;
  799. B = element_i.B;
  800. M = element_i.M;
  801.  
  802. num_ap = element_i.num_aperture-10;
  803.  
  804. int n_max = liste_apertures.length();
  805. if (num_ap >= n_max) {return 1;}
  806.  
  807. aperture_i = liste_apertures[num_ap];
  808.  
  809. WH = aperture_i.WH;
  810. w = WH.x();
  811.  
  812. forme_i=aperture_i.forme;
  813.  
  814. if (sorte_i == 'S') // SEGMENT
  815. {
  816. if (clique_i == 0) { couleur1 = couleur_piste;}; // non tracée
  817. if (clique_i == 1) { couleur1 = couleur_pisteT;} // en cours de traçage
  818. if (clique_i > 1) { couleur1 = couleur_pisteC;}