Vlugger alternatief voor if else

algemene C code
Gebruikers-avatar
Berichten: 631
Geregistreerd: 15 Nov 2015, 11:54

Vlugger alternatief voor if else

Berichtdoor Gij Kieken » 03 Mrt 2019, 21:58

Mijn vraag gaat specifiek over void rotate().
Is er een vlugger sneller manier om een if else constructie te schrijven?
Daarbij bedoel ik niet (een eventueel switch case) maar iets in de zin van low level of direct port manipulation.
Het test progje werkt op zich behoorlijk goed.
Ik gebruik zo een mechanisch rotary encoder 20PPR van onze gele broeders.
Natuurlijk als je het asje tussen duim en wijsvinger een flinke zet geeft durft ze nu en dan een paar pulsjes overslaan.
Misschien is dit grotendeels te wijten aan de kwaliteit van dit productje (lees traagheid van de contacten ed.)
Des al niet te min zoek ik een manier om de void rotate () vlugger te verwerken.
Nadeel ik ben niet vertrouwd met assembler.(mocht daar de oplossing in liggen).
Graag jullie mening.

Code: Alles selecteren
/*
  Update:   ver.03  03/03/2019
            Clean up void rotate()

  Purpose:  Full-step Bi-directional encoding
            The code is used for speed testing the encoder
  Board:    Arduino UNO
            Mechanical quadrature encoder
  Author:   Gij Kieken
  Date:     03/03/2019
  Info:     Wiring: Connect common pin of encoder to ground.
            Connect pin A to a pin with external interrupts (eg. D2)
            Connect pin B to another free pin (eg. D6)
            The encoder is hardware debounced and external pull-up
            The signal is also cleaned up with a shmitt trigger
*/
#define PIN_A 2 // D2 pin on the Uno is interrupt 0
#define PIN_B 3 // D3 pin on the Uno
#define SWpin 4 // The switch pin of the encoder
#define SHOWpin 5 // The print value button
boolean reset0 = false;
boolean show = false;
volatile long increase;

void rotate() {
  // Eerste probatie
  //if (digitalRead (PIN_B)) increase++;
  // else increase--;
  // Tweede probatie
  //if (PIND & B00001000) increase++; // B00001000=digital pin 3
  if (PIND & (1 << PD3)) increase++;
  else increase--;
}

void setup() {
  Serial.begin(9600);    // Start up serial communication
  pinMode(PIN_A, INPUT); // Not necessary,pin's are by default Input
  pinMode(PIN_B, INPUT); // Not necessary,pin's are by default Input
  pinMode(SWpin, INPUT); // The switch pin on the encoder
  pinMode(SHOWpin, INPUT_PULLUP); // The print button
  attachInterrupt(digitalPinToInterrupt(2), rotate, RISING); // Interrupt 0 is pin 2
}

void loop() {
  if (digitalRead(SWpin)) {
    reset0 = false; // Reset the reset to zero flag
  }
  if (digitalRead(SHOWpin)) {
    show = false; // Reset print once flag
  }
  if (!digitalRead(SWpin) && (!reset0)) {  // If button pressed reset counter
    reset0 = true;
    increase = 0;
    Serial.print ("Count = ");
    Serial.println(increase);
  }

  if (!digitalRead(SHOWpin) && (!show)) { // If button pressed print value
    show = true;
    Serial.print ("Count = ");
    Serial.println(increase);
  }
  delay(10);  // Used to debounce a bit
}

Advertisement

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Vlugger alternatief voor if else

Berichtdoor shooter » 05 Mrt 2019, 13:28

Als je op de falling ook een interrupt zet kun je dubbel zoveel pulsen krijgen
zet serial uit dat scheelt veel.
gebruik machinetaal.
en bij 20PPR en bijvoorbeeld 50 Hz zit je nog maar aan 1000 pulsen per seconde dat kan iedere processor bijhouden dus daar ligt het probleem niet en dat is bij 3000 toeren.
paul deelen
shooter@home.nl

Gebruikers-avatar
Berichten: 631
Geregistreerd: 15 Nov 2015, 11:54

Re: Vlugger alternatief voor if else

Berichtdoor Gij Kieken » 05 Mrt 2019, 20:28

Bedankt Shooter voor de reactie.
Dit is een vereenvoudige versie van het origineel.
De Serial heb ik nodig om te loggen in Exel en zo te saven in een .csv file ,dit werkt allemaal naar behoren.
Het is ook zo dat de serial slechts print na een druk op de knop.
De opzet is een 2d-X_Y tafel met een mechanische constructie en twee incrementeel encoders (200PPR), om zo een opgelegd werkstuk te kunnen aftasten en de X-Y coordinaten van bepaalde punten te kunnen vastleggen om vervolgens dit te gebruiken in AutoCad om een tekening te maken.
Dit omzetten in G-code en uit laseren.
Daarom wilde ik de isr zo kort als mogelijk maken.
Eerst gebruikte ik digitalRead maar dat neemt veel meer tijd in beslag dan direct port-acces.
Nu wilde ik nog iets uitvogelen om de cycle time van de if-else constructie te verminderen.
Iets met bitShift maar dan is het iedere keer een macht van twee die je optelt of aftrekt terwijl het de bedoeling is 1 op of af te trekken.
Toen dacht ik aan een constructie met pointers maar dat maakt het onnodig ingewikkeld.
In assembler kan ik mij niet behelpen (gebrek aan kennis).

Gebruikers-avatar
Berichten: 631
Geregistreerd: 15 Nov 2015, 11:54

Re: Vlugger alternatief voor if else

Berichtdoor Gij Kieken » 08 Mrt 2019, 19:07

Of het nu echt sneller loopt weet ik niet.
Denk zelf van niet doordat er veel meer operatoren en vergelijkingen gebruikt worden.
Nu het resultaat blijft het zelfde, met een vlugge spin aan het asje van de rotary encoder slaat ze een paar stapjes over.
Tweede feit is, als ik het uur nadien nog eens lees snap ik het al niet meer meteen, dus zeker geen verbetering.
En het wordt heel onoverzichtelijk als ik probeer op beide ingangen een Interrupt Change te gebruiken.
Maar het was eens een leuke uitdaging om geen if else te gebruiken in de Isr.
Code: Alles selecteren
Isr zonder if-else constructie

#define Switch 4  // De knop
#define A_pin 2   // De data pin
#define B_pin 3   // De clock pin
volatile long count;

void rotary() {
  // In de plaats van if else te gebruiken
  // Digital pin 2 is PD2 bij de Atmega 328
  // Digital pin 3 is PD3 bij de Atmega 328
  //**********************
  // Optellen of Aftrekken
  // boolean B = PIND & (1 << PD3);
  // count = count + (1 && B) - (1 && !B);
  //**********************
  /*
     if ((PINE & (1 << PE4)) && (PIND & (1 << PD1)) ||
     !(PINE & (1 << PE4)) && !(PIND & (1 << PD1))) {
     countX++;
     } else countX--;
  */
  count = count + (1 && ((PIND & (1 << PD2)) && (PIND & (1 << PD3))
                ||  !(PIND & (1 << PD2)) && !(PIND & (1 << PD3))))
                - (1 && ((PIND & (1 << PD2)) && !(PIND & (1 << PD3))
                ||  !(PIND & (1 << PD2)) && (PIND & (1 << PD3))));
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(Switch, INPUT_PULLUP);
  pinMode(A_pin, INPUT);
  pinMode(B_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), rotary, CHANGE);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(Switch) == false) {
    Serial.print("De teller staat op ");
    Serial.println(count);
  }
  delay(100);  // Wait a little bit to debounce
}

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Vlugger alternatief voor if else

Berichtdoor shooter » 08 Mrt 2019, 19:41

wellicht kan het niet sneller want de ingangen hebben een snubber circuit ofwel antidender, en dat heeft ook tijd nodig.
Dat kun je me een toongenerator proberen want dat zal voor iedere ingang anders zijn.
kijk eens hier http://jeelabs.org/2010/01/06/pin-io-performance/ zo zijn er meer hoor.
paul deelen
shooter@home.nl

Gebruikers-avatar
Berichten: 631
Geregistreerd: 15 Nov 2015, 11:54

Re: Vlugger alternatief voor if else

Berichtdoor Gij Kieken » 08 Mrt 2019, 21:35

Bedankt vind het een educatief artikel,het snelheidsverschil was mij bekent maar kon er geen getal op plakken.
Als alternatief kon ik nog een ESP of ander bord gebruiken, maar de 16Mhz moet normaal gezien voldoende zijn.
Het probleem zit hem echt in de traagheid en kwaliteit van de mechanical encoder, met twee optische rotary encoders mag ik een flinke zet aan de as geven het resultaat evenaart zwitserse preciesie.
Op voorhand was het doel geen bibliotheken te gebruiken ,deze zijn heel erg handig maar veelal als je iets dieper wil spitten in de werking ervan wordt de lat toch iets hoger gelegd.
De code is deze geworden.
Code: Alles selecteren
/*
  Update:   ver.01  04/03/2019
           
  Purpose:  Double 2x Bi-directional encoding
            to represent the X-Y axis of a 2d object
            and log it in .csv format.
  Board:    Arduino Mega 2560
            Optical encoder 500PPR
            Mechanical encoder 20PPR
  Author:   Gij Kieken
  Date:     04/03/2019
  Wiring:   Connect common pin of encoder to ground.
            Connect pin A to a pin with external interrupts (eg. D20)
            Connect pin B to another free pin (eg. D2)
            Connect common pin of encoder to ground.
            Connect pin A to a pin with external interrupts (eg. D21)
            Connect pin B to another free pin (eg. D3)
  Info:     The mechanical encoder is hardware debounced
*/
// Used functions
/* myDebounceShortLongPress
    Purpose:  Debounce an array of push buttons and determine if they
              where pressed a short or long time.(micro seconds)
              In setup use pinMode(pin, INPUT_PULLUP) so no external
              components are necessary.
              Buttons connected 1-side to gnd the other to Arduino pin.
              Author: Gij Kieken
*/
#define pinAx 20  // Digital pin D20 on the Mega is interrupt 1
#define pinBx 2   // Digital pin D2 on the Mega
#define pinAy 21  // Digital pin D21 on the Mega is interrupt 0
#define pinBy 3   // Digital pin D3 on the Mega

const byte maxButton = 3;                        //Number of buttons
const byte pinPushButton[maxButton] = {4, 5, 6}; //Arduino IN pins
const byte maxOutput = 4;                        //Number of outputs
const byte LED[maxOutput] = {9, 10, 11, 12};     //Arduino OUT pins

volatile long countX = 0;
volatile long countY = 0;

boolean modeStatus = false;        // Keep track of Hole or Line mode
boolean printHeaderHole = true;    // Print header once
boolean printHeaderLine = false;   // Print header once
boolean printHeaderStop = false;   // Print header once

const unsigned long interval = 500000;
unsigned long previousStartMicros;
unsigned long previousStopMicros;
boolean enabledStop = false;
boolean enabledStart = false;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(pinBx, INPUT); //Channel B of encoder X-axis
  pinMode(pinBy, INPUT); //Channel B of encoder Y-axis
  pinMode(pinAx, INPUT); //Channel A of encoder X-axis INT1
  pinMode(pinAy, INPUT); //Channel A of encoder Y-axis INT0
  //Initialize push button pins as inputs with pull-ups
  // button[0]=startButton, button[1]=stopButton, button[2]=modeButton
  for (byte i = 0; i < maxButton; i++) {
    pinMode(pinPushButton[i], INPUT_PULLUP);
  }
  //Initialize LED pins as outputs
  // LED[0]=HoleLed, LED[1]= LineLed, LED[2]=StartLed, LED[3]=StopLed
  for (byte j = 0; j < maxOutput; j++) {
    pinMode(LED[j], OUTPUT);
  }
  digitalWrite(LED[0], !modeStatus);   //We start in hole mode
  digitalWrite(LED[1], modeStatus);    //LineLED=OFF
  digitalWrite(LED[2], LOW);           //StartLed=OFF
  digitalWrite(LED[3], LOW);           //StopLed=OFF
  attachInterrupt(digitalPinToInterrupt(pinAx), rotateX, CHANGE);   //Int 1
  attachInterrupt(digitalPinToInterrupt(pinAy), rotateY, CHANGE);   //Int 0

  // Start communication with Excel
  Serial.println("CLEARSHEET");
  Serial.println("LABEL,X-Pos,Y-Pos");
  Serial.println("CELL,SET,C01, Gij Kieken X-Y pos ");
  Serial.println("CELL,SET,C02, Long press Start to start log.");
  Serial.println("CELL,SET,C03, Short press Start to tween.");
  Serial.println("CELL,SET,C04, Short press mode to toggle.");
  Serial.println("CELL,SET,C05, Short press Stop to stop log.");
  Serial.println("DATA,HOLE-X,HOLE-Y");
}

void loop() {
  // put your main code here, to run repeatedly:
  static unsigned long previousTime = 0;
  const byte timeInterval = 2000; //pick a short time interval
  byte button[maxButton] = {}; //array to store the latest readings
  // button[0]=startButton, button[1]=stopButton, button[2]=modeButton
  // LED[0]=HoleLed, LED[1]= LineLed, LED[2]=StartLed, LED[3]=StopLed
  // - check all buttons
  if ((micros() - previousTime) > timeInterval) {
    previousTime = micros();
    for (byte i = 0; i < maxButton; i++) {
      button[i] = checkButtons(i);
    }
    if (button[0] == 1) { // Code, when Start button is short-pushed
      //***Continue to Log***
      if (enabledStart) {
        digitalWrite(LED[2], HIGH);
        Serial.print("DATA,");
        Serial.print(countX);
        Serial.print(",");
        Serial.println(countY);
        Serial.println("BEEP");
        previousStartMicros = micros();
      }
    }
    if (button[0] == 2) { // Code, when Start button is long-pushed
      //***Start to Log***
      if (!enabledStart) {
        digitalWrite(LED[2], HIGH);
        enabledStart = true;
        // Reset countX and countY
        countX = 0;
        countY = 0;
        Serial.print("DATA,");
        Serial.print(countX);
        Serial.print(",");
        Serial.println(countY);
        Serial.println("BEEP");
        previousStartMicros = micros();
      }
    }
    if (button[1] == 1) { // Code, when Stop button is short-pushed
      //***Stop to Log***
      digitalWrite( LED[3], HIGH);         // turn on led
      if (!printHeaderStop) {
        Serial.println("DATA,STOPPED-X,STOPPED-Y");  // Print header
        // Reset the flags
        modeStatus = LOW;                  // Reset modeStatus to hole mode
        printHeaderLine = false;
        printHeaderStop = true;            // Make sure header is printed only once
        enabledStart = false;              // Reset the start flag
        enabledStop = true;                // Print offset X=0,Y=0 once
        digitalWrite(LED[0], !modeStatus); // Change hole led state
        digitalWrite(LED[1], modeStatus);  // Change line led state
        Serial.println("DATA,HOLE-X,HOLE-Y");
        Serial.println("BEEP");
        Serial.println("SAVEWORKBOOKAS,MyNewX-Y_pos");
        printHeaderHole = true;
        previousStopMicros = micros();
      }
    }
    if (button[2] == 1) { // Code, when Mode button is short-pushed
      //***Select the mode***
      // modeStatus=0 ---> hole-modus, modeStatus=1 ---> line-modus
      modeStatus = !modeStatus;          // Toggle the LED value
      digitalWrite(LED[0], !modeStatus); // Change hole led state
      digitalWrite(LED[1], modeStatus);  // Change line led state
      //***Determine mode Hole or Line and printout appropriate header***
      if (!modeStatus && !printHeaderHole && printHeaderLine) {
        Serial.println("DATA,HOLE-X,HOLE-Y");
        Serial.println("BEEP");
        printHeaderHole = true; // Make sure header is printed only once
        printHeaderLine = false;
      }
      else if (modeStatus && printHeaderHole && !printHeaderLine) {
        Serial.println("DATA,LINE-X,LINE-Y");
        Serial.println("BEEP");
        printHeaderLine = true;
        printHeaderHole = false;
      }
    }
  }
  // Switch off start led
  if ( micros() - previousStartMicros >= interval) {
    digitalWrite( LED[2], LOW);         // turn off led
  }
  // Switch off stop led
  if ( enabledStop)  {                  // software timer is active
    if ( micros() - previousStopMicros >= interval) {
      digitalWrite( LED[3], LOW);      // turn off led
      enabledStop = false;             // stop software timer
      printHeaderStop = false;         // Reset flag
    }
  }
} // End void loop()
//************************************************************************

/*  Function: Checks one button for short or long press (micro seconds)
              Accepts a byte for the button number
              Returns a byte 0-none 1-short 2-long
   Info:      Action is executed when release button
*/
byte checkButtons(byte buttonNo) {
  const unsigned long timeDebounce = 100000;//time to debounce
  const unsigned long timeLong = 1000000;   //minimum time for Long press
  const unsigned long timeBreak = 200000;   //time interval after button release,
  //before ready for next press
  static byte state[maxButton] = {};        //this initializes all elements to zero
  static unsigned long previousTime[maxButton] = {};//this initializes all elements to zero
  byte r = 0;                              // 0:not  1:short  2:long
  if (state[buttonNo] == 0) {  //no button has been pressed - check if
    if (digitalRead(pinPushButton[buttonNo]) == LOW) {
      previousTime[buttonNo] = micros();
      state[buttonNo] = 1;
    }
  } else if (state[buttonNo] == 1) {  //button was pressed - check for how long
    if ( (micros() - previousTime[buttonNo]) > timeDebounce) {
      if ( (micros() - previousTime[buttonNo]) < timeLong) {
        if ( digitalRead(pinPushButton[buttonNo]) == HIGH) { //released -> short press
          previousTime[buttonNo] = micros();
          state[buttonNo] = 3;
          r = 1;
        }
      } else {                        //it was a long press
        state[buttonNo] = 2;
        r = 2;
      }
    }
  } else if (state[buttonNo] == 2) {  //wait for long button press to end
    if (digitalRead(pinPushButton[buttonNo]) == HIGH) {
      previousTime[buttonNo] = micros();
      state[buttonNo] = 3;
    }
  } else if (state[buttonNo] == 3) {  //wait a little while after previous button press
    if ( (micros() - previousTime[buttonNo]) > timeBreak) {
      state[buttonNo] = 0;
    }
  }
  return r;
}

void rotateX() {
  //if (PINE & (1 << PE4)) countX++;  // B00010000= digital pin 2 PinBx
  // Als beide ingangen hoog zijn of beide ingangen laag zijn dan tel één op
  // Als beide ingangen verschillend zijn trek één af
  // (PINE & (1 << PE4)) dit is digital pin D2
  // (PIND & (1 << PD1)) dit is digital pin D20
  if ((PINE & (1 << PE4)) && (PIND & (1 << PD1)) ||
     !(PINE & (1 << PE4)) && !(PIND & (1 << PD1))) {
    countX++;
  } else countX--;
}

void rotateY() {
  //if (PINE & (1 << PE5)) countY++;  // B00100000= digital pin 3 PinBy
  // (PINE & (1 << PE5)) dit is digital pin D3
  // (PIND & (1 << PD0)) dit is digital pin D21
  if ((PINE & (1 << PE5)) && (PIND & (1 << PD0)) ||  // Als beide ingangen hoog zijn
     !(PINE & (1 << PE5)) && !(PIND & (1 << PD0))) { // of beide ingangen laag zijn
    countY++;                                        // tel één op
  } else countY--;        // Anders als beide ingangen verschillend zijn trek één af
}



Terug naar C code

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 7 gasten