Simulateur de roue dentée (EDIS4 36-1) #sinusoïde

Bonjour,à tous,
débutant dans ce vaste monde de l'Arduino, j'ai besoin de vos lumières...

je voudrais sortir un signal PWM, une sinusoïde qui se répète 34 fois, puis un signal "tordu" sur deux périodes, puis ça reprend en boucle.

Le but est de simuler le signal d'un capteur inductif placé devant une roue dentée, 36 dents mois une.

Je me base sur un programme tout fait qui génère une sinusoïde à fréquence variable fonction de l'entrée A0,

Le PWM pioche dans une table de 256 points,
Je pensais modifier le code pour intégrer une boucle,

  • générer 34 fois une sinusoîde normale
  • générer la dent manquante (2 périodes)

Mais je bute sur la compréhension de ceci:

// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect) {

  sbi(PORTD,7);          // Test / set PORTD,7 high to observe timing with a oscope

  phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
  icnt=phaccu >> 24;     // use upper 8 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
  OCR2A=pgm_read_byte_near(sine9216 + icnt);    

  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

 cbi(PORTD,7);            // reset PORTD,7

La double période a cette forme:

// table of 512 "missing tooth" values on EDIS Trigger Wheel / two sine periods / stored in flash memory
PROGMEM const unsigned char dent512[] = {
 254, 254, 254, 254, 253, 253, 253, 252, 252, 251, 250, 249, 249, 248, 247, 245, 244, 243, 242, 240, 239, 238, 236, 234, 233, 231, 229, 227, 225, 223, 221, 219, 217, 215, 212, 210, 208, 205, 203, 200, 
 198, 195, 192, 190, 187, 184, 181, 178, 176, 173, 170, 167, 164, 161, 158, 155, 152, 149, 146, 143, 139, 136, 133, 130, 127, 124, 121, 118, 115, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, 78, 76, 
 73, 70, 67, 64, 62, 59, 56, 54, 51, 49, 46, 44, 42, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 
 4, 5, 5, 6, 7, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 42, 44, 46, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 
 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 89, 90, 90, 91, 92, 93, 94, 94, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 100, 101, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 103, 103, 
 104, 104, 104, 104, 105, 105, 105, 105, 106, 106, 106, 107, 107, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 114, 114, 114, 114, 115, 115, 115, 
 116, 116, 116, 116, 116, 117, 117, 117, 118, 118, 118, 119, 119, 119, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 122, 122, 122, 122, 122, 
 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 127, 127, 127, 127, 128, 128, 128, 128, 129, 129, 
 129, 129, 129, 129, 129, 130, 130, 130, 130, 131, 131, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 133, 133, 134, 134, 134, 134, 134, 135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 137, 
 138, 138, 138, 138, 139, 139, 139, 139, 140, 140, 141, 141, 141, 142, 142, 142, 143, 143, 144, 144, 145, 145, 145, 146, 146, 146, 147, 147, 148, 148, 148, 149, 149, 150, 150, 151, 151, 152, 152, 153, 
 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 178, 179, 180, 181, 182, 183, 184, 186, 188, 190, 192, 195, 198, 200, 203, 205, 
 208, 210, 212, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 234, 236, 238, 239, 240, 242, 243, 244, 245, 247, 248, 249, 249, 250, 251, 252, 252, 253, 253, 253, 254, 254, 254[/quote]

La sinusoIde celle ci:
[quote]// table of 256 sine values / one sine period / stored in flash memory
PROGMEM  const unsigned char sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

Pour les avertis ça doit sembler bête et accessible, mais je sèche...
Pourquoi se sert-il des 8 bits supérieurs de phaccu (>>24) pour icnt???

Si quelqu'un y voit clair dans ce code...
Merci par avance,
Greg.


La sortie de l'Arduino sera dotée d'un filtre passe-bas

La plage de fréquence souhaitée:
300Hz<freq<8000Hz

Source de tout ceci:
http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-dds-sinewave-generator/

La période du signal est codée sur 256 octets. Les bits de plus faibles poids sont des décimales de l'angle. Ces décimales ne sont utilisées que pour le calcul de l'angle (afin d'avoir la précision nécessaire). Ces juste une convention.

Oui, le 'hacheur' génère des créneaux 'PWM', le rapport cyclique dépend de chaque valeur de la table sin256...
Là ou bloque, c'est comment lui faire lire non pas les 256 valeurs de la table d'origine, mais 512 par exemple (deux périodes)

Je sais pas si c'est clair...

Ou luis faire lire une table de 36 périodes (34 identiques et deux patatoïdes)...

Greg.

icnt=phaccu >> 24;     
OCR2A=pgm_read_byte_near(sine9216 + icnt);

icnt permet de pointer chaque valeur dans la table sine256
icnt est tiré ou extrait des 8 bits supérieurs du long word phaccu (icnt=phaccu >> 24;

j'ai tenté de manipuler icnt=phaccu >> 24; pour avoir une plus grande plage pour icnt, en vain...

Pour avoir une période codée sur 512 pas au lieu de 256, il faut modifier le code:
il faut définir icnt comme un int au lieu d'un byte
icnt=phaccu >> 24; doir être remplacé par icnt=phaccu >> 23;
mais attention, le calcul sur un entier au lieu d'un octet va allonger la durée du traitement de l'interruption.

Si tu veux faire générer n fois une table et m fois une autre table, il faut compter le nombre de tours de l'accumulateur. Pour certaines valeurs de ce compteur il faut utiliser une table à la place de l'autre. Cela revient à changer le nom de la table dans cette ligne:
OCR2A=pgm_read_byte_near(sine9216 + icnt);

icnt est déclaré en byte,
je change en int
puis
icnt=phaccu >> 16;
ça enlève la limitation à 256?
bon, aspirine.

phaccu est un long (32 bits). Si tu fais >>16 alors icnt sera sur 16 bits et il faudra que tu gères une table de 16 bits (65536 octets).

Définir une longue table n'a de sens que si tu veux une grande précision dans la reconstruction de ton signal.

fdufnews:
OCR2A=pgm_read_byte_near(sine9216 + icnt);

oui, là c'est pas une méthode fine.... j'avoue... Grosse table de 9116 valeurs, 34 répétitions de la même sinusoïde... mais ça ne prend que 40% de l'espace et ça évitait de boucler dans le programme...

il y a sans doute plus fin!
Greg.

ha oui, donc sur 9 bits on a 512, ce qui permet de lire 17 fois une double sinus et une fois le signal patatoïde qui dure deux périodes...

Bon, je ne peux pas visualiser pour le moment, ça compile, mais je n'ai pas de quoi réaliser le filtre passe-bas à la maison...

/*
 * DDS Sine Generator mit ATMEGS 168
 * Timer2 generates the  31250 KHz Clock Interrupt
 *
 * KHM 2009 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne

 */

#include "avr/pgmspace.h"

// table of 512 double sine values / 17x double sine period  / stored in flash memory
PROGMEM  const unsigned char sinus512[]  = {
254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,
176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,
23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,
81,84,87,90,93,96,99,102,105,108,111,115,118,121,124,127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,
223,225,227,229,231,233,234,236,238,239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,
240,239,238,236,234,233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,
118,115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,
3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124,127,130,133,136,139,143,146,
149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,242,243,244,245,247,248,249,249,250,
251,252,252,253,253,253,254,254,254
};

// table of 512 dent manquante values / 1x cette double period / stored in flash memory
PROGMEM  const unsigned char patate512[]  = {
254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,
176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,
23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,35,37,39,42,44,46,49,51,53,55,57,59,61,63,65,67,69,71,
72,73,74,75,76,77,78,79,80,81,82,83,84,85,85,86,86,87,87,88,88,89,89,89,90,90,91,92,93,94,94,94,94,95,95,96,96,97,97,98,98,99,99,100,100,100,101,101,101,101,102,102,102,102,103,103,103,103,
103,104,104,104,104,105,105,105,105,106,106,106,107,107,108,108,108,109,109,109,109,110,110,110,111,111,111,112,112,112,112,113,113,113,114,114,114,114,115,115,115,116,116,116,116,116,117,117,
117,118,118,118,119,119,119,120,120,120,120,120,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,122,122,122,122,122,122,122,122,122,122,122,123,123,123,123,123,123,123,124,124,
124,124,124,124,124,125,125,125,125,125,126,126,126,126,126,127,127,127,127,128,128,128,128,129,129,129,129,129,129,129,130,130,130,130,131,131,131,131,131,131,132,132,132,132,133,133,133,133,
133,134,134,134,134,134,135,135,135,136,136,136,136,137,137,137,137,138,138,138,138,139,139,139,139,140,140,141,141,141,142,142,142,143,143,144,144,145,145,145,146,146,146,147,147,148,148,148,
149,149,150,150,151,151,152,152,153,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,178,179,180,181,182,183,184,186,188,190,192,195,198,200,203,
205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254
};

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

int ledPin = 13;                 // LED pin 7
int testPin = 7;
int t2Pin = 6;
byte bb;

double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk=31376.6;      // measured

// variables used inside interrupt service declared as voilatile
volatile int icnt;              // var inside interrupt
volatile int dcnt;              // var nb lecture table sinus512
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter incremented all 4ms
volatile unsigned long phaccu;   // phase accumulator
volatile unsigned long tword_m;  // dds tuning word m

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");

  pinMode(6, OUTPUT);      // sets the digital pin as output
  pinMode(7, OUTPUT);      // sets the digital pin as output
  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output

  Setup_timer2();

  // disable interrupts to avoid timing distortion
  cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

  dfreq=1000.0;                    // initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 
  dcnt = 0; 
}
void loop()
{
  while(1) {
     if (c4ms > 250) {                 // timer / chaque demie seconde vient lire A0
      c4ms=0;
      dfreq=analogRead(0);             // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz

      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word  http://www.analog.com/library/analogdialogue/archives/38-08/dds.html
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt 

      /*Serial.print("dfreq= ");
      Serial.print(dfreq);
      Serial.print("tword_m= ");
      Serial.println(tword_m);
      Serial.print("icnt= ");
      Serial.println(icnt);
      Serial.print("isnt1= ");
      Serial.println(icnt1);
      Serial.print("phaccu= ");
      Serial.println(phaccu);
      //Serial.print("         ");*/
    }

   sbi(PORTD,6); // Test / set PORTD,6 high to observe timing with a scope
   cbi(PORTD,6); // Test /reset PORTD,6 high to observe timing with a scope
  }
 }
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2() {

// Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

// Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);

  sbi (TCCR2A, WGM20);  // Mode 1  / Phase Correct PWM
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}

//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)  ou M=binary tuning word 
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect) {    //http://www.locoduino.org/spip.php?article88 qui explique l'interruption du timer2, ici toutes les 32µS cette boucle intervient

  sbi(PORTD,7);          // Test / set PORTD,7 high to observe timing with a oscope

  phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
  icnt=phaccu >> 23;     // use upper 9 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
  if(dcnt>=17){ 
        OCR2A=pgm_read_byte_near(sinus512 + icnt);    
              }
  else 
              {
        OCR2A=pgm_read_byte_near(patate512 + icnt);
        dcnt = 0;
              } 
  
  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

 cbi(PORTD,7);            // reset PORTD,7
     
    }

J'ai ajouté dcnt en compteur et un test if

Oui mais tu n'incrémentes jamais dcnt.
Tu le mets à zéro à 2 endroits.
Je crois que ton if sur dcnt est à l'envers.

j'ai honte.............

 if(dcnt<=17){ 
        OCR2A=pgm_read_byte_near(sinus512 + icnt);    
        dcnt = dcnt+1;
        }
  else 
              {
        OCR2A=pgm_read_byte_near(patate512 + icnt);
        dcnt = 0;
              } 
  
  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }

C'est pour simuler un capteur PMH ?

Oui.

hello
notre ami super-Cinci a planché sur un tel simulateur.

Nice,
http://forum.arduino.cc/index.php?topic=355684.0
j'ai posté.
Merci,
Greg.

Salut

Je serais intéressé par la façon dont tu fais l'acquisition du signal PMH (j'imagine que c'est la suite ??) ..

Bon courage :wink: !

Salut,
l'acquisition c'est un module EDIS4 qui le fera...

EDIS4VW


Greg.

Ah ok cool !

BrUnO14200:
Salut

Je serais intéressé par la façon dont tu fais l'acquisition du signal PMH (j'imagine que c'est la suite ??) ..

Bon courage :wink: !

Par contre ici il a les détails de l'entrée de son AEI, donc comment traiter le signal du capteur (analogique) avant de s'en servir pour l'ECU.

Dans tout ça, j'ai donc découvert que mon signal passe bien par un intégrateur genre RC, donc son amplitude diminue avec la fréquence, donc à un moment, bah... il est trop faible pour se faire détecter. Il faut donc que le signal d'entrée compense le mauvais effet de l'intégrateur en augmentant son amplitude avec la fréquence... Ce que fait naturellement le capteur d'origine.

Greg.