#include #include "USBDesc.h" #include "Platform.h" int main(void) { init(); USBDevice.attach(); setup(); for (;;) { loop(); } return 0; } // definition des fonction cbi sbi idem assembleur #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif // définitions #define TEMPDMXRX 8 // Longueur de trame mini en reception #define IOUTDMX_FIN -4 #define IOUTDMX_WAIT -5 #define IOUTDMX_IDLE -1 #define IOUTDMX_BRK -2 #define IOUTDMX_MAB -3 #define IINUSB_IDLE 0 #define IINUSB_ESC 1 #define IINUSB_DATA 2 #define IINUSB_PARAM 10 #define TX1PIN 1 // pin DMX serial 1 #define LEDPIN 13 // led interne #define RX_TX_LED_TIME 12 // tableaux de données byte tab_input_pc[514]; // venant du pc byte tab_input_dmx[518]; // données venant de l'extérieur : les 512 premiers DMX; les 4 suivant 4x8 bp ; byte tab_temp_dmx[TEMPDMXRX]; byte inbuffer[7]; // Variables d'état et compteurs volatile int index_input_pc=0; // entrée USB volatile int index_output_pc=0; // sortie USB volatile int index_input_dmx=513; // entrée dmx volatile int index_output_dmx=0; // sortie dmx volatile int etat_input_pc=IINUSB_IDLE; // etat entrée USB volatile int emissionPc=0; // flag : emission USB en attente unsigned int blkl = 0, blkcpt=0, rxledcpt=0 ,txledcpt=0; // Gestion des leds unsigned int blinkon, blinkp, interbrk=0; // idem // Paramètres byte brk_timer_end=75; // Duree Break (par 2µs) def : 150us byte mab_timer_end=25; // Duree MAB (par 2µs) def : 50us int nb_circuits=512; // Nombre de circuits DMX emis int dmx_frame_interval=40; // Intervale entre trames DMX emises bool flag_merge1=1; bool syncflag=false; // ********************************** USB ***************************** // // lancé par interruption USB sur reception d'un char <- Cette fonction nécessite une modif de la lib arduino // l'interet est de ne pas utiliser le buffer de la classe Serial, trop petit (64o) void CDC_accept() { char c; byte *pb, *pe; switch (etat_input_pc) { case IINUSB_IDLE: USB_Recv(CDC_RX,&c,1); // on attend un 'esc' pour commencer if (c==27) { etat_input_pc=IINUSB_ESC; break;} break; case IINUSB_ESC: USB_Recv(CDC_RX,&c,1); // on attend 'D' pour recevoir if (c==68) { etat_input_pc=IINUSB_DATA; index_input_pc=1; tab_input_dmx[517]=68; index_output_pc=1; // on init l'index d'emmission vers le pc ( le 0 n'est pas emit => start code) emissionPc=1; break; } // Esc 'C' réinit if (c==67) { etat_input_pc=IINUSB_IDLE; pe=tab_input_pc+514; for(pb=tab_input_pc;pb 512) { etat_input_pc=0; if(index_output_dmx==IOUTDMX_WAIT) index_output_dmx=IOUTDMX_IDLE; } break; case IINUSB_PARAM: index_input_pc+=USB_Recv(CDC_RX,inbuffer+index_input_pc,5-index_input_pc); if(index_input_pc<5) return; nb_circuits= ((int)inbuffer[0])*2 + 2; brk_timer_end = (inbuffer[1]/2); mab_timer_end = (inbuffer[2]/2); flag_merge1 = inbuffer[3] & 1; dmx_frame_interval = inbuffer[4]; etat_input_pc=0; // on a tout recu, on reponds tab_input_dmx[517]=66; index_output_pc=517; // on init l'index d'emmission vers le pc ( uniquement etat : 66 'B' ) emissionPc=1; break; default: // on fait rien break; } } void ecritUSB() { TXLED1; txledcpt=RX_TX_LED_TIME; if(index_output_pc > 516){ // Emission d'un seul caractere (code etat) USB_Send(CDC_TX,tab_input_dmx+index_output_pc,1); emissionPc=0; return; } // Emission du tableau complet index_output_pc+= USB_Send(CDC_TX,tab_input_dmx+index_output_pc, 517-index_output_pc); if (index_output_pc>516) { emissionPc=0; } } // ********************************** RECEPTION DMX ********************************* // // vecteur d'intéruption pour reception dmx // sur reception d'un caractere / erreur ISR(USART1_RX_vect) { char c,r; r = UCSR1A; c = UDR1; if (r & (1< doit etre 0 if ( index_input_dmx on copie ce qu'on a déja recu for(int i=0;i Permet d'attendre que tout soit parti avant de déclancher le break ISR(USART1_TX_vect) { // si l'USART 1 est vide => break if(index_output_dmx==IOUTDMX_FIN) { if(syncflag) { syncflag=false; index_output_dmx=IOUTDMX_WAIT; } else index_output_dmx=IOUTDMX_IDLE; } } // vecteur : USART 1 transmission registre vide ISR(USART1_UDRE_vect) { if (flag_merge1==1) { UDR1 = max(tab_input_pc[index_output_dmx],tab_input_dmx[index_output_dmx]); } else { UDR1 = tab_input_pc[index_output_dmx]; } index_output_dmx++; // si 512 transmits => mise en attente de fin de transmission // desactivation de l'interruption sur le registre if (index_output_dmx>nb_circuits) { index_output_dmx=IOUTDMX_FIN; cbi(UCSR1B, UDRIE1); } } // Timer 4 : gestion des temps de break et mab ISR(TIMER4_COMPA_vect) { if (index_output_dmx==IOUTDMX_BRK ) { // en cours de break index_output_dmx=IOUTDMX_MAB; digitalWrite(TX1PIN, HIGH); // on met la broche à 1 // on relance le timer sur le temps du mab OCR4A = mab_timer_end ; TCNT4 = 0 ; // RAZ compteur timer TIFR4 = 0 ; //Clear Flags timer return; } if (index_output_dmx==IOUTDMX_MAB ) { // en cours de mab //TXLED1; txledcpt=RX_TX_LED_TIME; sbi(UCSR1B, TXEN1); // on reactive la transmission USART index_output_dmx=0; // on se prépare à émmettre à partir du stat code ( 513 octets ) sbi(UCSR1B, UDRIE1); // on réactive l'intéruption du registre // Arret du timer TIMSK4= 0 ; //desactivation intéruption TCCR4B = 0; // arret du timer TIFR4 = 0 ; //Clear Flags timer } } // ********************************** INIT ********************************* // void setup() { // Le startcode n'est jamais recu. On l'initialise ici tab_input_pc[0]=0; // init pin led interne en sortie pinMode(LEDPIN, OUTPUT); // init USART // baudrate à 250k UCSR1A = 1 << U2X1; UBRR1H=0; UBRR1L = 7; // 2 bit de stop; pas de parité; 8 bits de données UCSR1C = 14; // activation reception et intéruptions serial 1 sbi(UCSR1B, RXEN1); //Reception cbi(UCSR1B, TXEN1); //Pas de transmission avant 1er Break sbi(UCSR1B, RXCIE1); //Interruption sur reception sbi(UCSR1B, TXCIE1); //Interruption pour fin de transmission // init timer 4 (break) TIMSK4 = 0; TCCR4C = 0; TCCR4B = 0; TCCR4A = 0; // 00000000 TCNT4 = 0; // compteur TC4H=0; sei(); // préparation du premier break index_output_dmx=IOUTDMX_IDLE; } // ********************************** BOUCLE ********************************* // int tmptime; void loop() { if(index_output_dmx==IOUTDMX_WAIT && interbrk >255) index_output_dmx=IOUTDMX_IDLE; // Lancement du Break : après fin de transmisson et ecoulement de "dmx_frame_interval" ms depuis le dernier break if (index_output_dmx==IOUTDMX_IDLE && interbrk >= dmx_frame_interval ) { index_output_dmx=IOUTDMX_BRK; tab_input_dmx[514]= (byte)tmptime ; tmptime= interbrk=0; pinMode(TX1PIN, OUTPUT); // on met la broche en mode sortie cbi(UCSR1B, TXEN1); //on stop la transmission digitalWrite(TX1PIN, LOW); // on met la broche à 0 OCR4A = brk_timer_end ; // val 120 µs TCNT4 = 0 ; // RAZ compteur timer TIFR4 = 0 ; //Clear Flags timer TIMSK4 = 64 ; //activation intéruption A &B TCCR4B = 6; // 00000110 division par 32 de l'horloge base => 2µs } // octets d'état. Pour le moment, tous à 0 //tab_input_dmx[513]= 0; //tab_input_dmx[514]= 0; //tab_input_dmx[515]= 0; //tab_input_dmx[516]= 0; if(_usbLineInfo.lineState) { // Si port serie USB ouvert blinkp=100, blinkon=70; // la led clignote plus vite if(!syncflag && emissionPc!=0) { ecritUSB(); } } else { blinkon = 3500, blinkp=4000; // dans le doute, on force l'etat d'entree etat_input_pc=IINUSB_IDLE; } int m = millis(); if (m-blkl) { // Toutes les ms interbrk+=(m-blkl) ; tmptime+=(m-blkl); blkcpt++; blkl = m; if(rxledcpt) rxledcpt--; else RXLED0; if(txledcpt) txledcpt--; else TXLED0; if(blkcpt>=blinkon) { digitalWrite(LEDPIN, HIGH); } if(blkcpt>=blinkp){ digitalWrite(LEDPIN, LOW); blkcpt=0; } } }