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
Sommaire :
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++ & Qt5 pour le PC :
13 - Le code source du soft en Qt5 :
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
53 - Version du soft en QT5
54 - Réduction de la taille de la fenêtre du programme
55 - Nouveau format des fichiers Gerber
56 - La version du nouveau Kicad
57 - Nouvelle version disponible

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

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

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_motor6.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_motor6.h"
  10.  
  11.  
  12. #define _nop_() do { __asm__ volatile ("mov r0, r0"); } while (0)
  13.  
  14. Step_Motor::Step_Motor()
  15. {
  16.  
  17. }
  18.  
  19. void Step_Motor::init()
  20. {
  21. marche=0;
  22. sens=0;
  23. disable();
  24. steps_par_mm = steps_par_tour * tours_par_mm;
  25. impuls_par_mm = steps_par_mm * impuls_par_step;
  26. }
  27.  
  28.  
  29. void Step_Motor::set_marche(uint8_t valeur)
  30. {
  31. marche = valeur;
  32. }
  33.  
  34.  
  35. uint8_t Step_Motor::get_marche()
  36. {
  37. return marche;
  38. }
  39.  
  40.  
  41. void Step_Motor::enable()
  42. {
  43. PORT_moteur_enable &= ~bit_ENABLE;
  44. }
  45.  
  46.  
  47. void Step_Motor::disable()
  48. {
  49. PORT_moteur_enable |= bit_ENABLE;
  50. }
  51.  
  52.  
  53. void Step_Motor::RAZ_pos()
  54. {
  55. position_impuls=0;
  56. compteur_impuls=0;
  57. }
  58.  
  59.  
  60. void Step_Motor::RAZ_compteur_impuls()
  61. {
  62. compteur_impuls =0;
  63. }
  64.  
  65.  
  66. long Step_Motor::get_compteur_impuls()
  67. {
  68. return compteur_impuls;
  69. }
  70.  
  71.  
  72. void Step_Motor::step()
  73. {
  74. if ( ((sens == 1) && (stop_sens1 == 0) ) || ((sens == 0) && (stop_sens2 == 0) ) )
  75. {
  76. PORT_step |= bit_STEP; // RA1
  77. if (sens == 0) { position_impuls += 1; } else { position_impuls -= 1; }
  78. compteur_impuls++;
  79. PORT_led_blanche ^= bit_LED_blanche; // cette ligne sert surtout de tempo pour la largeur d'impulsion
  80. PORT_step &= ~bit_STEP; // RAZ
  81. }
  82. }
  83.  
  84.  
  85. void Step_Motor::set_sens(uint8_t valeur)
  86. {
  87. sens = valeur;
  88. if(sens == 0) {PORT_dir |= bit_DIR; } else {PORT_dir &= ~bit_DIR;}
  89. }
  90.  
  91.  
  92. void Step_Motor::set_stop_sens1(uint8_t valeur)
  93. {
  94. stop_sens1 = valeur;
  95. }
  96.  
  97.  
  98. void Step_Motor::set_stop_sens2(uint8_t valeur)
  99. {
  100. stop_sens2 = valeur;
  101. }
  102.  
  103.  
  104. uint8_t Step_Motor::get_sens()
  105. {
  106. return sens;
  107. }
  108.  



CODE SOURCE en C++ pour l'Arduino
  1. /*
  2.   step_motor6.h
  3.   Cree par Silicium628, 9 nov 2014
  4.   code free Open source
  5. */
  6.  
  7. #ifndef STEP_MOTOR6_H
  8. #define STEP_MOTOR6_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. #define PORT_led_blanche PORTC
  18. #define bit_LED_blanche 0b01000000;
  19.  
  20. class Step_Motor
  21. {
  22. private :
  23.  
  24. uint8_t sens;
  25. uint8_t marche; // peut prendre les valeurs 0 et 1 mais aussi d'autres valeurs >1 correspondants à des modes de fonctionnement divers.
  26. 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.
  27.  
  28.  
  29. public:
  30. Step_Motor();
  31.  
  32. uint8_t bit_ENABLE;
  33. uint8_t bit_finCourse1;
  34. uint8_t bit_finCourse2;
  35. uint8_t bit_STEP;
  36. uint8_t bit_DIR;
  37.  
  38. uint16_t steps_par_tour;
  39. uint8_t tours_par_mm;
  40. uint8_t impuls_par_step;
  41. uint16_t steps_par_mm;
  42. uint16_t impuls_par_mm;
  43.  
  44. uint8_t stop_sens1; // (fin de course)
  45. uint8_t stop_sens2; // (fin de course)
  46.  
  47. long position_impuls; //32 bits (4 bytes) ; nombre d'impulsions; automatiquement incrémenté ou décrémenté par la rotation
  48.  
  49. void init();
  50. void enable();
  51. void disable();
  52. void RAZ_pos();
  53. int32_t get_compteur_impuls();
  54. void RAZ_compteur_impuls();
  55. void step();
  56. void set_sens(uint8_t valeur); // valeur = 0 ou 1.
  57. 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)
  58. uint8_t get_marche();
  59. uint8_t get_sens();
  60. void set_stop_sens1(uint8_t valeur); // valeur = 0 ou 1. (1->signifie arret du moteur, 0 -> remise en marche possible)
  61. void set_stop_sens2(uint8_t valeur);
  62. };
  63.  
  64.  
  65. #endif
  66.  

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

13 Le code source du soft en Qt5 :

CODE SOURCE en Qt : 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. #include "mainwindow.h"
  14. #include "math.h"
  15. #include <QFile>
  16. #include <QFileDialog>
  17. #include <QTextStream>
  18. #include <QDebug>
  19. #include "boutonled.cpp"
  20. #include "qled.cpp"
  21. #include <QMessageBox>
  22. #include <QTextCodec>
  23. #include <QTimer>
  24. #include <stdlib.h> /* atoi */
  25. #include <QScrollBar>
  26. #include <QProcess>
  27.  
  28.  
  29. // #include <QMouseEvent>
  30.  
  31.  
  32. QString version = "23.5";
  33.  
  34.  
  35. QColor couleur_ecran = QColor::fromRgb(0x002020); // 0x001A00
  36.  
  37. QColor couleur_piste1 = QColor::fromRgb(0x147E00); // non flashée1 0xF57900
  38. QColor couleur_piste2 = QColor::fromRgb(0x999999); // non flashée2
  39.  
  40. QColor couleur_pisteT = QColor::fromRgb(0x1E90FF); // en cours de tracé
  41. QColor couleur_pisteC = QColor::fromRgb(0x179CFF); // flashée
  42.  
  43. QColor couleur_pastille1 = QColor::fromRgb(0xFCE94F);// non flashée
  44. QColor couleur_pastilleT = QColor::fromRgb(0x1E90FF); // en cours de tracé
  45. QColor couleur_pastilleC = QColor::fromRgb(0x179CFF); // flashée
  46.  
  47. QColor couleur_fait = QColor::fromRgb(255, 0, 0, 255);
  48. QColor couleur_envoye = QColor::fromRgb(0, 100, 0, 255);
  49. QColor couleur_pointage = QColor::fromRgb(0x1B85FF);
  50. QColor couleur_milieu = QColor::fromRgb(255, 0, 0, 255);
  51. QColor couleur_DT = QColor::fromRgb(0, 255, 0, 255);
  52. QColor couleur_trou = QColor::fromRgb(0, 0, 0, 255);
  53. QColor couleur_texte = QColor::fromRgb(255, 255, 255, 255);
  54. QColor couleur_erreur = QColor::fromRgb(255, 255, 100, 255);
  55.  
  56. QBrush brush_pastille;
  57. QBrush brush_milieu;
  58. QBrush brush_DT;
  59. QBrush brush_trou;
  60.  
  61. QPen pen_piste(couleur_piste1, 2, Qt::SolidLine);
  62. QPen pen_pastille(couleur_pastille1, 1, Qt::SolidLine);
  63. QPen pen_trou(couleur_trou, 1, Qt::SolidLine);
  64. QPen pen_pointage(couleur_pointage, 1, Qt::SolidLine);
  65. QPen pen_milieu(couleur_milieu, 1, Qt::SolidLine);
  66. QPen pen_DT(couleur_DT, 1, Qt::SolidLine);
  67.  
  68. int x_scene, y_scene;
  69. int memo_x, memo_y;
  70.  
  71. QStringList liste_gerber1;
  72. QList <Aperture> liste_apertures; //<aperture> désigne une structure déclarée dans le mainwindow.h
  73. QList <Element> liste_elements; // tous types confondus, segments et pastilles
  74. QList <Element> liste_elements_tries;
  75. QList <Element> liste_pastilles; // en vue de les "creuser" logiciellement (ici) en raccourcissant les segments qui y aboutissent
  76. QList <Element> liste_segments;
  77. QList <Element> liste_trous;
  78.  
  79. //QString dir_gerber;
  80. QString fileName_en_cours;
  81. QStringList liste_log;
  82.  
  83. QString s_type;
  84. QString s_format;
  85. quint8 num_ap_use; // numéro de l'aperture en service lors de la phase de traçage
  86. QString s_aperture_use; // même chose en texte (D10, D11... etc)
  87.  
  88. quint16 num_ligne_en_cours1;
  89. quint16 num_ligne_en_cours3;
  90. quint16 num_ligne3;
  91. quint16 nb_lignes_envoyees =0;
  92. quint16 i_dess_tri;
  93. quint16 nb_erreurs =0;
  94. quint16 nb_pistes_nulles; // décrivant des déplacements ou des tracés de pste de longueur = 0
  95. quint16 nb_corrections =0;
  96.  
  97. quint16 num_element_proche_en_cours =0;
  98.  
  99. float zoom;
  100. float ech;
  101.  
  102.  
  103. qint16 Xcent, Ycent; // en 1/100 mm
  104. qint16 memo_X, memo_Y;
  105. QPointF pos_actuelle;
  106. 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)
  107. qint16 Y_max =0; // coordonné Y max la plus grande parmis toutes celles de tous les éléments du circuit
  108.  
  109.  
  110. quint8 connect_ok =0;
  111. quint8 recu_PRET =0;
  112. quint8 flashage_en_cours = 0;
  113. quint8 simulation = 0;
  114. quint8 laser_on = 0; // allumage du laser en continu. POURS TESTS SEULEMENT !
  115. quint8 laser_bloque = 0; // empêche l'allumage du laser si =1 ; pour tests déplacements laser éteint
  116. quint8 trace_aspect_reel;
  117. quint8 findecourse = 0;
  118.  
  119. quint8 miroir=0;
  120. quint8 pastilles_creuses=0;
  121.  
  122. char buffer[100];
  123. QString msg ="";
  124. int pourcent = 0;
  125. QList <int> annonces_faites;
  126.  
  127. QString port_usb_name;
  128.  
  129. qreal sqr(qreal r1)
  130. {
  131. return r1 * r1;
  132. }
  133.  
  134.  
  135. QString valeur2txt4(int v1)
  136. {
  137. QString s;
  138. s.setNum(v1); // conversion num -> txt
  139. s = "0000"+s;
  140. s = s.right(4);
  141. return s;
  142. }
  143.  
  144.  
  145. QString valeur2txt2(int v1)
  146. {
  147. QString s;
  148. s.setNum(v1); // conversion num -> txt
  149. s = "00"+s;
  150. s = s.right(2);
  151. return s;
  152. }
  153.  
  154.  
  155.  
  156. MainWindow::MainWindow(QWidget *parent) :
  157. QMainWindow(parent)
  158. {
  159. setupUi(this);
  160. setWindowTitle("Gerber Photoplotter v:" + version + " - Silicium628");
  161.  
  162. // window()->setGeometry(0,0,1279,889);
  163. window()->setGeometry(0,0,1900,900); // -> affchage étendu
  164. textEdit_1->setGeometry(1285,5,595,855);
  165. //Btn_close_Tx1->setGeometry(1247,715,20,20);
  166. Btn_close_Tx1->setGeometry(1855,10,20,20);
  167. Btn_save_log->setGeometry(1780,10,70,20);
  168.  
  169. scene1 = new SceneCliquable(this);
  170.  
  171. InitTable3();
  172. InitTable4();
  173. InitTable5();
  174.  
  175. brush_pastille.setColor(couleur_pastille1);
  176. brush_pastille.setStyle(Qt::SolidPattern);
  177.  
  178. brush_milieu.setColor(couleur_milieu);
  179. brush_milieu.setStyle(Qt::SolidPattern);
  180.  
  181. brush_DT.setColor(couleur_DT);
  182. brush_DT.setStyle(Qt::SolidPattern);
  183.  
  184. brush_trou.setColor(couleur_trou);
  185. brush_trou.setStyle(Qt::SolidPattern);
  186.  
  187. pen_piste.setCapStyle(Qt::RoundCap); // extrémités des pistes arrondies - voir QPen dans la doc.
  188.  
  189. // QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
  190.  
  191.  
  192. effacer_ecran(); // et crée les groupes héritiers de la scene ainsi que la connexion entre les clics et le slot ici concerné
  193.  
  194. BoutonLed1 = new QBoutonLed(frame_10);
  195. BoutonLed1->setGeometry(QRect(4, 4, 40, 40));
  196. BoutonLed1->setCouleur(QColor (255,255,0));
  197. connect(BoutonLed1, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed1_toggled(bool)));
  198.  
  199. BoutonLed2 = new QBoutonLed(frame_12); // affichage REEL
  200. BoutonLed2->setGeometry(QRect(4, 4, 40, 40));
  201. BoutonLed2->setCouleur(QColor::fromRgb(0xFFFF00));
  202. connect(BoutonLed2, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed2_toggled(bool)));
  203.  
  204. trace_aspect_reel=1;
  205.  
  206. BoutonLed3 = new QBoutonLed(frame_3); // allumage laser
  207. BoutonLed3->setGeometry(QRect(4, 4, 40, 40));
  208. BoutonLed3->setCouleur(QColor::fromRgb(0x1E90FF));
  209. connect(BoutonLed3, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed3_toggled(bool)));
  210.  
  211. BoutonLed4 = new QBoutonLed(frame_17); // blocage laser
  212. BoutonLed4->setGeometry(QRect(4, 4, 40, 40));
  213. BoutonLed4->setCouleur(QColor::fromRgb(0xFF0000));
  214. connect(BoutonLed4, SIGNAL(toggled(bool)), this, SLOT(on_BoutonLed4_toggled(bool)));
  215.  
  216.  
  217. Led0 = new QLed(frame1); // Connexion USB ; verte = ok ; rouge = impossible
  218. Led0->setForme(1);
  219. Led0->setGeometry(QRect(4, 4, 40, 40));
  220. Led0->setCouleur(QColor (0,255,0));
  221. Led0->setEtat(0);
  222.  
  223. //=======================================================================================
  224. // jaune = Connexion USB établie, attente message bienvenue ; verte message "ATMEGA" reçu
  225. Led1 = new QLed(frame_4);
  226. Led1->setForme(1);
  227. Led1->setGeometry(QRect(4, 4, 40, 40));
  228. Led1->setCouleur(QColor (255,255,0));
  229. Led1->setEtat(0);
  230.  
  231. //=======================================================================================
  232. // envoi commande par USB ; jaune = message envoyé - verte = reçu réponse ("PRET")
  233. Led2 = new QLed(frame_6);
  234. Led2->setForme(1);
  235. Led2->setGeometry(QRect(4, 4, 40, 40));
  236. Led2->setCouleur(QColor (255,255,0));
  237. Led2->setEtat(0);
  238.  
  239. //=======================================================================================
  240. // VERTE ; allumée (verte) = flashage en cours
  241. Led3 = new QLed(frame_7);
  242. Led3->setForme(1);
  243. Led3->setGeometry(QRect(4, 4, 40, 40));
  244. Led3->setCouleur(QColor (0,255,0)); // VERTE
  245. Led3->setEtat(0);
  246.  
  247. //=======================================================================================
  248. // ROUGE, ronde ; allumée = FIN DE COURSE ACTIF !
  249. Led4 = new QLed(frame_11);
  250. Led4->setForme(2); // ronde
  251. Led4->setGeometry(QRect(4, 4, 40, 40));
  252. Led4->setCouleur(QColor (255,0,0)); // ROUGE
  253. Led4->setEtat(0);
  254.  
  255. //=======================================================================================
  256. /**
  257.   Led5 = new QLed(frame_18);
  258.   Led5->setForme(1);
  259.   Led5->setGeometry(QRect(2, 2, 20, 20));
  260.   Led5->setCouleur(QColor (255,255,0));
  261.   Led5->setEtat(0);
  262. **/
  263. //=======================================================================================
  264. Timer1 = new QTimer(this);
  265. connect(Timer1, SIGNAL(timeout()), this, SLOT(Timer1_clic()));
  266.  
  267. Timer2 = new QTimer(this);
  268. connect(Timer2, SIGNAL(timeout()), this, SLOT(Timer2_clic()));
  269.  
  270. Timer3 = new QTimer(this);
  271. connect(Timer3, SIGNAL(timeout()), this, SLOT(Timer3_clic()));
  272.  
  273. memo_X =0;
  274. memo_Y =0;
  275. num_ligne_en_cours1 = 0;
  276.  
  277. spinBox_zoom2->setValue(5);
  278.  
  279.  
  280. // QString filename = "./Fichiers_gerber/attenuateur-F_Cu.gtl";
  281. // QString filename = "./Fichiers_gerber/largeur_pistes-B_Cu.gbl";
  282. fileName_en_cours = "./Fichiers_gerber/largeur_pistes-F_Cu.gtl";
  283.  
  284. lecture_fichier_init();
  285.  
  286.  
  287. lineEdit_6->setText(fileName_en_cours);
  288.  
  289. int result = lire_fichier_gerber(fileName_en_cours);
  290.  
  291. if (result == 0)
  292. {
  293. analyse_fichier_gerber();
  294. //tout_decliquer();
  295. //dessiner_liste_elements_tries();
  296. classer_auto();
  297. trace_liste_apertures();
  298. on_BoutonLed2_toggled(true);
  299. BoutonLed2->setChecked(true);
  300. }
  301.  
  302. BoutonLed4->setChecked(1);
  303.  
  304. // pardéfaut :
  305. // port_usb_name="ttyUSB0";
  306. efface_buffer();
  307.  
  308. port_usb_name="ttyACM0";
  309. actionConnexion->setText("Connexion_ttyACM0");
  310.  
  311. }
  312.  
  313.  
  314.  
  315. MainWindow::~MainWindow()
  316. {
  317.  
  318. }
  319.  
  320.  
  321.  
  322.  
  323. void MainWindow::InitTable3()
  324. {
  325. QStringList liste_entetes;
  326. tableWidget_3->clear();
  327.  
  328. liste_entetes <<"CMD"<<"longueur";
  329.  
  330. tableWidget_3->setHorizontalHeaderLabels (liste_entetes);
  331. tableWidget_3->setColumnCount(2);
  332. tableWidget_3->setRowCount(1);
  333.  
  334. }
  335.  
  336.  
  337. void MainWindow::InitTable4()
  338. {
  339. QStringList liste_entetes;
  340. liste_entetes <<"CMD";
  341.  
  342. tableWidget_4->clear();
  343. tableWidget_4->setColumnCount(2);
  344. tableWidget_4->setRowCount(0);
  345. tableWidget_4->setHorizontalHeaderLabels (liste_entetes);
  346.  
  347. }
  348.  
  349.  
  350. void MainWindow::InitTable5()
  351. {
  352. QStringList liste_entetes;
  353.  
  354. tableWidget_5->clear();
  355. tableWidget_5->setColumnCount(2);
  356. tableWidget_5->setRowCount(0);
  357. tableWidget_5->setHorizontalHeaderLabels (liste_entetes);
  358.  
  359. }
  360.