arthurdubois:
Pas de problème, par contre, j'avoue que je ne comprends pas le décalage.
Hier j'ai vérifié que je comprenais bien l'API avec une vieille machine de 1988 à 2400 bps, ça a bien fonctionné.
Quant au programme du µC, il est très simple et je ne vois pas comment il pourrait causer ce décalage.
Si tu es encore motivé, tu peux tester cette version du programme PC :
Ca reste du Quick & Dirty, mais là j'essaie de voir ce qui est réellement dans la file d'attente après chaque écriture, pas uniquement le 1er caractère.
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 #include <fstream> #include <string> #include <vector> #include <iostream> #include <sstream> #include <Windows.h> using namespace std; string AttendEtLitTout(HANDLE h) { COMSTAT stat; vector<char> s; Sleep(500); ClearCommError(h, NULL, &stat); if (stat.cbInQue > 0) { s.resize(stat.cbInQue); ReadFile(h, s.data(), s.size(), NULL, NULL); } return string(s.begin(), s.end()); } int main(void) { COMMTIMEOUTS timeouts = { 0 }; HANDLE h = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) { cout << "Erreur: Impossible d´ouvrir le port série" << endl; return 1; } DCB dcb = { 0 }; BOOL dcbOk = GetCommState(h, &dcb); dcb.BaudRate = CBR_115200; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = TWOSTOPBITS; dcbOk = SetCommState(h, &dcb); timeouts.ReadIntervalTimeout = 100; timeouts.ReadTotalTimeoutMultiplier = 100; timeouts.ReadTotalTimeoutConstant = 100; timeouts.WriteTotalTimeoutMultiplier = 100; timeouts.WriteTotalTimeoutConstant = 100; if (!SetCommTimeouts(h, &timeouts)) return 1; // Test de l'écho for (int i = 0; i < 5; ++i) { char sentChar = '0' + i; if (!WriteFile(h, &sentChar, 1, NULL, 0)) return 1; cout << sentChar << " : " << AttendEtLitTout(h) << endl; } CloseHandle(h); return 0; }
Sinon, j'ai essayé d'écrire l'écho du µC avec les interruptions au lieu du poll :
Je me suis basé sur ton code.
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 #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define FOSC 8000000 // Clock Speed #define BAUD 115200UL #define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1) // clever runden #define usart_buffer_max_size 50 char usart0_rx_buffer[usart_buffer_max_size]; volatile uint8_t usart0_rx_buffer_size = 0; void USART_Init (unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char) ubrr; UCSR0B = (1<<RXEN0) | (0<<TXEN0) | (1<<RXCIE0) | (0<<UDRIE0); UCSR0C = (1<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00); } /* La fonction d´interruption de reception du byte */ /* Cette fonction est active lorsque RXCIE0 = 1 */ ISR(USART0_RXC0_vect) { char data = UDR0; /* Pour eviter ce depassement de buffer, il est possible de faire du flow control avec XOn/XOff par exemple */ if (usart0_rx_buffer_size < usart0_rx_buffer_max_size) { usart0_rx_buffer[usart0_rx_buffer_size] = data; ++usart0_rx_buffer_size; /* Active l'emission de donnees, car on a des donnees dans la file */ UCSR0B |= 1<<UDRIE0; } } /* La fonction d´interruption d´envoi de byte */ /* Cette fonction est active lorsque UDRIE0 = 1 */ ISR(USART0_UDRE0_vect) { int i; if (usart0_rx_buffer_size == 0) /* S'il n'y a plus de données à envoyer on arrete l'emission */ UCSR0B &= ~(1<<UDRIE0); else { UDR1 = usart0_rx_buffer[0]; --usart0_rx_buffer_size; /* S'il n'y a plus de données à envoyer on arrete l'emission */ if (usart0_rx_buffer_size == 0) UCSR0B &= ~(1<<UDRIE0); else /* Pour l'instant je gere la file de maniere bete et mechante, */ /* mais ca pourrait etre un buffer cyclique */ for (i = 0; i < usart0_rx_buffer_size; ++i) usart0_rx_buffer[i] = usart0_rx_buffer[i + 1]; } } int main (void) { USART_Init(UBRR_VAL) ; // initialisation USART sei(); // Activation des fonctions d´interruption while(1) { } }
Il y avait d'ailleurs une petite erreur : UCSZ02 n'est pas dans UCSR0C, il est dans UCSR0B. Mais ça change rien vu que tu y mets 0.
Je n'ai pas vu dans la doc si les 2 interruptions risquent de s'interrompre l'une l'autre. C'est peut-être une évidence (qu'elles ne le peuvent pas), mais je n'ai pas d'expérience dans ce domaine.
Mat.M, je reconnais sans problème qu'il faudra bien attendre les moteurs au niveau du µC, puis attendre le µC au niveau du PC, et donc un dialogue entre les 2.
Maintenant, le code que j'ai donné pour l'écho fonctionne, je l'ai testé hier. C'est juste une programme qui s'exécute en série.
Je ne vois vraiment pas ce qui te gêne là-dedans.
Moi je peux te dire ce qui me gênait un peu dans ton intervention : c'est que l'auteur de la question a de toute évidence assez de problèmes à résoudre avant de se perdre dans les pages d'aide de CreateThread, I/O cancellation (mauvaise idée, je le répète) etc.
Mais encore une fois, tu as raison sur le fait qu'il y aura un dialogue entre les machines, et c'est vrai que j'ai laissé ça de côté pour le moment. Ça n'empêche pas le développement d'un programme monothread bête et méchant sur le PC, si le cahier des charges dit : "exécuter la séquence du fichier texte et quitter". (d'ailleurs l'objet de la mission c'est probablement le µC, plus que le PC qui n'est là que pour tester)
Bonjour,
Hibernatus: j´ai deboggue le code que tu as poste tout a l´heure et une fenêtre contenant le message suivant s´est affiche:
.Signal received
Programm received signal SIGSEGV, Segmentation fault
Au même instant la fenêtre "call stack" s´est affiche a mon ecran.
La fenêtre "call stack" contient les donnees suivante:
Nr Adress Function File line
0 7C810EAC WriteFile() C:\WINDOWS\SY..
1 00000000 0x0022ff0c in ?? ()
2 00000000 0x00000794 in ?? ()
3 00000000 0x0022fef0 in ?? ()
4 00000000 0x0022ff0c in ?? ()
5 00000000 0x00000794 in ?? ()
0 00000000 0x00000000 in ?? ()
J´ai essaye a plusieurs reprises de tester le nouveau code, helas les deux fenêtres apparaîssent. Bref le deboggage ne marche pas.
Oups, désolé, je n'ai rien pour tester ici, et j'ai pas lu totalement la doc de WriteFile (un paramètre était noté "optionnel" mais dans les commentaires ils expliquent qu'il ne l'est pas toujours).
Voilà une correction :
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 #include <fstream> #include <string> #include <vector> #include <iostream> #include <sstream> #include <Windows.h> using namespace std; string AttendEtLitTout(HANDLE h) { COMSTAT stat; vector<char> s; DWORD sizeRead; Sleep(500); ClearCommError(h, NULL, &stat); if (stat.cbInQue > 0) { s.resize(stat.cbInQue); ReadFile(h, s.data(), s.size(), &sizeRead, NULL); } return string(s.begin(), s.end()); } int main(void) { COMMTIMEOUTS timeouts = { 0 }; HANDLE h = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) { cout << "Erreur: Impossible d´ouvrir le port série" << endl; return 1; } DCB dcb = { 0 }; BOOL dcbOk = GetCommState(h, &dcb); dcb.BaudRate = CBR_115200; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = TWOSTOPBITS; dcbOk = SetCommState(h, &dcb); timeouts.ReadIntervalTimeout = 100; timeouts.ReadTotalTimeoutMultiplier = 100; timeouts.ReadTotalTimeoutConstant = 100; timeouts.WriteTotalTimeoutMultiplier = 100; timeouts.WriteTotalTimeoutConstant = 100; if (!SetCommTimeouts(h, &timeouts)) return 1; // Test de l'écho for (int i = 0; i < 5; ++i) { char sentChar = '0' + i; DWORD sizeWritten; if (!WriteFile(h, &sentChar, 1, &sizeWritten, 0)) return 1; cout << sentChar << " : " << AttendEtLitTout(h) << endl; } CloseHandle(h); return 0; }
Salut,
j´ai deboggue a plusieurs reprises la version corrigee du code que tu as poste tout a l´heure et j´obtiens toujours un decalage. Voici ce que j´obtiens:
0:
1:0
2:1
3:2
4:3
Salut,
J´ai aussi donnes plusieurs valeurs au timeout afin d´eviter le decalage. Helas je n´obtiens rien de bon.
J´obtiens les resultats aleatoires suivants:
0:
1:
2:1
3:2
4:3
ou
0:
1:0
2:1
3:2
4:3
ou
0:0
1:
2:1
3:1
4:3
ou
0:
1:
2:01
3:2
4:3
Salut,
Cela ressemble soit à un problème de configuration du micro soit à une absence d'acquittement (lecture ?) aboutissant à un écho.
1/ Vérifies avec la datasheet de ton micro que tout est bien configuré et si la réception doit être acquittée et comment
2/ Utilises un espion sur ton lien (au pire un oscilloscope mais ça risque d'être + compliqué) pour voir ce qui se transmet sur celui-ci.
Tu es sûr de celui-là ? Parce que là ça serait vraiment bizarre. A l'ouverture d'un port COM, la file d'entrée est vidée, donc ça ne pourrait même pas s'expliquer par des restes d'un test précédent.
Malheureusement j'ai encore du mal à comprendre comment on peut obtenir ce décalage alors que le µC se contente de renvoyer chaque caractère immédiatement. C'est comme s'il y avait un contrôle de flux et l'envoi d'un caractère par le PC débloquerait l'envoi d'un caractère par le µC. Mais la doc n'en parle pas du tout. D'ailleurs c'est quelque chose d'obsolète, donc je suis parti du principe qu'il n'y en avait pas.
Peux-tu essayer la version basée sur les interruptions ?
J´ai essaye la version avec les interruptions et j´ai obtenu ceci:Peux-tu essayer la version basée sur les interruptions ?
0:0
1:1
2:
3:
4:
Apparement j´ai rate quelque chose lors du deboggage. Je vais reessayer.
Le code du microcontrôleur avec interruption (RXCIE0 --->1):
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // #include "uart.h" #include <avr/pgmspace.h> #define FOSC 8000000 // Clock Speed #define BAUD 115200UL // Berechnungen zur Baudrate: #define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1) // clever runden /***************************************************/ volatile unsigned char data; /****************************************************/ void USART_Init (unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char) ubrr; UBRR1H = (unsigned char)(ubrr>>8); UBRR1L = (unsigned char) ubrr; UCSR0B = (1<<RXEN0) | (1<<TXEN0) |(1<<RXCIE0)|(0<<TXCIE0); UCSR0C = (1<<USBS0) | (0<<UCSZ02)|(1<<UCSZ01)|(1<<UCSZ00); UCSR1B = (0<<RXEN1) | (0<<TXEN1) |(0<<RXCIE1)|(0<<TXCIE1); UCSR1C = (1<<USBS1) | (0<<UCSZ12)|(1<<UCSZ11)|(1<<UCSZ10); } /**********************************************************/ /*-- function receive USART0 --*/ unsigned char USART0_Receive (void) { while(!(UCSR0A & (1<<RXC0)) ); // warten bis Zeichen verfuegbar return UDR0; // Zeichen aus UDR an Aufrufer zurueckgeben } /*-- function transmit USART0 --*/ void USART0_Transmit (unsigned char data0) { while ( !(UCSR0A & (1<<UDRE0)) ); // warten bis Senden moeglich UDR0 = data0; } /*-- function receive USART1 --*/ unsigned char USART1_Receive (void) { while(!(UCSR1A & (1<<RXC1)) ); // warten bis Zeichen verfuegbar return UDR1; // Zeichen aus UDR an Aufrufer zurueckgeben } /*-- function transmit USART1 --*/ void USART1_Transmit (unsigned char data1) { while ( !(UCSR1A & (1<<UDRE1)) ) ; UDR1 = data1; // sende Zeichen } /**********************************************************/ /*-Aktivierung der Datenübertragung über RS485 von USART1-*/ void RS485_Init (void) { DDRD = (1<<PD4)|(1<<PD3)|(1<<PD5);//Steuer- und Datenausgang aktivieren PORTD = (1<<PD4); //auf Senden stellen (Aktivierung Datensendung) } ISR(USART0_RX_vect) { data = UDR0; // Lecture du byte UDR0 = data; // Renvoie du byte comme echo // UDR1 = data2; // Transmission du byte au port serie RS485 } int main (void) { unsigned char c ; USART_Init(UBRR_VAL) ; // USART Initialisierung RS485_Init (); // serielle Schnittstelle USART1 sei(); while(1) { /*-- Test USART0 (Receive and Transmit) --*/ // USART0_Transmit('X'); // c = USART0_Receive(); // USART0_Transmit(c); /*-- Test USART1 (Receive and Transmit) --*/ // USART1_Transmit( 'X' ); // c = USART0_Receive(); // USART1_Transmit(c); } }
Pour moi ton code n'est pas correct car tu écris dans UDR0 sans savoir s'il est dispo en émission.
Si tu regardes plus haut, je t'ai donné le code que je pense être correct (épuré de tout ce qui concerne l'usart1).
L'important est que j'utilise l'ISR UDRE0 pour l'envoi, comme indiqué dans la doc.
C'est une interruption répétée tant que UDRE0 (UDR0 dispo pour écriture) et UDRIE0 (interruption activée) sont vrais. Le principe est donc de stocker tout ce qui est reçu dans une file d'attente, et d'activer UDRIE0 pour lancer le transfert du contenu de cette file d'attente.
Dans l'ISR UDRE0, on envoie 1 octet de la file d'attente et si elle est vide on désactive UDRIE0 car on n'a plus rien à envoyer, sinon l'ISR sera déclenchée à nouveau pour le prochain octet.
D'après ce que j'ai lu dans la doc, ça me paraît une bonne manière de faire, surtout en préparation du programme final.
PS. Et je le répète, même si ça change rien au code généré, UCSZ02 n'est pas dans UCSR0C, il est dans UCSR0B.
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 #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define FOSC 8000000 // Clock Speed #define BAUD 115200UL #define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1) // clever runden #define usart_buffer_max_size 50 char usart0_rx_buffer[usart_buffer_max_size]; volatile uint8_t usart0_rx_buffer_size = 0; void USART_Init (unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char) ubrr; UCSR0B = (1<<RXEN0) | (0<<TXEN0) | (1<<RXCIE0) | (0<<UDRIE0); UCSR0C = (1<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00); } /* La fonction d´interruption de reception du byte */ /* Cette fonction est active lorsque RXCIE0 = 1 */ ISR(USART0_RX_vect) { char data = UDR0; /* Pour eviter ce depassement de buffer, il est possible de faire du flow control avec XOn/XOff par exemple */ if (usart0_rx_buffer_size < usart0_rx_buffer_max_size) { usart0_rx_buffer[usart0_rx_buffer_size] = data; ++usart0_rx_buffer_size; /* Active l'emission de donnees, car on a des donnees dans la file */ UCSR0B |= 1<<UDRIE0; } } /* La fonction d´interruption d´envoi de byte */ /* Cette fonction est active lorsque UDRIE0 = 1 */ ISR(USART0_UDRE_vect) { int i; if (usart0_rx_buffer_size == 0) /* S'il n'y a plus de données à envoyer on arrete l'emission */ UCSR0B &= ~(1<<UDRIE0); else { UDR1 = usart0_rx_buffer[0]; --usart0_rx_buffer_size; /* S'il n'y a plus de données à envoyer on arrete l'emission */ if (usart0_rx_buffer_size == 0) UCSR0B &= ~(1<<UDRIE0); else /* Pour l'instant je gere la file de maniere bete et mechante, */ /* mais ca pourrait etre un buffer cyclique */ for (i = 0; i < usart0_rx_buffer_size; ++i) usart0_rx_buffer[i] = usart0_rx_buffer[i + 1]; } } int main (void) { USART_Init(UBRR_VAL) ; // initialisation USART sei(); // Activation des fonctions d´interruption while(1) { } }
PS2. J'ai peut-être pas les bons noms d'interruptions, à toi de corriger.
PS3. J'ai cherché des exemples sur internet, et apparemment ce que tu fais (transmettre directement depuis l'ISR de réception), c'est une pratique courante. Moi je complique inutilement pour l'instant, mais il est probable que tu aies besoin d'un buffer plus tard de toute façon.
Bonjour,
Salut Hibernatus34: lorsque je deboggue le code c++ et le code c contenant les interruptions que tu as poste, j´obtiens ceci:
0 :
1 :
2 :
3 :
4 :
Je suis nocive dans le domaine du microcontrôleur et je suis vraiment impressionne par ta maniere de vite comprendre le fonctionnement. Je trouve que tu as bien programme la fonction d´interruption ISR(USART0_RX_vect). Par contre je ne comprends pas le travail de la fonction ISR(USART0_UDRE_vect). Apparement dans la fonction ISR(USART0_UDRE_vect) tu ne renvoies pas les bytes recus par le buffer UDR0 a nouveau sur le port serie. Ou du moins pêut-être que tu l´as fait, mais je n´apercois pas cela dans ton code.
Ne t'inquiète pas, moi je suis pire que novice, puisque non seulement je n'ai pas d'expérience là dedans, mais en plus je ne peux pas tester ce que j'écris !
En fait il y a une faute de frappe dans mon code, j'ai écrit UDR1 à la place de UDR0 :
UDR1 = usart0_rx_buffer[0]; devrait être UDR0 = usart0_rx_buffer[0];.
Peux-tu tester avec cette correction ?
De toute façon, comme j'ai dit dans mon PS3, mon code n'est probablement pas meilleur que le tien pour un simple écho.
Sinon, le nom de l'interruption était le bon ? (USART0_UDRE_vect)
En effet, le nom de l´interruption est juste.Sinon, le nom de l'interruption était le bon ? (USART0_UDRE_vect)
J´ai remplaceparUDR1 = usart0_rx_buffer[0];comme convenu. Mais j´obtiens toujours ceci:UDR0 = usart0_rx_buffer[0];
0 :
1 :
2 :
3 :
4 :
Je vais encore effectuer des tests.
J'ai probablement mal compris la doc.
Là j'ai pas mal de boulot, mais dès que j'ai un moment je m'y remets.
Si tu vois une erreur dans mon code, n'hésite pas à corriger. Par exemple le UDR1 à la place de UDR0 tu aurais pu le voir sans moi.
Ok, pas de soucis . Merci tout de même pour ton soutien. Je vais continuer a chercher .
Salut,
Bonjour hibernatus34, j´espere que ton week-end a ete agreable et que la semaine qui est en cours le sera aussi.
Comme convenu, j´ai effectue a plusieurs reprises differents tests afin d´abtenir la synchronisation suivante:
.0 : 0
1 : 1
2 : 2
3 : 3
4 : 4
En fin de compte, le test a marcher tout a l´heure.
J´ai utilise ton programme c et ainsi que le mien pour tester l´echo. Les resultats ont ete satisfaisants.
Voici la version modifiee de ton code avec les interruptions :
Le code pour le test de l´echo sans interruption:
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109 #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <avr/pgmspace.h> #define FOSC 8000000 // Clock Speed #define BAUD 115200UL // Berechnungen zur Baudrate: #define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1) // clever runden #define usart0_rx_buffer_max_size 50 /***************************************************/ char usart0_rx_buffer[usart0_rx_buffer_max_size]; volatile uint8_t usart0_rx_buffer_size = 0; /****************************************************/ void USART_Init (unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char) ubrr; // UBRR1H = (unsigned char)(ubrr>>8); // UBRR1L = (unsigned char) ubrr; UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UCSZ02)|(0<<UDRIE0); UCSR0C = (1<<USBS0) | (1<<UCSZ01)|(1<<UCSZ00); } /**********************************************************/ /*-- function receive USART0 --*/ unsigned char USART0_Receive (void) { while(!(UCSR0A & (1<<RXC0)) ); // warten bis Zeichen verfuegbar return UDR0; // Zeichen aus UDR an Aufrufer zurueckgeben } /*-- function transmit USART0 --*/ void USART0_Transmit (unsigned char data0) { while ( !(UCSR0A & (1<<UDRE0)) ); // warten bis Senden moeglich UDR0 = data0; } /**********************************************************/ /* La fonction d´interruption de reception du byte */ /* Cette fonction est active lorsque RXCIE0 = 1 */ ISR(USART0_RX_vect) { char data = UDR0; /* Pour eviter ce depassement de buffer, il est possible de faire du flow control avec XOn/XOff par exemple */ if (usart0_rx_buffer_size < usart0_rx_buffer_max_size) { usart0_rx_buffer[usart0_rx_buffer_size] = data; ++usart0_rx_buffer_size; /* Active l'emission de donnees, car on a des donnees dans la file */ UCSR0B |= 1<<UDRIE0; } } /* La fonction d´interruption d´envoi de byte */ /* Cette fonction est active lorsque UDRIE0 = 1 */ ISR(USART0_UDRE_vect) { int i; if (usart0_rx_buffer_size == 0) /* S'il n'y a plus de données à envoyer on arrete l'emission */ UCSR0B &= ~(1<<UDRIE0); else { UDR0 = usart0_rx_buffer[0]; --usart0_rx_buffer_size; /* S'il n'y a plus de données à envoyer on arrete l'emission */ if (usart0_rx_buffer_size == 0) UCSR0B &= ~(1<<UDRIE0); else /* Pour l'instant je gere la file de maniere bete et mechante, */ /* mais ca pourrait etre un buffer cyclique */ for (i = 0; i < usart0_rx_buffer_size; ++i) usart0_rx_buffer[i] = usart0_rx_buffer[i + 1]; } } int main (void) { USART_Init(UBRR_VAL) ; // USART Initialisierung sei(); while(1) { } }
Test d´echo avec interruption :
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 #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <avr/pgmspace.h> #define FOSC 8000000 // Clock Speed #define BAUD 115200UL // Berechnungen zur Baudrate: #define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1) // clever runden #define usart0_rx_buffer_max_size 50 /***************************************************/ char usart0_rx_buffer[usart0_rx_buffer_max_size]; volatile uint8_t usart0_rx_buffer_size = 0; /****************************************************/ void USART_Init (unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char) ubrr; UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(0<<RXCIE0)|(0<<TXCIE0)|(0<<UCSZ02)|(0<<UDRIE0); UCSR0C = (1<<USBS0) | (1<<UCSZ01)|(1<<UCSZ00); } /**********************************************************/ /*-- function receive USART0 --*/ unsigned char USART0_Receive (void) { while(!(UCSR0A & (1<<RXC0)) ); // warten bis Zeichen verfuegbar return UDR0; // Zeichen aus UDR an Aufrufer zurueckgeben } /*-- function transmit USART0 --*/ void USART0_Transmit (unsigned char data0) { while ( !(UCSR0A & (1<<UDRE0)) ); // warten bis Senden moeglich UDR0 = data0; } /**********************************************************/ int main (void) { unsigned char c ; USART_Init(UBRR_VAL) ; // USART Initialisierung // sei(); while(1) { /*-- Test USART0 (Receive and Transmit) --*/ // USART0_Transmit('X'); c = USART0_Receive(); USART0_Transmit(c); } }
.
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 #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <avr/pgmspace.h> #define FOSC 8000000 // Clock Speed #define BAUD 115200UL // Berechnungen zur Baudrate: #define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1) // clever runden #define usart0_rx_buffer_max_size 50 /***************************************************/ char usart0_rx_buffer[usart0_rx_buffer_max_size]; volatile uint8_t usart0_rx_buffer_size = 0; /****************************************************/ void USART_Init (unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char) ubrr; UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UCSZ02)|(0<<UDRIE0); UCSR0C = (1<<USBS0) | (1<<UCSZ01)|(1<<UCSZ00); } /**********************************************************/ /*-- function receive USART0 --*/ unsigned char USART0_Receive (void) { while(!(UCSR0A & (1<<RXC0)) ); // warten bis Zeichen verfuegbar return UDR0; // Zeichen aus UDR an Aufrufer zurueckgeben } /*-- function transmit USART0 --*/ void USART0_Transmit (unsigned char data0) { while ( !(UCSR0A & (1<<UDRE0)) ); // warten bis Senden moeglich UDR0 = data0; } /**********************************************************/ ISR(USART0_RX_vect) { char data; data = UDR0; // Lecture du byte UDR0 = data; // Renvoie du byte comme echo } int main (void) { USART_Init(UBRR_VAL) ; // USART Initialisierung // sei(); while(1) { } }
En bref les testes avec les codes ci-dessus ont ete un succes .
Peut-on des maintenant passer a l´envoi des positions x et y au microcontrôleur ? Qu´en penses-tu ? C´est clair que le programme d´envoi des positions x et y doit être modifie.
Merci pour ton aide.
salut,
Je desire que le PC envoie tout au microntrôleur deja formate sous la forme "#2C\r".Sinon, pour le programme complet, il faut que je relise un peu ce qu'on avait dit.
Qu'est-ce qui est le mieux pour toi ?
- Que le PC envoie tout déjà formaté comme "#2C\r" ?
- Ou bien que le PC envoie seulement X,Y et que ça soit le µC qui transforme ça en 2 messages ?
J´ai modifie ton code c++ en tenant compte du fichier texte contenant les positions x et y afin de tester les fonctions WriteFile et ReadFile. Mais je ne m´en sors pas. Pourrais-tu me filer un coup de pouce s´il te plaît ?
Par ailleurs je ne sais pas comment je pourrais formater les positions x et y sous la forme "#2C\r". S´il te plaît, aide moi.
Merci d´avance.
code d´envoi des positions x et y.
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 #include <fstream> #include <string> #include <vector> #include <iostream> #include <sstream> #include <Windows.h> using namespace std; string AttendEtLitTout(HANDLE h) { COMSTAT stat; vector<char> s; DWORD sizeRead; Sleep(500); ClearCommError(h, NULL, &stat); if (stat.cbInQue > 0) { s.resize(stat.cbInQue); ReadFile(h, s.data(), s.size(), &sizeRead, NULL); } return string(s.begin(), s.end()); } int main(void) { ifstream file("koordinaten.txt", ios::in | ios::binary); string line; if (!file) { cout << "Erreur: Impossible d´ouvrir le fichier en mode lecture" << endl; return 1; } COMMTIMEOUTS timeouts = { 0 }; HANDLE h = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) { cout << "Erreur: Impossible d´ouvrir le port série" << endl; return 1; } DCB dcb = { 0 }; BOOL dcbOk = GetCommState(h, &dcb); dcb.BaudRate = CBR_115200; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = TWOSTOPBITS; dcbOk = SetCommState(h, &dcb); timeouts.ReadIntervalTimeout = 200; timeouts.ReadTotalTimeoutMultiplier = 200; timeouts.ReadTotalTimeoutConstant = 200; timeouts.WriteTotalTimeoutMultiplier = 200; timeouts.WriteTotalTimeoutConstant = 200; if (!SetCommTimeouts(h, &timeouts)) return 1; /* Extraction et Conversion des positions X et Y */ // Lecture ligne par ligne while (getline(file, line)) { int x; // x, y du texte int y; int x_steps; // x, y en pas moteur int y_steps; stringstream input; // flux d'entrée (une ligne du texte) stringstream output_x; // flux de sortie (une paire de coordonnées) stringstream output_y; stringstream input_x; // une paire de coordonnées stringstream input_y; int x1; int y1; // Une ligne devient un flux d'entrée input.str(line); // Extraction du X et du Y. if (input.get() != 'X') continue; input >> x; if (input.get() != 'Y') continue; input >> y; // Conversion de la position en pas de moteur // J'ai rendu le calcul compatible avec le type int. (et je le trouve plus lisible) x_steps = x * 127 / 500; y_steps = y * 127 / 500; /* Writting to the serial port */ DWORD byteswritten ; output_x << x_steps; // TODO: Ne manque-t-il pas un terminateur ou un cadrage ? string s_x = output_x.str(); //string s(output_x.str()); for (size_t i = 0; i < s_x.size(); ++i) { if (!WriteFile(h, &s_x[i], 1, &byteswritten, NULL)) return 2; cout << s_x[i] << " : " << AttendEtLitTout(h) << endl; } output_y << y_steps; // TODO: Ne manque-t-il pas un terminateur ou un cadrage ? string s_y = output_y.str(); //string s(output_y.str()); for (size_t j = 0; j < s_y.size(); ++j) { if (!WriteFile(h, &s_y[j], 1, &byteswritten, NULL)); return 3; cout << s_y[j] << " : " << AttendEtLitTout(h) << endl; } /* // Test de l'écho for (int i = 0; i < 10; ++i) { char sentChar = '0' + i; DWORD sizeWritten; if (!WriteFile(h, &sentChar, 1, &sizeWritten, 0)) return 1; cout << sentChar << " : " << AttendEtLitTout(h) << endl; } */ } CloseHandle(h); return 0; }
Salut,
Content de voir que ça fonctionne. Si tu sais quelle était mon erreur, je serais curieux de savoir.
Sinon, pour le programme final, il vaut mieux se baser sur la toute 1ère version que j'ai postée plutôt que sur le test de l'écho qui est bâclé. (je pense à la fonction AttendEtLitTout que je vois en haut de ton code)
Avant de l'écrire, j'aimerais savoir comment on sait si le moteur est prêt à recevoir une commande, ou s'il a bien effectué la commande demandée.
Par exemple :
- Est-ce qu'il répond que la commande est prise en compte ?
- Est-ce qu'il envoie un message en fin de rotation ?
- Est-ce qu'il peut répondre "commande invalide", remettre à zéro son buffer de commande ?
- Est-ce qu'on peut l'interroger sur sa disponibilité ou sa position actuelle ?
- Est-ce qu'il a un contrôle du flux comme RTS/CTS ou XOn/XOff ?
etc.
PS. Rassure-moi, le test de l'écho fonctionnait à tous les coups à la fin ? Il n'est pas question de faire du bancal, même si dans le principe mon test l'est, puisqu'il dépend d'un timing pour la réponse, mais à 500 ms d'attente si ça buggue ne serait-ce qu'une fois sur 100 c'est qu'on fait quelque chose de travers.
Salut,
Reponse: Disons que c´est moi qui ai fait n´importe quoi lors du debogguage. Ton code c possedait seulement des erreurs de syntaxe. En realite ton raisonnement sur les fonctions d´interruption etait correct.Si tu sais quelle était mon erreur, je serais curieux de savoir.
- Est-ce qu'il répond que la commande est prise en compte ?Avant de l'écrire, j'aimerais savoir comment on sait si le moteur est prêt à recevoir une commande, ou s'il a bien effectué la commande demandée.
Par exemple :
- Est-ce qu'il répond que la commande est prise en compte ?
- Est-ce qu'il envoie un message en fin de rotation ?
- Est-ce qu'il peut répondre "commande invalide", remettre à zéro son buffer de commande ?
- Est-ce qu'on peut l'interroger sur sa disponibilité ou sa position actuelle ?
- Est-ce qu'il a un contrôle du flux comme RTS/CTS ou XOn/XOff ?
etc.
Reponse: je ne crois pas. Mais le moteur SMCI33-2 accepte par definition le protocole suivant:
* Debut de l´instruction: #
* Adresse du moteur: 1 a 255
* Ordre de mission: Exemple: A , c, C, i ...etc
* Fin de l´instruction: \r
* Presence de guillemets au debut et a la fin du protocole. Exemple: "#2A\r"
Pour le demarrage du moteur, le caractere 'A' est indispensable.( "#2A\r")
- Est-ce qu'il envoie un message en fin de rotation ?
Reponse: aucune idee. Par contre avec l´instruction "#2S\r", on peut stopper le moteur pas a pas. 'S' ---> Arrêt du moteur
Avec le caractere 'W', on peut definir le nombre de repetition.
Exemple: "#2W\r" ---> une repetition
"#2W2\r" ---> deux repetitions
- Est-ce qu'on peut l'interroger sur sa disponibilité ou sa position actuelle ?
Reponse: oui, on peut l´interroger sur sa position actuelle.
l´instruction est : "#2C\R", C ---> Renvoie la position actuelle
- Est-ce qu'il a un contrôle du flux comme RTS/CTS ou XOn/XOff ?
Reponse: Je ne crois pas.
- Est-ce qu'il peut répondre "commande invalide", remettre à zéro son buffer de commande ?
Reponse: Oui
'c' --------> Remettre la position du moteur a zero. Exemple ----> "#2c\r"
'?' --------> Commande invalide. Exemple -----> "#2?\r"
- Mode de deplacement ---------> 'p'. ("#2p2\r")
- Distance a parcourrir ----------> 's'. ("#2s100\r"), 100 est la distance
J´espere que j´ai reponsu a tes question. En piece jointe se trouve le manuel de programmation du moteur pas a pas.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager