Autolaturi mökille varavoimaksi Arduinon avulla

@ississ , ahaa eli lienee mahdollisuus, että tuo kierroslukumittauksen virhe kierrosluvun kasvaessa johtuisi tuosta?

Korjaa, jos ymmärrän väärin, mutta eikös tuo interrupt sitten olisi blokkaava?
 
Nyt varmistui muuten, miksi Arduino ei toimi ilman tietokoneeseen USB:llä liittämistä. VIN-pinnin tulee 9 voltin sijaan vain 0,96 volttia. Pahoin pelkään, että regulaattori on rikki. Mutta miksi? Kytkennässähän tuo on erotettu muusta, että ei sen 100 mA:n regulaattorin olisi pitänyt olla rajoilla.

No nyt pitää purkaa tuo johtohässäkkä, jotta vielä varmistellaan, että onko vika tosiaan siinä regulaattorissa vai missä. :(
 
Kiinanpojan tekoäly ehdottaisi tällaisia muutoksia kierrosluvun laskentaan, onko aivan kaheleita vai voisiko jopa toimia äkkiä katsottuna?

C++:
// ... existing code ...

// RPM Calculation variables - volatile for interrupt safety
volatile unsigned long lastFallTime = 0;  // Time of last falling edge
volatile unsigned long period = 0;        // Pulse period in microseconds

// ... existing setup ...
void setup() {
  // ... existing setup code ...

  // RPM Pin with pull-up and PCI enabled
  pinMode(rpmPin, INPUT_PULLUP);
  PCICR |= (1 << PCIE2);    // Enable PCINT2 group
  PCMSK2 |= (1 << PCINT21); // Enable interrupt for PCINT21 (pin 5)

  // ... rest of setup ...
}

// Pin Change Interrupt for RPM sensor (pin 5)
ISR(PCINT2_vect) {
  static unsigned long prevTime = 0;
  static int prevState = HIGH;
 
  int currentState = digitalRead(rpmPin);
  if (prevState == HIGH && currentState == LOW) { // Falling edge
    unsigned long currentTime = micros();
    lastFallTime = currentTime;
    if (prevTime != 0) {
      period = currentTime - prevTime;
    }
    prevTime = currentTime;
  }
  prevState = currentState;
}

void loop() {
  // ... existing sensor readings ...

  // New RPM Calculation (atomic read + timeout handling)
  unsigned long now = micros();
  unsigned long temp_lastFallTime;
  unsigned long temp_period;
 
  // Atomic read of volatile variables
  noInterrupts();
  temp_lastFallTime = lastFallTime;
  temp_period = period;
  interrupts();

  if (temp_lastFallTime == 0) {
    rpm = 0; // No pulse ever detected
  } else if (now - temp_lastFallTime > 500000) { // 500ms timeout
    rpm = 0;
  } else {
    rpm = (temp_period > 0) ? 60000000UL / temp_period : 0;
  }

  // ... rest of loop ...
}
 
@ississ , ahaa eli lienee mahdollisuus, että tuo kierroslukumittauksen virhe kierrosluvun kasvaessa johtuisi tuosta?

Korjaa, jos ymmärrän väärin, mutta eikös tuo interrupt sitten olisi blokkaava?

Ihan mahdollista että johtuu tuosta.

Ja tavallaan interrupt on blokkaava. Käytännössä voi t ajatella niin että loop() suoritetaan peräkkäin koko ajan.
Kun tulee pin change interrupt niin loopin suoritus laitetaan paussille, suoritetaan interrupt- funktio ja loop jatkaa siitä mihin jäi.
Tästä johtuen interrupt- funktiossa ei saa käyttää viiveitä yms vaan koodin pitää tehdä haluttu asia mahdollisimman nopeasti.


Kiinanpojan tekoäly ehdottaisi tällaisia muutoksia kierrosluvun laskentaan, onko aivan kaheleita vai voisiko jopa toimia äkkiä katsottuna?

C++:
// ... existing code ...

// RPM Calculation variables - volatile for interrupt safety
volatile unsigned long lastFallTime = 0;  // Time of last falling edge
volatile unsigned long period = 0;        // Pulse period in microseconds

// ... existing setup ...
void setup() {
  // ... existing setup code ...

  // RPM Pin with pull-up and PCI enabled
  pinMode(rpmPin, INPUT_PULLUP);
  PCICR |= (1 << PCIE2);    // Enable PCINT2 group
  PCMSK2 |= (1 << PCINT21); // Enable interrupt for PCINT21 (pin 5)

  // ... rest of setup ...
}

// Pin Change Interrupt for RPM sensor (pin 5)
ISR(PCINT2_vect) {
  static unsigned long prevTime = 0;
  static int prevState = HIGH;
 
  int currentState = digitalRead(rpmPin);
  if (prevState == HIGH && currentState == LOW) { // Falling edge
    unsigned long currentTime = micros();
    lastFallTime = currentTime;
    if (prevTime != 0) {
      period = currentTime - prevTime;
    }
    prevTime = currentTime;
  }
  prevState = currentState;
}

void loop() {
  // ... existing sensor readings ...

  // New RPM Calculation (atomic read + timeout handling)
  unsigned long now = micros();
  unsigned long temp_lastFallTime;
  unsigned long temp_period;
 
  // Atomic read of volatile variables
  noInterrupts();
  temp_lastFallTime = lastFallTime;
  temp_period = period;
  interrupts();

  if (temp_lastFallTime == 0) {
    rpm = 0; // No pulse ever detected
  } else if (now - temp_lastFallTime > 500000) { // 500ms timeout
    rpm = 0;
  } else {
    rpm = (temp_period > 0) ? 60000000UL / temp_period : 0;
  }

  // ... rest of loop ...
}

PCINT funktio suoritetaan sen jälkeen kun tilan vaihto on tapahtunut, siis edellistä tilaa ei tarvitse tutkia ja säästää vaan vain tarkistaa että nyt on alhaalla (tilanvaihto -> edellinen oli pakosti ylhäällä)
Int- funktion sisällä on myös määritetty prevTime- muuttuja, se on aina 0 tuolla tavalla -> pitää olla globaali jos haluaa verrata suorituysten välillä. Tämä näyttää olevan ai- koodarin kantapää aika usein...
Ja kyllä, C++ std mukaan tuonkin pitäisi toimia mutta koska kyseessä on avr niin en välttämättä luottaisi siihen että kaikki toimisi varmasti. Parempi siis laittaa suosiolla itse globaaliksi kaikki mikä sinne kuuluu, varsinkin int- funktioissa.

Eli joku tällainen pitäisi riittää:

Koodi:
volatile unsigned long prevTime = 0;

// Pin Change Interrupt for RPM sensor (pin 5)
ISR(PCINT2_vect) {
  if (digitalRead(rpmPin) == LOW) { // Falling edge
    unsigned long currentTime = micros();
    lastFallTime = currentTime;
    if (prevTime != 0) {
      period = currentTime - prevTime;
    }
    prevTime = currentTime;
  }
}

Alustuksen saat tarkastaa datalehdestä pinnin perusteella, teknisesti on oikein jos ai tulkkasi oikeaa datalehteä oikeasta arduinokortista.
 

Statistiikka

Viestiketjuista
283 513
Viestejä
4 873 056
Jäsenet
78 588
Uusin jäsen
Angkarn

Hinta.fi

Back
Ylös Bottom