LØST RPM måler

Hej

Jeg forsøger at bruge nedenstående sketch til at måler omdrejninger/min.
Jeg får dog kun en masse 5 cifrede tal ud på Serial monitoren, og tallene kommer hurtigt, uanset om der har været interrupt eller ej.

Jeg bruger en magnetføler til Interrupt.

Jeg vil gerne have at at serial.print af "rpm" bliver opdateret hver gang magnetføleren "interrupter". Grunden til dette er at "hjulet" drejer med kun max 150 omdrejninger/min.

unsigned int rpm;
 
unsigned long timeold;
unsigned long timenew;
unsigned long timediff;



void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, rpm_fun, LOW); 
 
  rpmcount = 0;
  rpm = 0;
  timeold = 0;
}
 
void loop()
{
  if (rpmcount==1) 
    timeold=millis();
 
  
    rpm = 60000/(millis() - timeold)*(rpmcount-1);
    //timeold = millis();
    rpmcount = 0;
    Serial.println(rpm,DEC);
  }
}
 
void rpm_fun()
{
  rpmcount++;
  //Each rotation, this interrupt function is run twice
}

Variabler der bruges i interrupts skal være [

volatile

](http://arduino.cc/en/Reference/Volatile) - det gør bl.a. at compileren ikke putter den midlertligt i et register. Jeg tror det løser dine problemer.

Dokumentationen nævner ikke at man også bør slå interrupts FRA mens man kigger på en multibyte variabel (som int). (Der er macro sei() og cli() - men brugen af dem er ... "tricky" )

Andre fejlkilder: Din magnetføler er vel "debounced" så vi ikke får flere hurtigt på hindanden følgende interrupts? Hvad hvis din main kode kommer bagud så du er forbi rpmcount==1?

Hej Mspuare

Du er jo næsten blevet en "tro følgesvend" i mit forsøg på at erober Arduino verdenen. XD

Nå...jeg ændrede variablerne, og aktiverede den indbyggede pullup.

og det hjalp rigtig meget.

Dog kunne jeg stadig godt tænke mig at serial.print af "rpm" bliver opdateret ved hvert "interrupt". Har du nogle forslag ud fra den nye sketch???

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

 




void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, rpm_fun, CHANGE);
 
 digitalWrite(2, HIGH);
  rpmcount = 0;
  rpm = 0;
  timeold = 0;
}
 
void loop()
{
  if (rpmcount==1) 
    timeold=millis();
 
  else if (rpmcount >= 20) { 
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update
    rpm = 30000/(millis() - timeold)*(rpmcount-1);
    //timeold = millis();
    rpmcount = 0;
    Serial.println(rpm);
  }
}
 
void rpm_fun()
{
  rpmcount++;
  //Each rotation, this interrupt function is run twice
}

VH
Lydfanger

Jeg forstår ikke hvad du vil gøre med din anden version med at test for hhv ==1 og >=20

I dit forrige eksempel fik du da en udskrift ved hver interrupt. (med den risiko at den tid du "hænger" i Serial.print - den tager jo den tid det tager ud udskrive - at rpmcount er imellemtiden nået til mere end 1) Der er dog den fejl at du laver en *(rpmcount-1) og da vi ved at rpmcount er 1 så ganger vi noget med 0. Det bruges oveni som dividend og da Arduino ikke er et fuldt OS sker der intet ved divide-by-zero - resultat er bare volapyk.

Brug lidt af hovedideen fra dit første forsøg: lav din test til >=1, tænk over at din udregning for rpm skal håndtere både at rpmcount er 1 og måske 2. Din konstant 60000 skal rettes. Default er tal i
** **int** **
og den kan som bekendt ikke blive mere end 32767. Put derfor et L bagved tallet så er det et long ("60000L") .

Hej Msquare

Nu fungerer koden. Jeg valgte den sidste kode jeg sendte, af en eller grund virker den første ikke. Det er lige meget hvor præcist rmpcount er, da jeg skal bruge variablen i et senere switch case , hvor jeg så justerer tallet så det passer.

Nu er problemmet så at mine Serial.println i switch case'ene bliver ved med at "løbe" på Serial monitoren. De skal kun vises 1 gang, for hvert case skifte.
Kan du se hvad det er jeg koder forkert????

const int UP = 13;
const int DOWN = 12;
 
volatile int rpm;
 
unsigned long timeold;
unsigned long timenew;
unsigned long timediff;
volatile byte rpmcount;
 

 const int HURTIG = 10;
 const int LANGSOM = 20;
 int lastState;

boolean lastbuttonUP = HIGH;          // debounce//
boolean currbuttonUP = HIGH;
boolean lastbuttonDOWN = HIGH;      
boolean currbuttonDOWN = HIGH;

int PushCounter = 0;

void setup()
{
   pinMode(UP, INPUT);
  digitalWrite(UP, HIGH);
  pinMode(DOWN , INPUT);
  digitalWrite(DOWN, HIGH);
 
  
  Serial.begin(9600);
  attachInterrupt(0, rpm_fun, RISING); // Interrupt triggers on rising edge; when the sensor turns off.
 
 digitalWrite(2, HIGH);
  rpmcount = 0;
  rpm = 0;
  timeold = 0;
  
}
boolean debounceUP(boolean lastUP)              //debounce UP/
{
  boolean currentUP = digitalRead(UP);
  if (lastUP != currentUP)
  {
    delay(50);
    currentUP = digitalRead(UP);
  }
  return currentUP;

}


boolean debounceDOWN(boolean lastDOWN)              //debounce DOWN/
{
  boolean currentDOWN = digitalRead(DOWN);
  if (lastDOWN != currentDOWN)
  {
    delay(50);
    currentDOWN = digitalRead(DOWN);
  }
  return currentDOWN;

} 
void loop()
{
    currbuttonUP = debounceUP(lastbuttonUP);                  // up //
  if(lastbuttonUP == HIGH && currbuttonUP == LOW)
  {
    PushCounter++;
    PushCounter = min(PushCounter, 10);
    Serial.print("PROFIL:");
    Serial.println(PushCounter);

  }
  lastbuttonUP = currbuttonUP;



  currbuttonDOWN= debounceDOWN(lastbuttonDOWN);            //DOWN//
  if(lastbuttonDOWN == HIGH && currbuttonDOWN == LOW)
  {
    PushCounter--;
    PushCounter = max(PushCounter, 1);
    Serial.print("PROFIL");
    Serial.println(PushCounter);
  }
  lastbuttonDOWN = currbuttonDOWN;
  
  
  if (rpmcount==1) 
    timeold=millis();
 

  else if (rpmcount >= 15) { 
    //Update RPM every 20 counts, increase this for better RPM resolution,
    //decrease for faster update
    rpm = 30000L/(millis() - timeold)*(rpmcount-1);
    //timeold = millis();
    rpmcount = 0;
    Serial.println(rpm);
  }

  if ( rpm >= 130 && lastState!=HURTIG)
   switch (PushCounter)
    {
    case 1 : 
      Serial.println("HURTIG 1"); 
      break;
    case 2 : 
      Serial.println("HURTIG 2"); 
      break;
    case 3: 
      Serial.println("HURTIG 3"); 
      break;
    case 4: 
      Serial.println("HURTIG 4"); 
      break;
    case 5: 
      Serial.println("HURTIG 5"); 
      break;
    case 6: 
      Serial.println("HURTIG 6"); 
      break;
    case 7: 
      Serial.println("HURTIG 7"); 
      break;
    case 8: 
      Serial.println("HURTIG 8"); 
      break;
    case 9: 
      Serial.println("HURTIG 9"); 
      break;
    case 10: 
      Serial.println("HURTIG 10"); 
      break;

    }

   
    lastState = HURTIG;
 

  
     if ( rpm <= 129 && lastState!=LANGSOM)
   switch (PushCounter)
    {
    case 1 : 
      Serial.println("LANGSOM 1"); 
      break;
    case 2 : 
      Serial.println("LANGSOM 2"); 
      break;
    case 3: 
      Serial.println("LANGSOM 3"); 
      break;
    case 4: 
      Serial.println("LANGSOM 4"); 
      break;
    case 5: 
      Serial.println("LANGSOM 5"); 
      break;
    case 6: 
      Serial.println("LANGSOM 6"); 
      break;
    case 7: 
      Serial.println("LANGSOM 7"); 
      break;
    case 8: 
      Serial.println("LANGSOM 8"); 
      break;
    case 9: 
      Serial.println("LANGSOM 9"); 
      break;
    case 10: 
      Serial.println("LANGSOM 10"); 
      break;

    }

    lastState = LANGSOM;
 
  
 
}
void rpm_fun()
{
  rpmcount++;
  //Each rotation, this interrupt function is run twice
}

Venlig hilsen

LYDANGER

Den gøær præcis det du beder den om. :slight_smile: I loop, gennemløber du din switch hver gang.

Men jeg kan ikke fra koden helt gætte hvad din hensigt er. Hvis du kun vil trigge den ved hver button up/down (hvis logik jeg ikke har nærlæst) så vil jeg foreslå du putter switch statement med tilbehør ud i en seperat procedure og kalder denne der hvor du skriver "PROFIL" og PROFIL:"

Ovenstående givet efter kort gennemgang - fejl og mangler kan forekomme - uden ansvar - bør ikke bruges til atomkrafteværker, kritiske medisinsk udstyr, eller fly sikkerheds udstyr :wink:

Msquare

Hensigten er: der foretages et valg på forhånd med up/down "Profil".
alt efter hvor hurtigt "hjulet" kører (rpm) skal der ske forskellige aktiviteter alt efter hvordan kobinationen af profil og rpm er.
Der er 10 "profiler" hvor der er 2 muligeder pr. profil.
Switch case Serial.println skal i virkeligheden inderholder koder der aktivere film/programmer via GoBeTwino.

Det hele er bygget ind i en kondicykel. Arduinoen skal motiverer børn til at motionerer. Profiler vælges ud fra hvilken film/musik/programmer børnene er interesseret i, og værdien på (rpm) bestemmer om børnene kan se filmen ( højt rpm) eller ikke kan se den (lavt rpm).

OK, så uden at nærlæse noget, dvs et hurtigt skud fra hoften, så skal du bruge samme logik med at se om du har skiftet til niveau "x" fra et andet niveau og kun udskrive (køre switch udsagnet) hvis det har skiftet siden sidst. Så noget á lá: (denne kode skrives uden stave kontrol - i øvrigt har jeg lige nydt et par juleøl :stuck_out_tongue: )

if ( rpm >= 130 && lastState!=HURTIG)
   if (Pushcounter!=lastPushCounter) {
     lastPushcounter=PushCounter ;
     switch (PushCounter) {

skal motiverer børn til at motionere

Spænnende. (tænker at hvis man kunne arrangere at opladning af iPad/mobil KUN kunne foretages via en kondicykel ...)

Hej igen

Håber juleølene bekom dig vel.

Problemmet er løst, dog var det en anden variable, der skulle "tæmmes".

 if ( rpm >= 130 && lastState!=HURTIG)
    if (rpm!=lastrpm) 
     { lastrpm=rpm ;

  switch (PushCounter)

Tusind tak.
LYDFANGER

Hej igen.

Nu mangler jeg bare en auto shut-off funktion i mit projekt. (barnet holder op med at træde i pedalerne)

Jeg har tænkt mig at bruge Interrupt 2, som er parallel forbundet med interupt 1 (samme sensor).

Funktionen skulle gerne gerne sende et Serial.println til GobeTwino, når der er gået feks. 10 sek. uden det næste interrupts er fundet sted.
Kan sketchen herunder overhovedet bruges, eller skal der tænkes helt andre veje.

promblemet, som jeg ser det er at jeg bruger millis(), fordi det næste interupt ikke kommer (pedalerne kører ikke længere rundt).
Er der en venlig sjæl der vil hjælpe, og denne gang, vil jeg være fræk og bede om noget, der er så tæt på færdigt som muligt, da min deadline er meget tæt på.

volatile int state = LOW;
int unsigned long starttid;
int unsigned long sluttid;
int unsigned long lastsluttid;
int laststate = 0;
int PAUSE = 0;


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

  digitalWrite(3, HIGH);
  attachInterrupt(1, autoslut, FALLING);
}

void loop()
{
  if (state==LOW)

    starttid = millis();
  {
    sluttid = (millis()-starttid);

 
      {
        
        Serial.print("tiden er:");
          Serial.println(sluttid);
      }
    

  }}
void autoslut()
{
  state = !state;
}

LYDFANGER

Se svar til "RPM 2"