Projet - Faire Fonctionner un encoder de Moteur triphasé

Bonjour,

Je suis actuellement en stage, pour ma 3ème année d'Ecole d'ingénieurs, en Espagne.
Je m'excuse d'avance pour le long post mais j'aurais voulu trouver les réponses par moi même du coup j'ai accumulé les question :frowning:

Je dois faire améliorer une carte déjà existante pour contrôler un Moteur triphasé, je dois donc générer 7 signaux PWM, ce qui est fait mais a son importance. Je dois aussi compter le nombre de tours que fais l'encoder du Moteur, qui va a 67.5KHz.

N'étant encore qu'en phase de test, je dois moi même générer le signal en quadrature, ce que j'ai réussi, mais je n'arrive pas à comprendre suffisamment les code pour changer les pins de sortie.

Je dois également lire le sens et la vitesse de l'encoder.

Voila donc pour résumé :

  • Comment changer les pins dans le code ci dessous ?
  • Comment marche les registres du code ?
  • Est ce que l'Arduino DUE est capable de faire fonctionner 6 PWM en même temps avec sa fonction d'interruption : PWM_Handler(); et lire un Encoder à 67.5Khz sans qu'il y ai de pertes?

Code pour l'émulateur du signal en Quadrature :

// Emulador de un encoder incremental
//   - señal A: pines 6 y 7
//   - señal B: pines 8 y 9
//   - señal index: 34 y 35
//   basado en: http://forum.arduino.cc/index.php?topic=161192.0;wap2

#define MAX_FREQ  100000
#define RESOLUCION  2000
#define DUTY_100     255
float freq;
int cont;

void pwmWrite(uint32_t ulFreq) {
  int duty_100 = DUTY_100;
  int duty_75 = (((duty_100+1)/4)*3)-1;
  int duty_50 = ((duty_100+1)/2)-1;
  int duty_25 = ((duty_100+1)/4)-1; 
 
  pmc_enable_periph_clk(ID_PWM);
  PWMC_ConfigureClocks(ulFreq * duty_100, 0, VARIANT_MCK );  // (frec cont A, frec cont B, master clock)

  // Canales PWM que vamos a usar:
  uint32_t chan6 = g_APinDescription[6].ulPWMChannel;
  uint32_t chan7 = g_APinDescription[7].ulPWMChannel;
  uint32_t chan8 = g_APinDescription[8].ulPWMChannel;
  uint32_t chan9 = g_APinDescription[9].ulPWMChannel;
  
  // usaremos los pines 6, 7, 8 y 9
  PIO_Configure(g_APinDescription[6].pPort, g_APinDescription[6].ulPinType, g_APinDescription[6].ulPin, g_APinDescription[6].ulPinConfiguration);
  PIO_Configure(g_APinDescription[7].pPort, g_APinDescription[7].ulPinType, g_APinDescription[7].ulPin, g_APinDescription[7].ulPinConfiguration);
  PIO_Configure(g_APinDescription[8].pPort, g_APinDescription[8].ulPinType, g_APinDescription[8].ulPin, g_APinDescription[8].ulPinConfiguration); 
  PIO_Configure(g_APinDescription[9].pPort, g_APinDescription[9].ulPinType, g_APinDescription[9].ulPin, g_APinDescription[9].ulPinConfiguration);
  PIO_Configure(PIOC,PIO_PERIPH_B,PIO_PC2B_PWML0,PIO_DEFAULT); // pin PC2 (dig34 en arduino) en configuración B -> PWML0
  PIO_Configure(PIOC,PIO_PERIPH_B,PIO_PC3B_PWMH0,PIO_DEFAULT); // pin PC3 (dig35 en arduino) en configuración B -> PWMH0
  
  // CONFIGURE CHANNELS
  PWMC_ConfigureChannel(PWM, chan6, PWM_CMR_CPRE_CLKA, 0, 0);
  PWMC_ConfigureChannel(PWM, chan7, PWM_CMR_CPRE_CLKA, 0, PWM_CMR_CPOL);
  PWMC_ConfigureChannel(PWM, chan8, PWM_CMR_CPRE_CLKA, 0, 0);           
  PWMC_ConfigureChannel(PWM, chan9, PWM_CMR_CPRE_CLKA, 0, PWM_CMR_CPOL);          
  // SET PERIODS
  PWMC_SetPeriod(PWM, chan6, duty_100);
  PWMC_SetPeriod(PWM, chan7, duty_100);
  PWMC_SetPeriod(PWM, chan8, duty_100);
  PWMC_SetPeriod(PWM, chan9, duty_100); 
  // SET DUTY CYCLES
  PWMC_SetDutyCycle(PWM, chan6, duty_50);   
  PWMC_SetDutyCycle(PWM, chan7, duty_50); 
  PWMC_SetDutyCycle(PWM, chan8, duty_75);   
  PWMC_SetDutyCycle(PWM, chan9, duty_75);  
  //SET DEAD TIME
  PWM->PWM_CH_NUM[chan8].PWM_CMR |= PWM_CMR_DTE;  // added, enable channel dead time DTE=1
  PWM->PWM_CH_NUM[chan9].PWM_CMR |= PWM_CMR_DTE;
  PWMC_SetDeadTime(PWM, chan8, 0, duty_25);
  PWMC_SetDeadTime(PWM, chan9, 0, duty_25);
  
  //SYNC CHANNELS
  PWMC_ConfigureSyncChannel(PWM, ( PWM_SCM_SYNC4 |  PWM_SCM_SYNC5 | PWM_SCM_SYNC6 | PWM_SCM_SYNC7), PWM_SCM_UPDM_MODE0, 0, 0);   
  PWMC_SetSyncChannelUpdateUnlock(PWM);              // PWM_SCUC set UPDULOCK to 1, update next period
  PWMC_SetSyncChannelUpdatePeriod(PWM, duty_100);    //  update period of the synchronous channels PWM_SCUP  
  
  // SET CHANNEL 0 FOR SYNC
  PWMC_ConfigureChannel(PWM, 0, PWM_CMR_CPRE_CLKA, 0, 0);
  PWMC_SetPeriod(PWM, 0, duty_100);
  PWMC_SetDutyCycle(PWM, 0, duty_50);
  
     // SET PWM INTERRUPTION
   NVIC_EnableIRQ(PWM_IRQn);
   PWM->PWM_IER1=1; // es lo mismo que PWMC_EnableChannelIt(PWM,0); // lanzamos int al final del periodo del canal 0
   
   PWMC_SetDutyCycle(PWM, 6, duty_50);
   PWMC_EnableChannel(PWM, 0);
   return;
}

void PWM_Handler(){
  uint32_t ref=PWM->PWM_ISR1;  // desactivamos int, si ha sido lanzada por IER1 (por ejemplo, al final del periodo)
  
  cont++;
  PWMC_SetSyncChannelUpdateUnlock(PWM);              // PWM_SCUC set UPDULOCK to 1, update next period
  if(cont==RESOLUCION) {
     cont=0;
     PWMC_SetDutyCycle(PWM, 0, DUTY_100*0.5);
     digitalWrite(13,1);
  } else {
     PWMC_SetDutyCycle(PWM, 0, DUTY_100*0);
     digitalWrite(13,0);
  }  
}

void setup() {
  pinMode(13,OUTPUT);
  Serial.begin(9600);
  pwmWrite(65000);
}

void loop() {
  
  delay(500);
}

Merci et encore désolé pour un si long post.
Les commentaires sont en espagnols mais sont simples à comprendre.

Code du Programme qui génére les signaux PWM (principal)

// Ampliación de accionamientos eléctricos
//
// Práctica de programación de un control V/f en Arduino
// parte 5: Control completo, para probar en la tarjeta de pruebas
//
// -------------------------------Jesús López, abril 2015

#include "pwm3.h"
#include <LiquidCrystal.h>

#define PI   3.141592
#define VBASE          311	// Tensión base (en valor pico y fase)
#define FBASE           50	// Frecuencia base
#define PARES_POLOS      2	// pares de polos
#define FREC_MUESTREO 2000.     // periodo de muestreo
#define FS_RPM        2000.     // Fondo de escala de la referencia (velocidad maxima, rpm)
#define FS_VBUS        670.     // Fondo de escala de la tensión de bus
#define FS_CORRIENTE  13.5      // Fondo de escala de la corriente
#define MAX_CORRIENTE   11      // Máxima corriente permitida
#define REOSTATO_ON    640
#define REOSTATO_OFF   630
#define MAX_VBUS       660      // Máxima Tensión bus
#define MAX_PEND_REF    1000.    // maxima pendiente permitida para cambiar la referencia (en rpm/seg)
#define MAX_PEND_REF_  (MAX_PEND_REF/FREC_MUESTREO)  // mismo en rpm/periodo muestreo

// pines
#define PIN_ARRANQUE     51
#define PIN_PARO  53
#define PIN_CAMBIOGIRO  12
#define PIN_DISIPACION  40
#define PIN_LED_MARCHA  19
#define PIN_LED_SOBREI  17
#define PIN_LED_SOBREV  15
#define PIN_LED_DISIPA  14

LiquidCrystal lcd(11, 10, 9, 5, 4, 3, 2);
float ref, Vbus, Ia, Ib, Ic;
float ref_ant, frec, amplitud, ang;
int signoRef=1, cambioGiroAntes, reostato;
float dutyA, dutyB, dutyC;
#define PARO   0
#define MARCHA 1
#define ERROR_SOBREI 2
#define ERROR_SOBREV 3
int status=PARO;


// PWM Interrupt handler.
void PWM_Handler(){
  float shit;
  shit=PWM->PWM_ISR1;  // desactivamos int, si ha sido lanzada por IER1 (por ejemplo, al final del periodo)
  shit=PWM->PWM_ISR2;  // desactivamos int, si esta ha sido lanzada por IER2 (por ejemplo, con una comparación)
  
  if(digitalRead(PIN_ARRANQUE)&&!digitalRead(PIN_PARO)) status=MARCHA;
  if(digitalRead(PIN_PARO)) status=PARO;
  
  //lecturas 
  ref=analogRead(A5)*FS_RPM/1024*signoRef;
  Vbus=analogRead(A10)*FS_VBUS/1024;
  Ia=analogRead(A9)*FS_CORRIENTE/512-FS_CORRIENTE;
  Ib=0; //analogRead(A11)*FS_CORRIENTE/512-FS_CORRIENTE;
  Ic=-Ia-Ib;
  if(status==MARCHA) {
      pwm3_start();
      
      // rampeado referencia
      if ((ref-ref_ant)>(MAX_PEND_REF_)) ref=ref_ant+MAX_PEND_REF_;
      if ((ref_ant-ref)>(MAX_PEND_REF_)) ref=ref_ant-MAX_PEND_REF_;
      ref_ant=ref;
      
      // cálculo tensiones
      frec=ref/60*PARES_POLOS;  
      amplitud=abs(frec)*VBASE/FBASE;    // amplitud de la tensión (valor pico)
      if  (amplitud>Vbus/2) amplitud=Vbus/2; 
      ang=ang+frec*2*PI/FREC_MUESTREO;
      if(ang>2*PI) ang=ang-2*PI;             
      dutyA=amplitud/Vbus*sin(ang)+0.5;
      dutyB=amplitud/Vbus*sin(ang-2*PI/3)+0.5;
      dutyC=amplitud/Vbus*sin(ang+2*PI/3)+0.5;
      pwm3_setDutyCycles(dutyA, dutyB, dutyC);
      
      // para comprobar que todo va bien
      analogWrite(DAC0,dutyA*255);
      analogWrite(DAC1,dutyB*255);
      
      // Control de la tensión del bus por histéresis
      if(Vbus>REOSTATO_ON)  reostato=1;
      if(Vbus<REOSTATO_OFF) reostato=0;
      
      // protecciones
      if(Ia>MAX_CORRIENTE || Ia<-MAX_CORRIENTE) status=ERROR_SOBREI;
      if(Ib>MAX_CORRIENTE || Ib<-MAX_CORRIENTE) status=ERROR_SOBREI;
      if(Ic>MAX_CORRIENTE || Ic<-MAX_CORRIENTE) status=ERROR_SOBREI;
      if(Vbus>MAX_VBUS) status=ERROR_SOBREV;
  }
  if (status!=MARCHA) {
      ref_ant=0;
      pwm3_stop();
      reostato=0;
  }
  // salidas: reostato + leds
  digitalWrite(PIN_DISIPACION,reostato);
  digitalWrite(PIN_LED_DISIPA,reostato);
  digitalWrite(PIN_LED_MARCHA,status==MARCHA);  
  digitalWrite(PIN_LED_SOBREI,status==ERROR_SOBREI);  
  digitalWrite(PIN_LED_SOBREV,status==ERROR_SOBREV);    
  
  // cambio de giro
  if(digitalRead(PIN_CAMBIOGIRO)==LOW) {
    if (cambioGiroAntes==0) signoRef=-signoRef;
    cambioGiroAntes=1;      // memorizo que ya le he hecho caso
  } else cambioGiroAntes=0; // ya ha dejado de pulsar el botón
}

void setup() {
  Serial.begin(9600);  // CUIDADO: parece que el puerto serie se pelea con los pines de la pantalla
  pinMode(PIN_ARRANQUE,INPUT);
  pinMode(PIN_PARO,INPUT);
  pinMode(PIN_CAMBIOGIRO,INPUT);
  pinMode(PIN_DISIPACION,OUTPUT);
  pinMode(PIN_LED_MARCHA,OUTPUT);
  pinMode(PIN_LED_SOBREI,OUTPUT);
  pinMode(PIN_LED_SOBREV,OUTPUT);
  pinMode(PIN_LED_DISIPA,OUTPUT);
  
  pwm3_setup(FREC_MUESTREO,0,0.01);  // (frecPWM, deadtime, inst_interr)  inst_interr!=0
  lcd.begin(16, 2);
}

void loop() {
  if(status==MARCHA) {
      lcd.setCursor(0,0);
      lcd.print("Ref: "); lcd.print(ref,0); lcd.print(" rpm  ");
      lcd.setCursor(0, 1);
      lcd.print("Tension bus: "); lcd.print(Vbus,0); lcd.print(" V  ");
  }
  else { // apagado
      lcd.setCursor(0,0);
      lcd.print("PARO          ");
      lcd.setCursor(0,1);
      if     (status==ERROR_SOBREI) lcd.print("ERROR sobreI    "); 
      else if(status==ERROR_SOBREV) lcd.print("ERROR sobretension ");
      else lcd.print("                ");
  }
  delay(500);
}