// Version corrigée 2019.05.15 #include #include #include "clock.h" // Base Robot RSLK : PWM et détecteurs de piste //============================================= // Pierre-Yves Rochat, 2018, EPFL, pyr@pyr.ch // LED du Launchpad MSP432 : #define LedRougeInit P1DIR|=(1<<0);P1OUT&=~(1<<0) #define LedRougeOn P1OUT|=(1<<0) #define LedRougeOff P1OUT&=~(1<<0) #define LedRougeToggle P1OUT^=(1<<0) #define LedCoulInit P2DIR|=(1<<0)|(1<<1)|(1<<2);P2OUT&=~((1<<0)|(1<<1)|(1<<2)) #define LedCoulRougeOn P2OUT|=(1<<0) #define LedCoulRougeOff P2OUT&=~(1<<0) #define LedCoulRougeToggle P2OUT^=(1<<0) #define LedCoulVertOn P2OUT|=(1<<1) #define LedCoulVertOff P2OUT&=~(1<<1) #define LedCoulVertToggle P2OUT^=(1<<1) #define LedCoulBleuOn P2OUT|=(1<<2) #define LedCoulBleuOff P2OUT&=~(1<<2) #define LedCoulBleuToggle P2OUT^=(1<<2) // Moteurs du robot : #define MoteurDroiteInit P6DIR|=(1<<4);P6OUT&=~(1<<4);P6DIR|=(1<<5);P6OUT&=~(1<5) #define MoteurDroiteOn P6OUT|=(1<<4) #define MoteurDroiteOff P6OUT&=~(1<<4) #define MoteurDroiteRecule P6OUT|=(1<<5) #define MoteurDroiteAvance P6OUT&=~(1<<5) #define MoteurGaucheInit P4DIR|=(1<<6);P4OUT&=~(1<<6);P1DIR|=(1<<5);P1OUT&=~(1<<5) #define MoteurGaucheOn P4OUT|=(1<<6) #define MoteurGaucheOff P4OUT&=~(1<<6) #define MoteurGaucheRecule P1OUT|=(1<<5) #define MoteurGaucheAvance P1OUT&=~(1<<5) #define DetIrOn P3DIR|=(1<<7);P3OUT|=(1<<7) // Variables globales : volatile uint16_t PwmLedRouge; // géré par TA0 CCR1 volatile uint16_t PwmCoulRouge; // géré par TA0 CCR2 volatile uint16_t PwmCoulVert; // géré par TA0 CCR3 volatile uint16_t PwmCoulBleu; // géré par TA0 CCR4 volatile int16_t CommandeDroite; // géré par TA1 CCR1 volatile int16_t CommandeGauche; // géré par TA1 CCR2 volatile int16_t ValDetecteurs[8]; int16_t LimiteDetecteurs[] = {12000, 10000, 10000, 10000, 10000, 10000, 10000, 12000}; int8_t BitDetecteurs[8]; volatile uint8_t FinCycle; #define PeriodeCycle 50000 #define LimiteMoteur 100 #define LimiteLed 100 // Communication avec l'afficheur : uint16_t idxDet; void InitSerie() { // initialise la ligne série P3SEL0 |= BIT2 | BIT3; // UART2 pin en fonction secondaire P3.2 et P3.3 UCA2CTLW0 |= UCSWRST; // Reset de l'automate de la liaison série UCA2CTLW0 |= UCSSEL__SMCLK; // sélection de l'horloge UCA2BR0 = (uint8_t)((uint32_t)48000000/(16*4*9600))%256; // choisit le baud-rate UCA2BR1 = (uint8_t)((uint32_t)48000000/(16*4*9600))/256; UCA2MCTLW = 0x1000 | UCOS16 | 0x0020; UCA2CTLW0 &= ~UCSWRST; // Initialise l'automate de la liaison série idxDet = 0; } char car; void AfficheDetecteurs() { // envoie successivement les valeurs des détecteurs if (UCA2IFG & UCTXIFG) { // prêt à l'envoi UCA2TXBUF = ((((7-idxDet) & 0b1111)+8)<<4) | (ValDetecteurs[idxDet]>>11); idxDet++; if (idxDet>=8) idxDet = 0; } } int32_t Centre; void CalculeCentre() { Centre = 0; Centre += ValDetecteurs[0]*7; Centre += ValDetecteurs[1]*5; Centre += ValDetecteurs[2]*3; Centre += ValDetecteurs[3]*1; Centre -= ValDetecteurs[4]*1; Centre -= ValDetecteurs[5]*3; Centre -= ValDetecteurs[6]*5; Centre -= ValDetecteurs[7]*7; } void AfficheCentre() { PwmLedRouge = 0; PwmCoulBleu = 0; if (Centre < 0) { PwmLedRouge = -Centre/(1+3+5+7); } if (Centre > 0) { PwmCoulBleu = Centre/(1+3+5+7); } } uint8_t Poussoir() { if (UCA2IFG & UCRXIFG) { car = UCA2RXBUF; if (car=='P') return 1; } return 0; } #define FACTEUR_P 50 // Programme principal : //====================== void main() { WDTCTL = WDTPW | WDTHOLD; Clock_Init48MHz(); P3SEL0 = 0; P3SEL1 = 0; LedRougeInit; LedCoulInit; PwmLedRouge; PwmCoulRouge = PwmCoulVert = PwmCoulBleu = 0; MoteurGaucheInit; MoteurDroiteInit; CommandeDroite = CommandeGauche = 0; InitSerie(); FinCycle = 0; DetIrOn; // allume l'IR des détecteurs // Initialisation des timers : NVIC->ISER[0] = 1 << ((TA0_0_IRQn) & 31); TA0CTL = TASSEL_2 | MC_2 | ID_1 ; // SMCLK, mode continu, DIV 2 TA0CCTL0 = CCIE; // interruption TA0CCR0 TA0CCR0 = PeriodeCycle; // période du PWM et des mesures NVIC->ISER[0] = 1 << ((TA0_N_IRQn) & 31); TA0CCTL1 = CCIE; // interruption TA0 CCR1 TA0CCR1 = 0; TA0CCTL2 = CCIE; TA0CCR2 = 0; TA0CCTL3 = CCIE; TA0CCR3 = 0; TA0CCTL4 = CCIE; TA0CCR4 = 0; NVIC->ISER[0] = 1 << ((TA1_0_IRQn) & 31); TA1CTL = TASSEL_2 | MC_2 | ID_1 ; TA1CCTL0 = CCIE; TA1CCR0 = PeriodeCycle; NVIC->ISER[0] = 1 << ((TA1_N_IRQn) & 31); TA1CCTL1 = CCIE; TA1CCR1 = 0; TA1CCTL2 = CCIE; TA1CCR2 = 0; // Initialisation des ports : NVIC->ISER[1] = 1 << ((PORT2_IRQn) & 31); P2IES |= (1<<3); P2IE |= (1<<3); P2IFG &=~(1<<3); // Détecteur 2 sur P2.3 P2IES |= (1<<4); P2IE |= (1<<4); P2IFG &=~(1<<4); // Détecteur 6 sur P2.4 P2IES |= (1<<6); P2IE |= (1<<6); P2IFG &=~(1<<6); // Détecteur 7 sur P2.7 NVIC->ISER[1] = 1 << ((PORT3_IRQn) & 31); P3IES |= (1<<5); P3IE |= (1<<5); P3IFG &=~(61<<5); // Détecteur 0 sur P3.5 NVIC->ISER[1] = 1 << ((PORT5_IRQn) & 31); P5IES |= (1<<1); P5IE |= (1<<1); P5IFG &=~(1<<1); // Détecteur 1 sur P5.1 P5IES |= (1<<6); P5IE |= (1<<6); P5IFG &=~(1<<6); // Détecteur 5 sur P5.6 NVIC->ISER[1] = 1 << ((PORT6_IRQn) & 31); P6IES |= (1<<6); P6IE |= (1<<6); P6IFG &=~(1<<6); // Détecteur 4 sur P6.6 P6IES |= (1<<7); P6IE |= (1<<7); P6IFG &=~(1<<7); // Détecteur 3 sur P6.7 __enable_interrupt(); while(1) { // boucle principale : calcul des PWM pour le cycle suivant uint8_t i; if (FinCycle) { for (i=0; i<8; i++) { if ((uint16_t)ValDetecteurs[i]> LimiteDetecteurs[i]) BitDetecteurs[i]=1; else BitDetecteurs[i]=0; } AfficheDetecteurs(); CalculeCentre(); AfficheCentre(); CommandeDroite = 10000; CommandeGauche = 20000; FinCycle = 0; } } } // Routines d'interruptions : //=========================== void PORT2_IRQHandler() { if (P2IFG & (1<<3)) { P2IFG &=~(1<<3); ValDetecteurs[2] = TA0R/2; } if (P2IFG & (1<<4)) { P2IFG &=~(1<<4); ValDetecteurs[6] = TA0R/2; } if (P2IFG & (1<<6)) { P2IFG &=~(1<<6); ValDetecteurs[7] = TA0R/2; } } void PORT3_IRQHandler() { if (P3IFG & (1<<5)) { P3IFG &=~(1<<5); ValDetecteurs[0] = TA0R/2; } } void PORT5_IRQHandler() { if (P5IFG & (1<<1)) { P5IFG &=~(1<<1); ValDetecteurs[1] = TA0R/2; } if (P5IFG & (1<<6)) { P5IFG &=~(1<<6); ValDetecteurs[5] = TA0R/2; } } void PORT6_IRQHandler() { if (P6IFG & (1<<6)) { P6IFG &=~(1<<6); ValDetecteurs[4] = TA0R/2; } if (P6IFG & (1<<7)) { P6IFG &=~(1<<7); ValDetecteurs[3] = TA0R/2; } } // Timer A0 : PWM des LED et début des cycles des capteurs void TA0_0_IRQHandler(void){ // TA0 CCR0 : fin (et début) des cycles volatile uint8_t i; P3DIR |= (1<<5); P3OUT |= (1<<5); // charge le condensateur P5DIR |= (1<<1); P5OUT |= (1<<1); P2DIR |= (1<<3); P2OUT |= (1<<3); P6DIR |= (1<<7); P6OUT |= (1<<7); P6DIR |= (1<<6); P6OUT |= (1<<6); P5DIR |= (1<<6); P5OUT |= (1<<6); P2DIR |= (1<<4); P2OUT |= (1<<4); P2DIR |= (1<<6); P2OUT |= (1<<6); TA0CCTL0 &=~ CCIFG; TA0R = 0; // début du cycle suivant if (PwmLedRouge>LimiteLed) LedRougeOn; // CCR1 if (PwmCoulRouge>LimiteLed) LedCoulRougeOn; //CCR2 if (PwmCoulVert>LimiteLed) LedCoulVertOn; //CCR3 if (PwmCoulBleu>LimiteLed) LedCoulBleuOn; // CCR4 TA0CCR1 = PwmLedRouge; TA0CCR2 = PwmCoulRouge; TA0CCR3 = PwmCoulVert; TA0CCR4 = PwmCoulBleu; FinCycle = 1; for (i=0; i<20; i++){} // charge des condensateurs P3DIR &=~(1<<5); // détecteur en entrée P5DIR &=~(1<<1); P2DIR &=~(1<<3); P6DIR &=~(1<<7); P6DIR &=~(1<<6); P5DIR &=~(1<<6); P2DIR &=~(1<<4); P2DIR &=~(1<<6); } void TA0_N_IRQHandler(void){ TA0CCTL0 &=~ CCIFG; switch (TA0IV) { case 2 : LedRougeOff; break; // TA0 CCR1 case 4 : LedCoulRougeOff; break; // TA0 CCR2 case 6 : LedCoulVertOff; break; // TA0 CCR3 case 8 : LedCoulBleuOff; break; // TA0 CCR4 default : break; } } // Timer A1 : PWM des moteurs void TA1_0_IRQHandler(void){ // TA1CCR0 : début des cycles PWM TA1CCTL0 &=~CCIFG; TA1R = 0; // début du cycle suivant MoteurDroiteOff; MoteurGaucheOff; if (CommandeDroite>LimiteMoteur) { TA1CCR1 = CommandeDroite*2; MoteurDroiteAvance; MoteurDroiteOn; } if (CommandeDroite<-LimiteMoteur) { TA1CCR1 = -CommandeDroite*2; MoteurDroiteRecule; MoteurDroiteOn; } if (CommandeGauche>LimiteMoteur) { TA1CCR2 = CommandeGauche*2; MoteurGaucheAvance; MoteurGaucheOn; } if (CommandeGauche<-LimiteMoteur) { TA1CCR2 = -CommandeGauche*2;MoteurGaucheRecule; MoteurGaucheOn; } } void TA1_N_IRQHandler(void){ TA1CCTL0 &=~CCIFG; switch (TA1IV) { case 2 : MoteurDroiteOff; break; // TA1 CCR1 case 4 : MoteurGaucheOff; break; // TA1 CCR2 default : break; } }