PRÉSENTATION
Le programme permet de recevoir une trame et de commander un moteur et un servo.
Le programme fonctionne ainsi*:
on attend un front montant sur D2 qui génère une interruption*: ISR(INT0_vect)
si front montant on appelle fct_StartTimer2(); qui démarre le comptage (CmptPulse) à l'aide des interruptions du timer2
puis on attend maintenant un front descendant.
lorsque front descendant*: interruption : ISR(INT0_vect) qui appelle la fonction fct_ReadBit().
Cette dernière va* déterminer si le premier bit fait bien environ 900us ( WildStartPulse) à partir de là autoriser la lecture des 2 octects suivants.
Pour cette lecture, je teste si à la position des bit successifs (grâce au timer 2)le signal sur D2 est haut ou bas. En fait je teste le bit s'il est à 1 ou 0
Je rempli un tableau avec les valeurs.
le programme navigue donc entre
fct_ReadBit(),
ISR(TIMER2_OVF_vect) qui incremente (CmptPulse)
LOOP
une fois la lecture des 2 octets terminer (CmptPulse>1000) on créer l'octect ByteX et ByteY
dont on se sert pour commander le moteur et le servo.
PROBLEME
le Byte X fonctionne très bien (essai à l'oscilo ou avec le moniteur série) chaque bit de x7 à x0 est correct. On va bien de 0 à 255.
le ByteY est faux
SAUF si je rajoute dans le programme* un Serial.println (quelque chose)*;
pourquoi la fonction Serial.println inserée dans le programme (même sans serialbegin). Me permet d'avoir des valeurs correctes du ByteY*????
Merci
TRAME
PROGRAMME
Code:// ce programme récupère une trame entrante sur D2 (INT0) // il faut que le premier bit ait une largeur de 1000us pour prendre en compte le reste de la trame (fct ReadBit) // une fois les 16 bits récuperés (y7 Y6... x1 x0) on reforme un octet byteX et un octet byteY // byteX pour commander le moteur et byteY le servo // programme effectué avec l'aide de la datasheet de l'atmenga 328P // Le Timer2 est utilisé pour determiner la largeur d'implusion entre front montant&descendant d'INT0 (entrée D2) // ainsi que pour determiner le moment ou on teste l'etat de chaque bit (on se repère dans la trame avec le timer2) // le Timer1 est utilisé pour le PWM du servo // le Timer0 est utilisé pour le PWM du moteur // les variables utilisées par les ISR doivent être déclarées en volatile // les volatiles sont normalement codée sur 1 octets??? // il serait necessaire de sauvegarder le SREG aprés une interruption??? (j'ai fait, mais pas tout compris) // ne pas utiliser le port serie ou des fonctions comme digitalWrite etc ... trop chronophage. // je suis obligé de mettre un Serial.println(); pour que le byteY soit correct et fasse fonctionner le servo correctement. unsigned int CmptPulse = 0; unsigned int WildStartPulse = 0; volatile int TypeFront=0; bool xy = 0;// permet de retourner du loop dans fct_ReadBit() tant qu'on n'a pas fini la trame bool x7 = 0;// bit 7 de la trame à recevoir bool x6 = 0;// bit 6 de la trame à recevoir bool x5 = 0;// bit 5 de la trame à recevoir bool x4 = 0;// bit 4 de la trame à recevoir bool x3 = 0;// bit 3 de la trame à recevoir bool x2 = 0;// bit 2 de la trame à recevoir bool x1 = 0;// bit 1 de la trame à recevoir bool x0 = 0;// bit 0 de la trame à recevoir bool y7 = 0;// bit 7 de la trame à recevoir bool y6 = 0;// bit 6 de la trame à recevoir bool y5 = 0;// bit 5 de la trame à recevoir bool y4 = 0;// bit 4 de la trame à recevoir bool y3 = 0;// bit 3 de la trame à recevoir bool y2 = 0;// bit 2 de la trame à recevoir bool y1 = 0;// bit 1 de la trame à recevoir bool y0 = 0;// bit 0 de la trame à recevoir int i=88; // pointeur de pulse (tombe au milieu de la largeur d'implusion du premier bit x7) int j=0; // variable pointeur de chaque bit de la trame 16 bit (0 à 15) pour le tableau A[16] unsigned char byteX = 0;// Octet du moteur unsigned char byteY = 0;// Octet du servo int PWMmoteur=0; int PWMservo=0; //static unsigned int previousTime = 0; // static : prend la valeur 0 qu'une fois //unsigned int currentMillis; void setup() { //Serial.begin(9600); // Ouverture du port série et debit de communication fixé à 9600 bauds cli(); // Désactive l'interruption globale TypeFront = 1; // front montant (TypeFront==0:front descendant) // D2 est defini comme la PIN recevant le signal d'entrée (la trame) EICRA = 0b00000011; // decl INT0 sur front montant (pin D2) EIMSK = 0b00000001; // autorise interruption broche INT0 (pin D2) // Timer2 permet de se localisée dans la trame (2 octects) TCCR2A = 0b00000000; // comptage normale TCCR2B = 0b00000001; // fclock/1 soit 62.5ns/div soit 16 us / 256 div timer2 DDRB |= 0b00000010; // D9 OUTPUT // pour mettre une pin HIGH ou LOW // on joue sur DDRB et PROTB // Timer0 PWM du Moteur brushed TCCR0A = (1<<COM0A1) | (1<<WGM01)|(1<<WGM00); // fast PWM signal non inversé TCCR0B = (1<<CS02) | (1<<CS00); // fclock/1024 soit 64us/div soit 16384 us / 256 div timer0 DDRD |=0b11010010; // D6 (OC0A signal pont en H); D7 et D4 (sens pont en H) en output TX toujour en output // Timer1 PWM du Servo TCCR1A = (1<<COM1A1) | (1<<WGM11); TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11); // prescaler = fcl/8 soit 500ns/div timer 1 ICR1 = 40000; //Période 20ms (40000x500ns) sei(); // Active l'interruption globale } void loop() { // currentMillis = millis(); if (xy==1) { //permet de retourner du loop dans fct_ReadBit() tant qu'on n'a pas fini la trame fct_ReadBit(); } /*else if ((xy==0)&&(currentMillis - previousTime >100)){ // on teste si pas de signal entrant (D2) pendant 200 ms alors on coupe les sorties PORTD &= ~0b10010000; // D4 D7 mis à LOW PORTB |= 0b00100000; //D13 allumée previousTime = currentMillis; }*/ else{ //rien } } int fct_StartTimer2() { // previousTime = currentMillis; EICRA = 0b00000010; // on programme INT0 sur front descendant: interruption sur front descendant (D2) EIMSK = 0b00000001; // interruption autorisée TypeFront = 0; // TypeFront sur front descendant (on attend maintenant un front descendant) TCNT2=0; // on clear le compteur du timer2 permet de compter plus proprement (D2) TIMSK2 |= 0b00000001; // autorise interruption du Timer2 } int fct_ReadBit() { if ((WildStartPulse>800) && (WildStartPulse<1000)) { //CmptPulse fait environ 55 donc le premier pulse fait environ 55*16us 900us // previousTime = currentMillis; xy=1;// permet de retourner du loop dans fct_Total tant qu'on n'a pas fini la trame if (CmptPulse>1000) { // fin de la trame environ 9500us TIMSK2 &= 0b00000000; // interdit interruption du Timer2 CmptPulse = 0; WildStartPulse = 0; i=88; j=0; TypeFront = 1; // on attend maintenant un front montant xy=0; Create_ByteX(); } else if (CmptPulse==i){ //else if ((CmptPulse>i-4) && (CmptPulse<i+4)){ // byte A[16]; // création du tableau pour octet XYvalue ( x7,x6...y7,y6...) // Attention à toujours déclarer le tableau en fonction du type // de variable qu'il contient (ici byte) si on met int A[16] // avec y4,y3... en byte, ça déconne A[j] = PIND & 0b00000100; A[j]=A[j]>>2; i=i+50; j=j+1; x7 = A[0];// bit 15 de la trame à recevoir x6 = A[1];// bit 14 de la trame à recevoir x5 = A[2];// x4 = A[3];// x3 = A[4];// x2 = A[5];// x1 = A[6];// x0 = A[7];// y7 = A[8];// y6 = A[9];// y5 = A[10];// y4 = A[11];// y3 = A[12];// y2 = A[13];// y1 = A[14];// y0 = A[15];// bit 0 de la trame à recevoir } else { // retourne dans loop } } else { Redem_Trame(); } } int Redem_Trame() { TIMSK2 &= 0b00000000; // interdit interruption du Timer2 CmptPulse = 0; WildStartPulse = 0; i=88; j=0; TypeFront = 1; // on attend maintenant un front montant xy=0; //delay(1); //PORTD &= ~0b00010000; // test // Serial.println(byteX); EICRA |= 0b00000011; // decl INT0 sur front montant (pin D2) EIMSK |= 0b00000001;// autorise interruption broche INT0 (pin D2) sei(); // Active l'interruption globale } int Create_ByteX(){ byteX |= (x7<<7)| (x6<<6)| (x5<<5)| (x4<<4)| (x3<<3)| (x2<<2)| (x1<<1)| (x0<<0); Create_ByteY(); } int Create_ByteY(){ byteY |= (y7<<7)| (y6<<6)| (y5<<5)| (y4<<4)| (y3<<3)| (y2<<2)| (y1<<1)| (y0<<0); //Serial.println(byteY); /*if (y6==1){ // test DDRD |=0b11010010; // D6 (OC0A signal pont en H); D7 et D4 (sens pont en H) en output TX toujour en output PORTD |= 0b00010000; // D4 HIGH (il faut DDRD a 1 et PORTD a 1) } else{ DDRD |=0b11010010; // D6 (OC0A signal pont en H); D7 et D4 (sens pont en H) en output TX toujour en output PORTD &= ~0b00010000; // test }*/ /* y7 = 0;// y6 = 0;// y5 = 0;// y4 = 0;// y3 = 0;// y2 = 0;// y1 = 0;// y0 = 0;// bit 0 de la trame à recevoir*/ //Serial.println(byteX); mappingXY(); } int mappingXY(){ if ((byteX<=126) && (byteX>=0)){ // marche arriere PWMmoteur=map(byteX,126,0,5,255); } else if ((byteX>=128) && (byteX<=255)){ // marche avant PWMmoteur=map(byteX,128,255,5,255); } else { PWMmoteur=3; } PWMservo=map(byteY,0,255,2000,4000); // 2000 pour 1000us; 3000 pour 1500us et 4000 pour 2000us //Serial.println(byteY); //commande_servo(); commande_moteur(); } int commande_moteur(){ if (byteX <= 126){ // Marche avant PORTD |= 0b00010000; // D4 HIGH (il faut DDRD a 1 et PORTD a 1) PORTD &= ~0b10000000; // D7 LOW (il faut DDRD a 1 et PORTD a 1) OCR0A = PWMmoteur; } else if (byteX >=128 ){ // Marche arriere PORTD |= 0b10000000; // D7 HIGH (il faut DDRD a 1 et PORTD a 1) PORTD &= ~0b00010000; // D4 LOW (il faut DDRD a 1 et PORTD a 1) OCR0A = PWMmoteur; } else { OCR0A = 3;// PWM au minimum PORTD &= ~0b10000000; // D7 LOW (il faut DDRD a 1 et PORTD a 1) PORTD &= ~0b00010000; // D4 LOW (il faut DDRD a 1 et PORTD a 1) } //Serial.println(byteX); //Serial.println(PWMmoteur); PWMmoteur=0; byteX=0; commande_servo(); } int commande_servo(){ OCR1A = PWMservo; PWMservo=0; byteY=0; Redem_Trame(); } int Incr_Compteur(){ CmptPulse++; } int StartPulse(){ WildStartPulse = CmptPulse * 16; //largeur impulsion en us } ISR(INT0_vect) { // lance routine d'interruption externe arrivé signal sur D2 uint8_t reg1_sauv; sei(); // Active l'interruption globale if (TypeFront ==1) { fct_StartTimer2(); } else if (TypeFront ==0){ // Front Descendant EIMSK = 0b00000000;// interdit interruption broche INT0 (pin D2) StartPulse(); fct_ReadBit(); } SREG=reg1_sauv ; // sauvegarde du registre } ISR(TIMER2_OVF_vect) { // lance routine d'interruption Timer2 uint8_t reg1_sauv; Incr_Compteur(); SREG=reg1_sauv ; }
-----