bonjour à tous, je rencontre des difficultés pour mon multi-thread avec les classe codeur et afficheur. Le problème que j'ai actuellement est que toutes les 100 milliseconde environ je récupère des informations sous forme de trame grâce à la classe noeud_can (envoyer_trame / recevoir_trame) pour la méthode CodeurValeur() de la classe Codeur.cs.
Mais comme j'ai le thread de cette méthode et celle de l'afficheur (CodeurValeurAfficheur()), 1 fois sur 5 environ je ne reçoit pas de trame et donc je n'obtient pas de valeur.
Je n'ai pas ce problème lorsque le thread du codeur fonctionne tout seul, sans celui de l'afficheur. Si je remet en place le thread de l'afficheur et que je le lance, le problème revient.
--------------------------------------------------------------------------
Classe Codeur.cs
La valeur du capteur est 222
--------------------------------------------------------------
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 class Codeur : noeud_can { //Variable témoin du lock. private static Object _lock = new Object(); //Variable de contrôle. private bool _quitter = false; //Variable valeur pour afficheur public int ValeurCodeurFinal; public Codeur(string nom_peripherique, UInt16 numero_noeud) : base(nom_peripherique, numero_noeud) { } public void CodeurValeur(object capteur) { //Boucle infinie contrôlée. while (!_quitter) { //On verouille l'accès aux variables tant que l'on a pas terminé. lock (_lock) { Capteur grid = (Capteur)capteur; if ((grid.ValeurCapteurFinal != 0)) { #region Envoie et reception trame //COB ID uint COB_ID_emission_sdo = (uint)0x600 + numero_noeud; //0x600 trame SDO cf manuel p668 + numero noeud (1) uint COB_ID_reception_sdo = (uint)0x580 + numero_noeud; //0x580 trame SDO cf manuel p668 + numero noeud (1) Console.WriteLine("début de la capture"); //Envoie de la trame pour lire l'entrée analogique numéro 2 du variateur //0x40 - requête de lecture d'un paramètre du variateur 64 en décimal 4 octets //5cbd - Affichage des marques de repère actuelles du noyau Motion Control // plage d'affichage du capteur : -214748.3647 a 214748.3647 voir page 1015 (C01210) // 0x3 - sous index 3: affichage de la position -- réelle actuelle générée par un système codeur en option envoyer_trame(COB_ID_emission_sdo, 8, 0x40, 0x45, 0x5b, 0x03, 0x0, 0x0, 0x0, 0x0); //envoyer_trame(COB_ID_emission_sdo, 8, 0x40, 0xbd, 0x5c, 0x05, 0x0, 0x0, 0x0, 0x0); -- ancienne version (moins précise) Console.WriteLine("\nenvoi de la trame de lecture de la valeur d'entrée"); TPCANMsg message_reponse; message_reponse = recevoir_trame(COB_ID_reception_sdo, 8); //Thread.Sleep(400); #endregion #region Conversion reception trame Thread.Sleep(100); string disthexa = message_reponse.DATA[7].ToString("X2"); string disthexa2 = disthexa + message_reponse.DATA[6].ToString("X2"); string disthexa3 = disthexa2 + message_reponse.DATA[5].ToString("X2"); string disthexa4 = disthexa3 + message_reponse.DATA[4].ToString("X2"); int intAgain2 = int.Parse(disthexa4, System.Globalization.NumberStyles.HexNumber); Console.WriteLine("La valeur de intAgain2 = {0}", intAgain2); int tour = (intAgain2 / 10000 / 360); //Divise le nombre par 10k car la valeur est mise à l'échelle //(Facteur de mise à l'échelle : 10000) et division par 360 pour obtenir une valeur précise double tourcodeur = (tour * 0.2); // 10 tour = 2 cm double valeurcodeur = (tourcodeur * 10.0); int theValueToConvert = Convert.ToInt32(valeurcodeur); Console.WriteLine("\n\n\tNombres de tours : {0}", tour); Console.WriteLine("\tnombres de centimètres : {0}", tourcodeur); #endregion #region Valeur pour afficheur (calcule) this.ValeurCodeurFinal = (grid.ValeurCapteurFinal - theValueToConvert); Console.WriteLine("La distance restant a parcourir est de {0} mm", this.ValeurCodeurFinal); #endregion } else { Console.WriteLine("ValeurcapteurFinal n'a pas la bonne valeur !"); } //On recommence dans 500ms. //Thread.Sleep(500); } } } public void InerrupteurCodeur() // Méthode arrêt boucle { _quitter = true; } }
Classe Afficheur.cs
-----------------------------------------------------------------
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 class Afficheur : noeud_can { //Variable témoin du lock. private static Object _lock = new Object(); //Variable de contrôle. public static bool _quitter = false; //constructeur par defaut public Afficheur(string nom_peripherique, UInt16 numero_noeud) : base(nom_peripherique, numero_noeud) { } public void CodeurValeurAfficheur(object codeur) { //Boucle infinie contrôlée. while (!_quitter) { Console.WriteLine("\n\n\n\tAfficheur"); //On verouille l'accès aux variables tant que l'on a pas terminé. lock (_lock) { Codeur grid = (Codeur)codeur; //COB ID uint COB_ID_emission_sdo = (uint)0x600 + numero_noeud; //0x600 trame SDO cf manuel p668 + numero_noeud (3) if (grid.ValeurCodeurFinal != 0) { //Console.WriteLine("debut de l'affichage valeur"); if (grid.ValeurCodeurFinal > 255) { //double valeurCodeurAfficheur = (grid.ValeurcodeurFinal * 10.0); double valeurbit = (256 - grid.ValeurCodeurFinal); //int ValeurCodeur = Convert.ToInt32(valeurbit); string Output1 = valeurbit.ToString("X"); //Conversion en châine de caractere byte ValeurInferieurCapteur = Convert.ToByte(Output1, 16); //Conversion en byte pour l'afficheur et hexadécimal //Console.WriteLine("\n\tAttendre 100 miliseconde"); //Thread.Sleep(200); //test distance //Console.WriteLine("\nenvoi de la trame d'affichage"); envoyer_trame(COB_ID_emission_sdo, 8, 0x23, 0x00, 0x52, 0x00, ValeurInferieurCapteur, 0x01, 0x0, 0x0); //Thread.Sleep(200); } else { string Output = grid.ValeurCodeurFinal.ToString("X"); byte ValeurInferieurCodeur = Convert.ToByte(Output, 16); //Conversion en hexa byte //Console.WriteLine("\n\tAttendre 100 miliseconde"); //Thread.Sleep(100); //test distance //Console.WriteLine("\nenvoi de la trame d'affichage"); envoyer_trame(COB_ID_emission_sdo, 8, 0x23, 0x00, 0x52, 0x00, ValeurInferieurCodeur, 0x0, 0x0, 0x0); //Thread.Sleep(100); } } else { // Si valeur non bonne Console.WriteLine("ValeurcodeurFinal n'a pas la bonne valeur !"); envoyer_trame(COB_ID_emission_sdo, 8, 0x23, 0x00, 0x52, 0x00, 0xFF, 0xFF, 0xFF, 0xFF); Thread.Sleep(200); } //On recommence dans 600ms. Thread.Sleep(1000); } } } public void InerrupteurAfficheur() // Méthode arrêt boucle { _quitter = true; } }
Classe noeud_can.cs
-----------------------------------------------------------
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 //Variable témoin du lock. private static Object _lock = new Object(); public bool envoyer_trame(uint ID, byte LEN, byte data0, byte data1, byte data2, byte data3, byte data4, byte data5, byte data6, byte data7) { lock (_lock) { TPCANStatus gstatus; // Represents a PCAN status/error code -- Représente un état / code d'erreur PCAN TPCANMsg message; message.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD; message.ID = ID; message.LEN = LEN; message.DATA = new byte[8]; message.DATA[0] = data0; message.DATA[1] = data1; message.DATA[2] = data2; message.DATA[3] = data3; message.DATA[4] = data4; message.DATA[5] = data5; message.DATA[6] = data6; message.DATA[7] = data7; gstatus = PCANBasic.Write(handle, ref message); if (gstatus != TPCANStatus.PCAN_ERROR_OK) return false; else return true; } } /// <summary> /// Reception trame variateur /// </summary> /// <param name="ID"></param> /// <param name="LEN"></param> /// <returns></returns> public TPCANMsg recevoir_trame(uint ID, byte LEN) { lock (_lock) { TPCANStatus gstatus; // Represents a PCAN status/error code -- Représente un état / code d'erreur PCAN TPCANMsg message_lu; message_lu.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD; message_lu.ID = ID; //0x581 message_lu.LEN = LEN; message_lu.DATA = new byte[8]; //lire plusieurs trames jusqu'à récupérer la bonne (i.e. avec un COBID de 0x581) while (true) { gstatus = PCANBasic.Read(handle, out message_lu); if (gstatus != TPCANStatus.PCAN_ERROR_OK) { Console.WriteLine("erreur reception trame tension2"); System.Environment.Exit(Convert.ToInt32(TPCANStatus.PCAN_ERROR_UNKNOWN)); } if (gstatus == TPCANStatus.PCAN_ERROR_OK && message_lu.ID == ID) { //Affiche verification trame retour for (int i = 0; i < 8; i++) { //Console.Write("{0} ", (int)message_lu.DATA[i]); string Tramesréponse = message_lu.DATA[i].ToString("X2"); Console.Write("{0} ", Tramesréponse); // test /* Console.Write("COB_ID {0:x} ", message_lu.ID); Console.Write("octet1 {0:x} ", message_lu.DATA[0]); Console.Write("octet2 {0:x} ", message_lu.DATA[1]); Console.Write("octet3 {0:x} ", message_lu.DATA[2]); Console.Write("octet4 {0:x} ", message_lu.DATA[3]); Console.Write("octet5 {0:x} ", message_lu.DATA[4]); Console.Write("octet6 {0:x} ", message_lu.DATA[5]); Console.Write("octet7 {0:x} ", message_lu.DATA[6]); Console.Write("octet8 {0:x} \n", message_lu.DATA[7]); * */ } } return message_lu; } } }
Main
---------------------------------------------------------------
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 Console.WriteLine("Lancement boucle"); // Create the thread object, passing in the (CODEUR.codeurvaleur) method // via a ThreadStart delegate. This does not start the thread. var CodeurBoucle = new Thread(new ParameterizedThreadStart(CODEUR.CodeurValeur)); //Start the thread CodeurBoucle.Start(CAPTEUR); // Create the thread object, passing in the (AFFICHEUR.CodeurValeurAfficheur) method // via a ThreadStart delegate. This does not start the thread. var AfficheurBoucle = new Thread(new ParameterizedThreadStart(AFFICHEUR.CodeurValeurAfficheur)); //Start the thread AfficheurBoucle.Start(CODEUR); CodeurBoucle.Join(); AfficheurBoucle.Join(); Thread.Sleep(20000); // Laisse travailler pendant 20 seconde // Arréter les thread CODEUR.InerrupteurCodeur(); AFFICHEUR.InerrupteurAfficheur(); Console.WriteLine("Thread stoper dans le programme.");
Image console du programme avec la trame vide
Comme le montre l'image de la console. Dans la zone encadré en orange on voit que je ne reçois pas de trame de réponse du noeud_can avant la phrase "La valeur de intAgain2 = 0". Du coup la méthode de la classe codeur n'a que la valeur du capteur (222), et vu que la valeur de la trame de réponse vaut 0, le nombres de tours et le nombres de centimètres ne peuvent être calculés.
Le problème vient de mes thread ?
est-ce que je dois utiliser des sémaphore ou passer par autre chose ?
S'il faut d'autres informations, indiquer-les moi.
Partager