IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Embarqué Discussion :

L´envoi du contenu d´un fichier texte vers le port serie RS232


Sujet :

Embarqué

  1. #101
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Oui, là où j'ai écrit "data" c'était bien "c" que je voulais dire.

    Concernant ton test, j'ai un gros doute tout d'un coup : dans l'initialisation, est-ce que tu mets le bit UDRIE0 à 0 ou à 1 ?
    Je le répète, UDRIE0 doit être à zéro au démarrage de ton programme.
    Il doit être mis à 1 quand on a des données à envoyer.

    Dans ton test qui "fonctionne", tu balances des ACK sans arrêt. Essaie côté PC de virer le WriteFile et tu recevras toujours des ACK sans avoir rien demandé.

  2. #102
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Du moins j´ai active UDRIE0 dans le registre UCSR0B et le test a marche.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UCSZ02)|(1<<UDRIE0);
    J´ai essaye a nouveau ta proposition. Helas le pc ne rcoit rien.

  3. #103
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Okay, je vais suivre ta logique.

  4. #104
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Je ne comprends pas tes réponses. Il ne s'agit pas de suivre ma logique, mais celle de la doc du µC.
    Peut-être que je me plante sur le fonctionnement de l'interruption sur UDRE0 et dans ce cas il faut me l'expliquer. Sinon, fais le test dont je t'ai parlé (ne faire aucun WriteFile côté PC), ça permettra de valider le fait que l'interruption est cyclique.

  5. #105
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    J´ai vire "WriteFile" du test et j´ai obtenu ceci:
    Envoie de :
    5359,6121
    OK
    Envoie de :
    2756,4216
    OK
    ............
    T´a vu juste. Je me demande bien a quel niveau on se plante !!

  6. #106
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Je remets mon code après correction de quelques fautes de frappe et une réorganisation du code de RX.
    Si tu modifies à nouveau quelque chose (comme quand tu avais passé le flag UDRIE0 à 1), préviens-moi.

    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
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    #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 64u
    #define usart_command_max_size 10
    
    char usart_command[usart_command_max_size + 1] = {0};
    char usart0_tx_buffer[usart_buffer_max_size];
    char usart1_tx_buffer[usart_buffer_max_size];
    volatile uint8_t usart_command_size = 0;
    volatile uint8_t usart0_tx_buffer_size = 0;
    volatile uint8_t usart0_tx_buffer_start = 0;
    volatile uint8_t usart1_tx_buffer_size = 0;
    volatile uint8_t usart1_tx_buffer_start = 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) | (0<<TXEN0) | (1<<RXCIE0) | (0<<UDRIE0);
      UCSR0C = (1<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00);
      UCSR1B = (1<<RXEN1) | (0<<TXEN1) | (1<<RXCIE1) | (0<<UDRIE1);
      UCSR1C = (1<<USBS1) | (1<<UCSZ11) | (1<<UCSZ10);
    } 
    
    /* Ajout dans une file */
    void USART0_QueueIn(char c)
    {
      int i;
    
      if (usart0_tx_buffer_size < usart_buffer_max_size)
      {
        i = (usart0_tx_buffer_size + usart0_tx_buffer_start) % usart_buffer_max_size;
        usart0_tx_buffer[i] = c;
        ++usart0_tx_buffer_size;
      }
    }
    
    /* Sortie d'une file */
    /* J'utilise le caractère nul pour dire qu'il ne reste rien dans la file */
    /* Ca signifie que la file n'est pas prête à recevoir du binaire */
    char USART0_QueueOut(void)
    {
      char c;
    
      if (usart0_tx_buffer_size == 0)
        return 0;
      c = usart0_tx_buffer[usart0_tx_buffer_start];
      --usart0_tx_buffer_size;
      usart0_tx_buffer_start = (usart0_tx_buffer_start + 1) % usart_buffer_max_size;
      return c;
    }
    
    /* Ajout dans une file */
    void USART1_QueueIn(char c)
    {
      int i;
    
      if (usart1_tx_buffer_size < usart_buffer_max_size)
      {
        i = (usart1_tx_buffer_size + usart1_tx_buffer_start) % usart_buffer_max_size;
        usart1_tx_buffer[i] = c;
        ++usart1_tx_buffer_size;
      }
    }
    
    /* Sortie d'une file */
    /* J'utilise le caractère nul pour dire qu'il ne reste rien dans la file */
    /* Ca signifie que la file n'est pas prête à recevoir du binaire */
    char USART1_QueueOut(void)
    {
      char c;
    
      if (usart1_tx_buffer_size == 0)
        return 0;
      c = usart1_tx_buffer[usart1_tx_buffer_start];
      --usart1_tx_buffer_size;
      usart1_tx_buffer_start = (usart1_tx_buffer_start + 1) % usart_buffer_max_size;
      return c;
    }
    
    /* Envoie une réponse sur l'USART0 via la file de transfert */
    static void USART0_Send(const char *s)
    {
      int i;
      
      for (i = 0; s[i] != 0; ++i)
        USART0_QueueIn(s[i]);
      if (usart0_tx_buffer_size > 0)
        UCSR0B |= 1 << UDRIE0;
    }
    
    /* Envoie une commande sur l'USART1 via la file de transfert */
    static void USART1_Send(const char *s)
    {
      int i;
      
      for (i = 0; s[i] != 0; ++i)
        USART1_QueueIn(s[i]);
      if (usart1_tx_buffer_size > 0)
        UCSR1B |= 1 << UDRIE1;
    }
    
    /* Traitement de la commande */
    static void ProcessCommand(void)
    {
      int i;
      int x;
      int y;
      char x_moteur[12];
      char y_moteur[12];
    
      /* On extrait le X et le Y, puis on génère les commandes moteurs */
      for (i = 0; i < usart_command_size; ++i)
        if (usart_command[i] == ',')
          break;
      if (i <= 0 || i >= usart_command_size - 1)
      {
        /* On n'a pas trouvé la virgule au milieu de la chaîne -> erreur */
        USART0_Send("\x15");  /* NAK */
        usart_command_size = 0;
        return;
      }
      /* Je transforme volontairement x et y en int pour te permettre des contrôles ou des calculs */
      usart_command[i] = 0;
      usart_command[usart_command_size] = 0;
      x = atoi(usart_command);
      y = atoi(usart_command + i + 1);
      usart_command_size = 0;
      /* Envoi des commandes moteurs */
      itoa(x, x_moteur, 10);
      itoa(y, y_moteur, 10);
      USART1_Send("#1s");
      USART1_Send(x_moteur);
      USART1_Send("\r");
      USART1_Send("#2s");
      USART1_Send(y_moteur);
      USART1_Send("\r");
      /* TODO:
      Le moteur répond par un écho pour confirmer la commande
      Il faut le gérer, mais pas directement ici, car ici on ne doit pas rester trop longtemps */
      USART0_Send("\x06");  /* ACK */
    }
    
    /* La fonction d´interruption de reception du byte */
    /* Cette fonction est active lorsque RXCIE0 = 1 */ 
    ISR(USART0_RX_vect)
    {
      char data;
    
      data = UDR0;
      if (data == '\r')
        /* Traitement de la commande */
        ProcessCommand();
      else if (data == '\n')
        /* Démarrage d'une nouvelle commande */
        usart_command_size = 0;
      else
        /* Quand on ne reçoit ni \r ni \n, on enregistre le caractère dans la commande */
        if (usart_command_size < usart_command_max_size)
        {
          usart_command[usart_command_size] = data;
          ++usart_command_size;
        }
    }
    
    /* La fonction d´interruption d´envoi de byte */
    /* Cette fonction est active lorsque UDRIE0 = 1 */
    ISR(USART0_UDRE_vect)
    {
      UDR0 = USART0_QueueOut();
      /* S'il n'y a plus de données à envoyer on arrete l'emission */
      if (usart0_tx_buffer_size == 0)
        UCSR0B &= ~(1 << UDRIE0);
    }
    
    /* La fonction d´interruption d´envoi de byte */
    /* Cette fonction est active lorsque UDRIE1 = 1 */
    ISR(USART1_UDRE_vect)
    {
      UDR1 = USART1_QueueOut();
      /* S'il n'y a plus de données à envoyer on arrete l'emission */
      if (usart1_tx_buffer_size == 0)
        UCSR1B &= ~(1 << UDRIE1);
    }
    
    int main (void)
    { 
      USART_Init(UBRR_VAL);
      sei();
      /* TODO: Ici il faut paramétrer les moteurs (mode de positionnement etc.) */
      while (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
    #include <fstream>
    #include <string>
    #include <iostream>
    #include <sstream>
    
    #include <Windows.h>
    
    using namespace std;
    
    // Envoie une commande caractère par caractère, et teste la réception d'un ACK
    static bool EnvoieCommande(HANDLE h, string s)
    {
    	DWORD	length;
    	char	c;
    
    	// S'il y avait des réponses à lire depuis la dernière commande,
    	// trop tard, on les supprime.
    	PurgeComm(h, PURGE_RXCLEAR);
    	if (!WriteFile(h, s.c_str(), s.size(), &length, 0) || length != s.size())
    	{
    		cout << "Erreur de WriteFile" << endl;
    		return false;
    	}
    	if (!ReadFile(h, &c, 1, &length, 0) || length != 1)
    	{
    		cout << "Erreur de ReadFile (time-out)" << endl;
    		return false;
    	}
    	cout << "Réponse : " << (int)c << endl
    	return c == '\x06';	// ACK
    }
    
    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;
    	}
    	// Ouverture du port COM (c'est votre code tel quel)
    	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);
    	COMMTIMEOUTS timeouts = { 0 };
    	timeouts.ReadIntervalTimeout = 100;
    	timeouts.ReadTotalTimeoutMultiplier = 100;
    	timeouts.ReadTotalTimeoutConstant = 100;
    	timeouts.WriteTotalTimeoutMultiplier = 100;
    	timeouts.WriteTotalTimeoutConstant = 100;
    	if (!SetCommTimeouts(h, &timeouts))
    	{
    		cout << "Erreur: SetCommTimeouts" << endl;
    		CloseHandle(h);
    		return 1;
    	}
    	// 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;	// flux de sortie (une paire de coordonnées)
    
    		// 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 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;
    		// Envoi des coordonnées par le port série
    		output << '\n';
    		output << x_steps;
    		output << ',';
    		output << y_steps;
    		output << '\r';
    		cout << "Envoi de : " << output.str() << endl;
    		if (EnvoieCommande(h, output.str()))
    			cout << "OK" << endl;
    		else
    			cout << "ERREUR" << endl;
    	}
    	CloseHandle(h);
    	return 0;
    }

  7. #107
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Bonjour Hibernatus34,

    tout d´abord je tiens a m´escuser pour mon silence. En fait j´ai revu en integralite les codes et je n´ai decele aucune erreurs de notre part. Bref je ne comprenais pas ce qui clôchait. Alors j´ai decide de tester a nouveau la communication entre le pc et le µC. Mais le test n´a pas marche. C´est alors que j´ai compris que l´erreur ne venait pas des codes, mais de mon circuit electronique. En fait, une entree de mon circuit ne recevait pas assez de courant. Au lieu de recevoir 5volt, l´entree en question du circuit recevait moins de 1Volt. Bref j´ai remedie au probleme et j´ai teste a nouveau les derniers codes que tu as postes. Le resultat donne ceci:

    Envoi de:
    5359,6121
    Reponse: 6
    OK
    Envoi de:
    2756,4216
    Reponse: 6
    OK
    Le µC recoit en effet les positions et en suite il retourne au pc la reponse 'ACK' pour confirmer la reception.

    Cependant, j´ai teste les codes precedents et ils fonctionnent aussi.

    Dire que mon circuit me jouait un sale tour.

    merci.

  8. #108
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Une fois de plus bonjour,

    J´ai parametrer les moteurs de commande dans le code du µC comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void ParametrageMoteur(void)
     { 
       USART1_Send("#2D\r"); // Considerer la position actuelle comme origine du repere sur l´axe x 
       USART1_Send("#3D\r"); // Considerer la position actuelle comme origine du repere sur l´axe y
       
       USART1_Send("#2p2\r");// Mode de travail: deplacement absolu --> p = 2
       USART1_Send("#3p2\r");	      
     }
    Dans la fonction ProcessCommand(), j´ai ajoute:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     - USART1_Send("#2A\r"); // Activation de l´envoi sur l´axe x
     - USART1_Send("#3A\r"); // Activation de l´envoi sur l´axe y
    J´ai aussi modifie la configuration de l´USART0 et l`USART1 de la maniere suivante:
    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
    void USART_Init (unsigned int ubrr)
    {
      UBRR0H = (unsigned char)(ubrr>>8);
      UBRR0L = (unsigned char) ubrr;
      UBRR1H = (unsigned char)(ubrr>>8);
      UBRR1L = (unsigned char) ubrr;
      
    /* Enable receiver and transmitter and set frame format: 8data, 2stop bit */ 
    
      UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UCSZ02)|(0<<UDRIE0);
      UCSR0C = (1<<USBS0) | (1<<UCSZ01)|(1<<UCSZ00);
    
      UCSR1B = (0<<RXEN1)|(1<<TXEN1)|(0<<RXCIE1)|(0<<TXCIE1)|(0<<UCSZ12)|(0<<UDRIE1);
      UCSR1C = (1<<USBS1) |(1<<UCSZ11)|(1<<UCSZ10);
      
    }
    Code du µC en integralite:
    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
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    #include <avr/io.h>
    #include <avr/interrupt.h> 
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdint.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 usart_buffer_max_size 64u
    #define usart_command_max_size 10
    
    /***************************************************/
    
    char usart_command[usart_command_max_size + 1] = {0};
    char usart0_tx_buffer[usart_buffer_max_size ];
    char usart1_tx_buffer[usart_buffer_max_size ];
    volatile uint8_t usart_command_size = 0;
    volatile uint8_t usart0_tx_buffer_size = 0;
    volatile uint8_t usart0_tx_buffer_start = 0;
    volatile uint8_t usart1_tx_buffer_size = 0;
    volatile uint8_t usart1_tx_buffer_start = 0;
    
    
    /****************************************************/
        /* Set baud rate */
    
    void USART_Init (unsigned int ubrr)
    {
      UBRR0H = (unsigned char)(ubrr>>8);
      UBRR0L = (unsigned char) ubrr;
      UBRR1H = (unsigned char)(ubrr>>8);
      UBRR1L = (unsigned char) ubrr;
      
    /* Enable receiver and transmitter and set frame format: 8data, 2stop bit */ 
    
      UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UCSZ02)|(0<<UDRIE0);
      UCSR0C = (1<<USBS0) | (1<<UCSZ01)|(1<<UCSZ00);
    
      UCSR1B = (0<<RXEN1)|(1<<TXEN1)|(0<<RXCIE1)|(0<<TXCIE1)|(0<<UCSZ12)|(0<<UDRIE1);
      UCSR1C = (1<<USBS1) |(1<<UCSZ11)|(1<<UCSZ10);
      
    } 
    
    /*********************************************************
    
    /**********************************************************/
    
    /*-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)
    }
    
    /* Ajout dans une file */
    void USART0_QueueIn(char c)
    {
      int i;
      
    
      if (usart0_tx_buffer_size < usart_buffer_max_size)
      {
        i = (usart0_tx_buffer_size + usart0_tx_buffer_start) % usart_buffer_max_size;
        usart0_tx_buffer[i] = c;
        ++usart0_tx_buffer_size;
      }
    }
    
    /* Sortie d'une file */
    /* J'utilise le caractère nul pour dire qu'il ne reste rien dans la file */
    /* Ca signifie que la file n'est pas prête à recevoir du binaire */
    char USART0_QueueOut(void)
    {
      char c;
    
      if (usart0_tx_buffer_size == 0)
        return 0;
      c = usart0_tx_buffer[usart0_tx_buffer_start];
      --usart0_tx_buffer_size;
      usart0_tx_buffer_start = (usart0_tx_buffer_start + 1) % usart_buffer_max_size;
      return c;
    }
    
    /* Ajout dans une file */
    void USART1_QueueIn(char c)
    {
      int i;
      
      if (usart1_tx_buffer_size < usart_buffer_max_size)
      {
        i = (usart1_tx_buffer_size + usart1_tx_buffer_start) % usart_buffer_max_size;
        usart1_tx_buffer[i] = c;
        ++usart1_tx_buffer_size;
      }
    }
    
    /* Sortie d'une file */
    /* J'utilise le caractère nul pour dire qu'il ne reste rien dans la file */
    /* Ca signifie que la file n'est pas prête à recevoir du binaire */
    char USART1_QueueOut(void)
    {
      char c;
    
      if (usart1_tx_buffer_size == 0)
        return 0;
      c = usart1_tx_buffer[usart1_tx_buffer_start];
      --usart1_tx_buffer_size;
      usart1_tx_buffer_start = (usart1_tx_buffer_start + 1) % usart_buffer_max_size;
      return c;
    }
    
    /* Envoie une réponse sur l'USART0 via la file de transfert */
    static void USART0_Send(const char *s)
    {
      int i;
      
      for (i = 0; s[i] != 0; ++i)
        USART0_QueueIn(s[i]);
      if (usart0_tx_buffer_size > 0)
        UCSR0B |= 1 << UDRIE0;
    }
    
    /* Envoie une commande sur l'USART1 via la file de transfert */
    static void USART1_Send(const char *s)
    {
      int i;
      
      for (i = 0; s[i] != 0; ++i)
        USART1_QueueIn(s[i]);
      if (usart1_tx_buffer_size > 0)
        UCSR1B |= 1 << UDRIE1;
    }
    
    /* Traitement de la commande */
    static void ProcessCommand(void)
    {
      int i;
      int x;
      int y;
      char x_moteur[12];
      char y_moteur[12];
    
      /* On extrait le X et le Y, puis on génère les commandes moteurs */
      for (i = 0; i < usart_command_size; ++i)
        if (usart_command[i] == ',')
          break;
      if (i <= 0 || i >= usart_command_size - 1)
      {
        /* On n'a pas trouvé la virgule au milieu de la chaîne -> erreur */
        USART0_Send("\x15");  /* NAK */
        usart_command_size = 0;
        return;
      }
      /* Je transforme volontairement x et y en int pour te permettre des contrôles ou des calculs */
      usart_command[i] = 0;
      usart_command[usart_command_size] = 0;
      x = atoi(usart_command);
      y = atoi(usart_command + i + 1);
      usart_command_size = 0;
      /* Envoi des commandes moteurs */
      itoa(x, x_moteur, 10);
      itoa(y, y_moteur, 10);
      USART1_Send("#2s");
      USART1_Send(x_moteur);
      USART1_Send("\r");
      USART1_Send("#2A\r"); // Activation de l´envoi de x_moteur via USART1
      USART1_Send("#3s");
      USART1_Send(y_moteur);
      USART1_Send("\r");
      USART1_Send("#3A\r"); // Activation de l´envoi de y_moteur via USART1
      /* TODO:
      Le moteur répond par un écho pour confirmer la commande
      Il faut le gérer, mais pas directement ici, car ici on ne doit pas rester trop longtemps */
      USART0_Send("\x06");  /* ACK */
    }
    
    /* La fonction d´interruption de reception du byte */
    /* Cette fonction est active lorsque RXCIE0 = 1 */ 
    ISR(USART0_RX_vect)
    {
      char data;
    
      data = UDR0;
      if (data == '\r')
        /* Traitement de la commande */
        ProcessCommand();
      else if (data == '\n')
        /* Démarrage d'une nouvelle commande */
        usart_command_size = 0;
      else
        /* Quand on ne reçoit ni \r ni \n, on enregistre le caractère dans la commande */
        if (usart_command_size < usart_command_max_size)
        {
          usart_command[usart_command_size] = data;
          ++usart_command_size;
        }
    }
    
    /*
    ISR(USART0_RX_vect)
    {
      char data;
      data = UDR0;
    
      if (data == '\r')
        UCSR0B |= 1 << UDRIE0;
    }
    
    ISR(USART0_UDRE_vect)
    {
      
      UDR0 = '\x06';
      //  UCSR0B |= 0 << UDRIE0;
      UCSR0B &= ~(1 << UDRIE0);
    }
    */
    
    /* La fonction d´interruption d´envoi de byte */
    /* Cette fonction est active lorsque UDRIE0 = 1 */
    ISR(USART0_UDRE_vect)
    {
      UDR0 = USART0_QueueOut();
      /* S'il n'y a plus de données à envoyer on arrete l'emission */
      if (usart0_tx_buffer_size == 0)
        UCSR0B &= ~(1 << UDRIE0);
    }
    
    /* La fonction d´interruption d´envoi de byte */
    /* Cette fonction est active lorsque UDRIE1 = 1 */
    ISR(USART1_UDRE_vect)
    {
      UDR1 = USART1_QueueOut();
      /* S'il n'y a plus de données à envoyer on arrete l'emission */
      if (usart1_tx_buffer_size == 0)
        UCSR1B &= ~(1 << UDRIE1);
    }
    
    void ParametrageMoteur(void)
     { 
       USART1_Send("#2D\r"); // Considerer la position actuelle comme origine du repere sur l´axe x 
       USART1_Send("#3D\r"); // Considerer la position actuelle comme origine du repere sur l´axe y
       
       USART1_Send("#2p2\r");// Mode de travail: deplacement absolu --> p = 2
       USART1_Send("#3p2\r");	      
     }
    
    
    int main (void)
    { 
      USART_Init(UBRR_VAL);
      RS485_Init();
    /* TODO: Ici il faut paramétrer les moteurs (mode de positionnement etc.) */
      ParametrageMoteur();
      sei();
     
      while (1)
      {	 
      }
      
    }
    Qu´en penses-tu ? Dois-je proceder autrement ou bien ma proposition est bonne ?

  9. #109
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Content que ça marche.
    Je pense que tu es sur les rails maintenant, tu n'as plus tellement besoin de moi.

  10. #110
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Je pense que tu es sur les rails maintenant, tu n'as plus tellement besoin de moi.
    J´ai interêt a être sur les rails, car je ressens deja la pression. Neanmoins, je vais te tenir informer de la suite.

    Merci encore .

  11. #111
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Bonsoir Hibernatus,

    j´ai quelques soucis avec le pc, le µC et les deux moteurs de commande.

    J´ai envoye en integralite les positions X et Y du pc vers le µC. L´envoi des donnees fonctionnent, mais les deux moteurs (axe X et Y) de la platine relies aux deux moteurs de commande ne recoivent pas toutes les positions envoyees par le microcontrôleur.

    Pour être plus clair, si le pc envoie 15 couples (X,Y) de position, alors la platine effectue uniquement le deplacement d´un couple de position. Pourtant la platine devrait aussi effectuer le deplacement de 15 couples de position qui lui ont ete transmis par le µC . Mais la platine ne recoit pas toutes les 15 positions, elle(platine) recoit seulement une position.


    J´ai verifie la configuration du pc et du µC et tout semble être ok. Helas la platine n´effectue pas le deplacement de toutes les positions qui sont envoyes par le pc et puis le microcontrôleur. Se pourrait-il que le microcontrôleur et le pc soient trop rapide pour les deux moteurs de commande? Ou bien on doit diminuer la vitesse d´envoi des positions du pc vers le microcontrôleur ?? j´ai essaye de regler le probleme, mais je n´y arrive pas !!

    Sais-tu comment on pourrais ressoudre ce probleme ?

    Merci d´avance et bonne soiree.

  12. #112
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Salut,

    Il y a plusieurs possibilités.
    Évidemment le buffer d'entrée des moteurs n'est pas infini, mais surtout il pourrait être limité à une commande. Dans ce cas il faut attendre la réponse du moteur avant d'en envoyer une autre.
    Je n'en sais rien, c'est à toi de te renseigner sur ces moteurs, mais de toute façon, à moins que le débit d'envoi temporise lui-même suffisamment, il est certain que tu ne peux pas envoyer une infinité de commandes en continu.

    Je crois que les moteurs renvoient un écho à chaque commande.
    Il est probable que cet écho suffise à dire "je suis prêt à recevoir une autre commande" (même si la rotation n'est pas terminée, le buffer de commande est prêt). Sinon, il y a peut-être une fonction de polling pour demander au moteur "es-tu prêt ?".

    Tu peux par exemple renvoyer le ACK au PC uniquement quand tu as reçu l'écho des moteurs. Puisque le PC attend ce ACK après chaque commande, ça temporisera automatiquement. (sous réserve d'un réglage du time-out)
    Pour ça il faut gérer une ISR sur le RX de l'USART1.

    Quand on reçoit \r sur l'USART0, au lieu de renvoyer ACK à la fin, on stocke les 2 échos qu'on attend dans des chaînes statiques.
    Quand on reçoit \n sur l'USART0, on vide ces 2 chaînes (machaîne[0] = 0). C'est pour le cas d'un time-out ou d'un redémarrage.
    Quand on reçoit quelque chose sur l'USART1, on le compare à l'écho attendu, et quand on l'a reçu, on envoie un ACK sur l'USART0.
    Si on reçoit autre chose que ce qui était attendu, je pense qu'il faut l'ignorer.

    Je ne connais pas le RS-485, je ne sais pas ce qui garantit que tu reçois une réponse complète de chaque moteur, sans entrelacement entre les deux.
    Faisons comme si c'était géré pour l'instant, donc il suffit d'un buffer d'entrée etc. (comme le buffer de commande qu'on utilise sur l'USART0, ou une file pour ignorer facilement des reliquats d'une autre réponse)

    Là il faudrait l'avis de quelqu'un qui a de l'expérience dans ce domaine.

  13. #113
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    PS. J'ai cherché un peu des infos sur le RS-485, visiblement c'est du half-duplex géré en "software". Je suis pas sûr d'avoir compris, mais j'ai l'impression il faudrait donc envoyer une commande à un moteur, attendre sa réponse, envoyer celle de l'autre moteur et attendre sa réponse. Et pas envoyer les 2 commandes d'un coup et attendre les 2 réponses après.
    Si quelqu'un connaissant le RS-485 peut te renseigner, ça sera mieux.
    Ou peut-être que c'est expliqué dans la doc du moteur.

  14. #114
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Bonjour Hibernatus,

    J´ai recueuillis les infos et j´aimerais te communiquer le concept.

    1er etape: Le pc envoie sucessivement les positions ligne par ligne au µC

    2ieme etape:
    -si le µC ne recoit pas les positions , il retourne "NAK" au pc

    -si le µC recoit les positions, alors il retourne "ACK" au pc

    -Ensuite le µC envoie sucessivement les positions (X,Y)
    simultanement vers les deux moteurs de commande.

    3ieme etape:

    -Des lors que les deux moteurs de commande recoivent sucessivement une position (X,Y), alors les moteurs de commande retournent respectivement les reponses pour confirmer si oui ou non la position recue a ete parcourue par la platine sur les deux axes x et y.

    - Une fois que la platine aura atteint la position (X,Y) envoyee, il va falloir faire une courte pause, afin que un trou soit perce sur la platine.

    - En suite on peut passer a l´envoie de la 2nde position, 3ieme position, 4ieme position, ainsi de suite. Biensûr toutes les positions envoyees par le pc devront respecter le protocol que je viens de decrire.

    En bref, il faut qu´on envoie une position (X,Y) d´un coup, ensuite les deux moteurs de commande retournent les reponses pour confirmer si oui ou non la platine s´est deplaacee a la position (X,Y). Apres il va falloir faire une courte pause pour faire un trou sur la platine correspondant a la position (X,Y) parcourue par la platine. En suite on passe a partir du pc a l´envoi de la 2nde, 3ieme , 4ieme position ...etc

    En fait, c´est le protocol qu´on m´a propose afin qu´il n y ait plus de conflit pendant le transfert des positions entre le pc, le µC et les deux moteurs de commande. Je crois que ce concept suit aussi tes idees. Mais c´est vraiment primordial qu´une position soit envoyee d´un coup. Je me suis renseigne et on m´a dit que le RS485 peut le faire.

    Qu´en penses-tu ?

  15. #115
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Il faut m'expliquer comment le RS-485 peut le faire.
    Sur ce sujet, si je ne comprends pas comment ça marche, je vais partir du principe que ça ne marche pas.
    D'après ce que j'ai lu (ou plutôt survolé), c'est au maître (ton µC) de faire respecter un protocole. Quand il envoie un message à une adresse spécifique, il doit attendre sa réponse avant d'envoyer tout autre message.

    Là, si on envoie une commande à chaque moteur presque en même temps, et si le décalage inverse est produit par un moteur plus long que l'autre à répondre (oui c'est un peu tiré par les cheveux), il vont se retrouver à vouloir émettre en même temps une réponse. Donc il faut m'expliquer pourquoi et comment ça va marcher quand même.

    Concernant le reste, tu sembles dire au début de la 3ème étape que la réponse du moteur est envoyée à la fin du mouvement. Tu es sûr de ce point ? C'est important à savoir.

    Ce qui ne va pas dans ton protocole, c'est que rien ne permet au PC de savoir quand il peut envoyer une nouvelle commande, car il reçoit le ACK trop tôt.

  16. #116
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    salut hibernatus,

    ce que tu dis est vraiment pertinent. Pourrais-tu me suggerer une amelioration du protocol que je t´ai presente.

    Il faut m'expliquer comment le RS-485 peut le faire.
    En fait le µC et les deux moteurs de commande sont connectes par un câble. le bout du câble connecte a l´USART1 du µC possede une entree RS485 et l´autre bout du câble connecte aux deux moteurs de commande possedes deux sorties RS485. Car chaque Moteur de commande possede une entree RS485.
    Lorsque j´ai effectue le deboggage en transferant les positions du fichier texte en direction des deux moteurs de commande, j´ai remarque que la platine effectue uniquement le deplacement d´une position (X,Y) simultanement sur l´axe x et y. Biensûre c´est grâce a tes codes du pc et µC que j´ai observe cela. C´est pourquoi je pense que c´est possible d´envoyer simultanement une position (X,Y) via le RS485 du µC en direction des deux moteurs de commande.

    Concernant le reste, tu sembles dire au début de la 3ème étape que la réponse du moteur est envoyée à la fin du mouvement. Tu es sûr de ce point ? C'est important à savoir.
    Bon, je ne suis pas sûre a 100%. J´ai regarde dans le doc du moteur de commande pour connaître l´instruction qui permet de retourner une reponse lorsque le moteur recoit une position. Helas j´ai pas trouve. Peut-être que je suis passe a côte. Mais je vais encore chercher, car se serait embêtant qu´il n´est pas pense a cela. Cependant, il y a une instruction qui permet de connaître la distance parcourue par la platine. Je ne sais pas si cela peut nous aider. En clair, c´etait une proposition !!

    Qu´en dis-tu ? Apparement, il faut a tout prix que les moteurs de commande nous fournissent des reponses. Mais je ne sais pas si cela doit se faire avant ou apres le deplacement de la platine !! Tout compte fait, je pense que la reponse doit intervenir avant le deplacement de la platine.

  17. #117
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Ton explication n'est pas suffisante.
    D'après ce que j'ai cru comprendre, le RS-485 ne ferait que du half-duplex (un seul point émet à la fois, donc le µC ne pourrait pas émettre une commande Y en même temps qu'il reçoit l'écho de X).
    Et, toujours d'après ce que j'ai cru comprendre, l'orchestration se fait par la couche supérieure, en général avec un système maître/esclaves :
    - Le maître peut envoyer des trames nominatives, il attend alors la réponse de chacune avant d'émettre à nouveau.
    - Il peut aussi envoyer des trames en broadcast, et là il ne doit pas y avoir de réponse.
    - Enfin, les esclaves ne doivent émettre que pour répondre aux trames du maître (l'écho renvoyé par les moteur, qui ne commence pas par #, d'ailleurs).

    Mais bon, je peux pas te garantir que j'ai bien tout compris.

  18. #118
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Okay, essayons ta proposition. C´est fort probable que mon explication ne soit pas suffisant!!!

  19. #119
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    110
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 110
    Points : 27
    Points
    27
    Par défaut
    Bonjour Hibernatus34,

    J´ai relus la doc du moteur de commande et il s´avere effectivement que le moteur de commande
    retourne une reponse lorsqu´il recoit une commande valide ou invalide. J´ai recueillis ces
    explications a la page 10 de la doc (Controller response).

    - Si le moteur de commande reconnaît une commande comme etant valide, alors le moteur de
    commande confirme la reception en retournant la commande recue comme echo, mais sans le
    caractere '#' , qui marque le debut d´une commande.

    Exemple: Commande envoyee au moteur de commande ------> '#1G10000000\r'
    Reponse du moteur de commande ------> '1G10000000\r'

    - Si le moteur de commande reconnaît une commande qu´il recoit comme etant une commande
    invalide, alors le moteur de commande retourne comme reponse la commande recue en incluant
    un point d´interrogation '?' avant le caractere '\r', qui marque la fin d´une commande.

    Exemple: Commande envoyee au moteur de commande ------> '#1°\r'
    Reponse du moteur de commande - -----> '#1°?\r'

    D´apres ces explications, je pense qu´il est preferable que les deux moteurs de commande
    retournent une reponse lorsqu´il recoivent une commande valide ou invalide avant que la
    platine se deplace. Une fois les reponses retournees par les deux moteurs de commande, le uc
    retourne "ACK" ou "NAK" au pc et la platine se deplace a la position de la commande qu´il
    a recue. Puis une courte pause sera effectuee pour percer un trou sur la platine. Dans la
    même lancee, les prochaines positions qui seront envoyees respecteront ce procesus.

    En clair, tes propositions etaient les bonnes. Dis Hibernatus34, comment
    va-t-on s´y prendre pour la programmation. Elle sera a coup sûre complexe.

  20. #120
    Membre expérimenté
    Inscrit en
    Août 2010
    Messages
    726
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 726
    Points : 1 645
    Points
    1 645
    Par défaut
    Dis Hibernatus34, comment va-t-on s´y prendre pour la programmation. Elle sera a coup sûre complexe.
    A un moment donné il faut savoir dire stop, parce que j'ai aussi un boulot, et parce que je t'ai déjà trop aidé.

    Une remarque, quand même :
    Je ne sais pas ce qu'est cette histoire de trou, mais si tu dois déclencher une autre action à la fin du positionnement, il te faudra interroger les moteurs pour savoir quand ils ont terminé leur mouvement.

+ Répondre à la discussion
Cette discussion est résolue.
Page 6 sur 7 PremièrePremière ... 234567 DernièreDernière

Discussions similaires

  1. Réponses: 1
    Dernier message: 30/04/2010, 21h24
  2. Réponses: 3
    Dernier message: 26/10/2009, 13h32
  3. Lecture d´un fichier texte .
    Par pilouface dans le forum C
    Réponses: 5
    Dernier message: 20/01/2006, 23h48
  4. importation d'un fichier texte vers excel
    Par darkpocket dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 07/01/2005, 11h47

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo