Go Down

Topic: Compte tour avec liaison I2C entre Attiny85 et Uno (Read 380 times) previous topic - next topic

pierrotm777

Mar 21, 2020, 12:52 pm Last Edit: Apr 11, 2020, 04:44 pm by pierrotm777
Bonjour,

J'essaie de réaliser un compte tour .
Un attiny85 utilise un capteur IR GP2Y0D810Z0F et envoie le résultat à l'Uno via le port I2C.

Ca semble fonctionner mais le résultat sur le port série de l'Uno semble bizarre.

Voici donc le code de L'attiny85 en configuration esclave:
Code: [Select]


#include "TinyWireS.h"      // ATTiny wire lib
#include "PinChangeInterrupt.h"
           
#define I2C_SLAVE_ADDR  0x26           
#define Sensor_PIN  1
#define Led_PIN     4
boolean firstbyte = true;

volatile byte rpmcount;
unsigned int rpm;
unsigned long timeold;

void setup() {
  pinMode(Sensor_PIN,INPUT);
  TinyWireS.begin(I2C_SLAVE_ADDR);
  TinyWireS.onRequest(requestEvent);
  attachPCINT(Sensor_PIN, rpm_fall, FALLING);
  rpmcount = 0;
  rpm = 0;
  timeold = 0;
}

void rpm_fall()
{
  rpmcount++;  //Each rotation, this interrupt function is run twice
}

void loop()
{
  if (rpmcount >= 250)
  {
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update
    rpm = 30*1000/(millis() - timeold)*rpmcount/75;
    timeold = millis();
    rpmcount = 0;
  } 
  if (digitalRead(Sensor_PIN) == LOW)
  {
    digitalWrite(Led_PIN,HIGH);
  }
  else
  {
    digitalWrite(Led_PIN,LOW);
  }
}


void requestEvent()
{

  byte plow;
  byte phi;
 
  if(firstbyte == true)
  {     // on the first byte we do the math
   plow=lowByte(rpm);
   firstbyte = false;      //so next time though we send the next byte   
   TinyWireS.send(plow);
  }
  else
  {
   phi=highByte(rpm);
   TinyWireS.send(phi);
   firstbyte = true;
  }
}


et le code de l'Uno en configuration maître:
Code: [Select]
#include "Wire.h";
int ATtinyAddress=0x26;
unsigned long marktime;

void setup()
{
 Wire.begin();
 Serial.begin(9600);
}


void loop(){
 if (millis()>marktime)
 {
   byte hb;
   byte lb;
   Wire.requestFrom(ATtinyAddress,2);
   if (Wire.available())
   {
     lb=Wire.read();
     hb=Wire.read();
   }
   int rpm=word(hb,lb);
   Serial.println (rpm);
   marktime+=1000;
 }
}


Pourriez me dire quel est mon erreur svp .

Merci de votre aide par avance.

Pierre

Jambe

Sans nous donner le résultat du moniteur série, pas évident de donner une réponse

pierrotm777

Bonjour,

Je n'avais pas vu votre réponse, désolé.
Le résultat de la console donne ça.


Code: [Select]
36
36
36
36
36
33
33
33
33
33
33
33
30
30
30
30
30
30
30
26
26
26
26
26
26
30
30
30
30
30
30
30
30
30
30


Mon ventilo de PC tourne au moins à 1000 tr/mn je pense donc , ya un bug.

kamill

#3
Mar 31, 2020, 08:48 pm Last Edit: Mar 31, 2020, 08:49 pm by kamill
Bonjour,

Ça correspond à quoi le /75 dans la formule?
Code: [Select]
   rpm = 30 * 1000 / (millis() - timeold) * rpmcount / 75;
Je pense que la vitesse en rpm devrait être
Code: [Select]
   rpm = 30 * 1000 / (millis() - timeold) * rpmcount ;

pierrotm777


Bonjour,

Ça correspond à quoi le /75 dans la formule?
Code: [Select]
   rpm = 30 * 1000 / (millis() - timeold) * rpmcount / 75;
Je pense que la vitesse en rpm devrait être
Code: [Select]
   rpm = 30 * 1000 / (millis() - timeold) * rpmcount ;
Désolé pour le délais.
Je ne reçois pas d'alerte. C'est bizarre.

Je pense que oui.

kamill

Ça donne un résultat correct sans le /75 ?

pierrotm777

Ça donne un résultat correct sans le /75 ?
J'ai été interrompu par des courses :-)
Je regarde ça dès que possible et vous rend compte !

pierrotm777

Alors, j'ai essayé dans un premier temps de commenter le code du compte tour pour n'envoyer que rpm = 10000 via l'I2C.
Pour l'attiny85 j'ai simplifié ainsi:
Code: [Select]
/*


                  +-\/-+
             NC  1|    |8  VCC (2.7-5.5V)
             NC  2|    |7  I2C   SCK -> Uno A5
            LED  3|    |6  (PB1) SENSOR
            GND  4|    |5  I2C   SDA -> Uno A4
                  +----+
*/

#include "TinyWireS.h"      // ATTiny wire lib
#include "PinChangeInterrupt.h"
           
#define I2C_SLAVE_ADDR  0x26           
#define Sensor_PIN  1
#define Led_PIN     4
boolean firstbyte = true;

volatile byte rpmcount;
volatile unsigned int rpm;
unsigned long timeold;

#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif
volatile uint8_t i2c_regs[] =
{
    0, //older 8
    0 //younger 8
};
volatile byte reg_position = 0;
const byte reg_size = sizeof(i2c_regs);


void setup() {
//  pinMode(Sensor_PIN,INPUT);
  TinyWireS.begin(I2C_SLAVE_ADDR);
  TinyWireS.onRequest(requestEvent);
//  attachPCINT(Sensor_PIN, rpm_fall, FALLING);
//  rpmcount = 0;
//  rpm = 0;
//  timeold = 0;
}

//void rpm_fall()
//{
//  rpmcount++;  //Each rotation, this interrupt function is run twice
//}

void loop()
{
//  if (rpmcount >= 250)
//  {
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update
    rpm = 10000;//30*1000/(millis() - timeold)*rpmcount;//rpm = 30*1000/(millis() - timeold)*rpmcount/75;
    i2c_regs[0] = rpm >> 8;
    i2c_regs[1] = rpm & 0xFF;   
    //timeold = millis();
    //rpmcount = 0;

   
   
//  } 
//  if (digitalRead(Sensor_PIN) == LOW)
//  {
//    digitalWrite(Led_PIN,HIGH);
//  }
//  else
//  {
//    digitalWrite(Led_PIN,LOW);
//  }
}


void requestEvent()

  TinyWireS.send(i2c_regs[reg_position]);

  reg_position++;
  if (reg_position >= reg_size)
  {
      reg_position = 0;
  }
}


Pour le Uno:
Code: [Select]
#include "Wire.h";
int ATtinyAddress=0x26;
unsigned long marktime;

void setup()
{
 Wire.begin();
 Serial.begin(9600);
}


void loop(){
 if (millis()>marktime)
 {
   byte hb;
   byte lb;
   Wire.requestFrom(ATtinyAddress,2);
   if (Wire.available())
   {
     lb=Wire.read();
     hb=Wire.read();
   }
   //int rpm=word(hb,lb);
   int rpm = (lb << 8) | hb;
   //int rpm = ((lb * 16 + hb) / 16) / 4;
   Serial.println (rpm);
   marktime+=1000;
 }
}


Le Uno me retourne 0:
Code: [Select]
0
0
0
0
0

kamill

Ca doit fonctionner.
A part le fait que tu te mélanges les pinceaux entre low byte et high byte. Tu transmets le high byte en premier et quand tu reçois le low byte en premier.
Comme il y a inversion aussi dans le calcul 'int rpm = (lb << 8) | hb' ça compense la première erreur.

pierrotm777

Si je comprend bien dans l'attiny, je devrais écrire:
Code: [Select]
    i2c_regs[1] = rpm >> 8;
    i2c_regs[0] = rpm & 0xFF;


Et dans le Uno:

Code: [Select]
   if (Wire.available())
   {
     hb=Wire.read();
     lb=Wire.read();
   }
   //int rpm=word(hb,lb);
   int rpm = (lb << 8) | hb;


C'est ça ?

kamill

Oui pour l'envoi, mais autant les mettre dans l'ordre
Code: [Select]
   i2c_regs[0] = rpm & 0xFF;  // poids faible
   i2c_regs[1] = rpm >> 8;    // poids fort


Pour la réception
Code: [Select]
  if (Wire.available())
  {
    lb=Wire.read();  // poids faible
    hb=Wire.read();  // poids fort
  }
  int rpm=word(hb,lb);


Je ne sais pas pourquoi tu as créé la variable i2c_regs qui ne sert à rien. Ca fonctionnait très bien comme c'était dans ton premier programme.

pierrotm777

#11
Apr 11, 2020, 09:13 pm Last Edit: Apr 11, 2020, 09:13 pm by pierrotm777
Oui pour l'envoi, mais autant les mettre dans l'ordre
Code: [Select]
   i2c_regs[0] = rpm & 0xFF;  // poids faible
   i2c_regs[1] = rpm >> 8;    // poids fort


Pour la réception
Code: [Select]
  if (Wire.available())
  {
    lb=Wire.read();  // poids faible
    hb=Wire.read();  // poids fort
  }
  int rpm=word(hb,lb);


Je ne sais pas pourquoi tu as créé la variable i2c_regs qui ne sert à rien. Ca fonctionnait très bien comme c'était dans ton premier programme.

Cool ça fonctionne :-)

Je reçois bien:
Code: [Select]
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000
10000

Je vais rajouter le compteur de tour

Merci pour le coup de main :-)

pierrotm777


kamill



Go Up