Vlugger alternatief voor if else
6 berichten
• Pagina 1 van 1
- Gij Kieken
- Berichten: 631
- Geregistreerd: 15 Nov 2015, 11:54
Vlugger alternatief voor if else
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.
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
Re: Vlugger alternatief voor if else
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.
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
shooter@home.nl
- Gij Kieken
- Berichten: 631
- Geregistreerd: 15 Nov 2015, 11:54
Re: Vlugger alternatief voor if else
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).
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).
- Gij Kieken
- Berichten: 631
- Geregistreerd: 15 Nov 2015, 11:54
Re: Vlugger alternatief voor if else
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.
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
}
Re: Vlugger alternatief voor if else
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.
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
shooter@home.nl
- Gij Kieken
- Berichten: 631
- Geregistreerd: 15 Nov 2015, 11:54
Re: Vlugger alternatief voor if else
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.
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
}
6 berichten
• Pagina 1 van 1
Wie is er online?
Gebruikers in dit forum: Geen geregistreerde gebruikers en 12 gasten