[SOLVED] Question: AVR, interrupts and ISR

Go To Last Post
35 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

 

I searched here and found quite a few posts about ISRs and interrupts, but none answered my question. Please consider this example code:

 

volatile uint8_t x;

//////// LOCATION A ////////
ISR (TIMER1_COMPA_vect)
{
    blink(); // led on or off
    x++; // increment x (eventually rolls over 0xFF->0x00)
}

//////// LOCATION B ////////
void blink (void)
{
    // led on if x less than 128, else led off
    (x < 128) ? PORTB |= (1 << 7) : PORTB &= ~(1 << 7);
}

void set_timer (uint32_t rate)
{
    cli();
    // set up timer blah blah...
    sei();
}

int main (void)
{
    DDRB |= (1 << 7); // enable PB7 as output
    set_timer (100); // timer fires 100 times per second

    while (1) { // hang here }
}

 

Now, I know that interrupts are disabled within an ISR, but what about outside? Specifically, the area called "Location B". When "blink" is called, are interrupts enabled at that time or only after "blink" is done, control returns to the ISR and the ISR finally exits?

 

Thanks!

 

This topic has a solution.

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Last Edited: Mon. Mar 30, 2020 - 05:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Location A is an ISR, and you really should NOT call a function from inside an ISR.  I usually set a flag, or increment a variable and get out quick so I do not miss another interrupt.

 

As long as you STAY IN location a....that is teh ISR, then interrupts are disabled.   I do not know what will happen if you leave due to a call....If I had to guess I would think the interrupts might still be disabled.

 

Others will certainly know better.  But you could always run this in teh simulator and see what happens

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Krupski wrote:
after "blink" is done, control returns to the ISR and the ISR finally exits?

Yes.  What part is confusing to you?  Assuming your ISR code generated by your compiler ends in RETI [it would be a very rare exception], then what does RETI do?

93. RETI – Return from Interrupt93.1. DescriptionReturns from interrupt. The return address is loaded from the STACK and the Global Interrupt Flag is set. ...

Now, what does the datasheet for your AVR model say about entering an interrupt service routine?

When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are dis-abled. ...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The next pending IRQ is processed when the current one is completely finished & returned from (an reti is executed by the code).  Calling other routines from the IRQ doesn't affect it (unless those routines do something to modify the IRQ flags, return stack, etc).

 

Make SURE that any routine you call from an IRQ is ONLY called by that IRQ, or be designed in some manner as reentrant-capable.  Why?  If that routine is called by main it might be in the middle of its work when an IRQ fires & calls it again, with the first instance being half-finished.  Upon resumption, things may be different than originally, causing strange results, or complete failure.    

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sun. Mar 29, 2020 - 09:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't see any problem with the code.

 

Calling subroutines inside a ISR is perfectly ok provided they don't do anything that wouldn't be permitted usually in an ISR.

 

Inside the subroutines, interrupts will remain disabled and should not be enabled.

 

Normally I try to segregate ISR subroutines from non-ISR subroutines, but for trivial things it might not matter.

 

Also note that you can declare subroutines as "static" in C and the compiler will often inline them, reducing a few instructions and stack usage. Declare the subroutines static unless you need to use them from another module.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

markxr wrote:
Calling subroutines inside a ISR is perfectly ok provided they don't do anything that wouldn't be permitted usually in an ISR.
Apart from the avr-gcc overhead of course? But if you use some other C compiler it should be OK.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:

Location A is an ISR, and you really should NOT call a function from inside an ISR.  I usually set a flag, or increment a variable and get out quick so I do not miss another interrupt.

 

As long as you STAY IN location a....that is teh ISR, then interrupts are disabled.   I do not know what will happen if you leave due to a call....If I had to guess I would think the interrupts might still be disabled.

 

Others will certainly know better.  But you could always run this in teh simulator and see what happens

JIm

Sorry - typo. I meant "Location B".

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Calling subroutines inside a ISR is perfectly ok provided they don't do anything that wouldn't be permitted usually in an ISR.

That is not a good way to state it...it is fine as long as the routine is callable ONLY by the isr.  If it is callable both by main and the isr, it usually needs to be reentrant. 

Neglecting this can cause many days of frustration. 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What I really am after is this:  I am using a pin change interrupt (2 actually) to read a rotary encoder. When I get an interrupt, I want to immediately disable the pin change interrupt enable bits to avoid bogus position updates due to contact bounce within the encoder. I also wanted to be sure interrupts STAY off while I am in the encoder position update subroutine.

 

This is what I want to be sure will work:

 

PIN CHANGE ISR EITHER EDGE

{

    disable pin change interrupts

    call encoder_update();

}

 

ENCODER_UPDATE (not all code shown for clarity)

{

    // update positon (a volatile uint16_t)

}

 

See? I want to be sure that no other interrupts fire during the position update to avoid any bounces. I needed to know if I should ALSO do a "cli()" as soon as I entered "encoder_update" but it seems from what you all have said, I do NOT need to. Correct?

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think that was all covered in #3 ?

 

So, after re-reading #3, what doubts remain ?

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Mar 30, 2020 - 05:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Calling subroutines inside a ISR is perfectly ok provided they don't do anything that wouldn't be permitted usually in an ISR.

That is not a good way to state it...it is fine as long as the routine is callable ONLY by the isr.  If it is callable both by main and the isr, it usually needs to be reentrant. 

Neglecting this can cause many days of frustration. 

 

See the post above. The only thing that will call the position update subroutine is either ISR (one for each encoder output pin). And since the encoder outputs gray code, there will never be more than one pin change (i.e. interrupt) per encoder detent.

 

So, although two different ISRs call the same subroutine, never will it be called WHILE it's being used (unless the encoder is turned at 100,000 RPM) laugh

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

I think that was all covered in #3 ?

 

So, after re-reading #3, what doubts remain ?

 

 

I think "none", but just wanted to be sure I was understanding properly. Thanks!

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

When I get an interrupt, I want to immediately disable the pin change interrupt enable bits to avoid bogus position updates

This is where you are going wrong...you should write your routines assuming that the noise pulses WILL occur and generate interrupts.  In fact, you may not be able to turn them off in time anyhow, so you cant guarantee none will occur before your IRQ shutoff.

You might be better clearing any pending pinchange irq flags, before exiting your PC irq, though it is more robust if you make the irq smarter so the algorithm rejects them as invalid.

 

 

  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Mar 30, 2020 - 07:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

When I get an interrupt, I want to immediately disable the pin change interrupt enable bits to avoid bogus position updates

This is where you are gong wrong...you should write your routines assuming that the noise pulses WILL occur and generate interrupts.  In fact, you may not be able to turn them off in time anyhow, so you cant guarantee none will occur before your IRQ shutoff.

You might be better clearing any pending pinchange irq flags, before exiting your PC irq, though it is more robust if you make the irq smarter so the algorithm rejects them as invalid.

 

 

  

 

Very good idea. Each ISR should normally be called ALTERNATELY. If I see a pending bit from the ISR I'm in, then obviously it's bogus (most likely a bounce) and I need to clear (ignore) that flag.

 

Question: Say the encoder bounces 3 times, if I see the IRQ flag and clear it, will it come back 2 more times?

 

What I mean is, should I do this:

 

while (PCINT FLAG is set) {

    clear the flag bit;

}

 

Thanks for the answer and the idea!

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Say the encoder bounces 3 times, if I see the IRQ flag and clear it, will it come back 2 more times?

Of course, the 5th time will set it just like the first does.  clearing it, just allows another try to set it.   

You don't need to see the flag to clear it, you can just issue a clear.  For many AVR IRQ flags (not all, so see datasheet) writing a "1" clears the flag bit.

 

Having a smarter algorithm should check when it occurred and make some determination. 

 

Note that clearing pending irqs (flags) just before exiting the irq solves the issue of clearing "noise" interrupts that happened during the irq.  But it does not answer the question:

   When does an irq no longer represent noise &  instead becomes an irq you want to actually process?   Only you can determine that & is a critical part of your algorithm ("smarts") development.  

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Mon. Mar 30, 2020 - 07:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

If it is a twisty knob encoder vs a encoder on a motor or suchlike, why are you using external interrupts? What is the maximum pulse rate? Can this be satisfied by reading the inputs in a timer tick?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
why are you using external interrupts?
+1

 

The golden rule is "don't attach a "bouncy" input to an interrupt source"

 

You'd be far better off with a timer interrupt polling the input state if it#s subject to bounce. Take the usual precautions to filter any such bouncing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In #11 you say :

And since the encoder outputs gray code ......

That mean that the encoder has drivers, and then there is something VERY wrong with your HW if that bounce!!! 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
That mean that the encoder has drivers
Huh?  A bog-standard quadrature encoder outputs gray code naturally (i.e. only one bit changes with each step):

 

00

01

11

10

00

01

11

10

00

...etc.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok point taken

 

For me a gray encoder is one that give an absolute position with something more than 6 bit 

 

 A quadrature encoder I would call it that and never a gray encoder. 

 

But I we need OP to tell us :)  

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Each ISR should normally be called ALTERNATELY.

Sounds like a 2 bit quad encoder.

 

 Just use a state machine decode...it will not care about spurious inputs, since it can decide what inputs will be allowed to change states.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, rotary encoders don't bounce like push switches.  You'll get say 24 pin updates on a complete revolution of the shaft. 

Now when a turn of the rotary encoder triggers a pin-change interrupt, that IRQ should do nothing but set a volatile boolean flag that indicates that this particular pin-change interrupt occurred.   

The loop section of main() [often inside a while(1) statement]  checks the volatile boolean flags for the various peripherals and sub-systems (like the rotary encoder).  When any of these flags are set, then main() calls the functions that deal with this flag (and clears the flag for the next interrupt on that sub-system).

And as to the original question, when the Timer1_CompareA IRQ happens, the Enable-Interrupt control bit is changed:the interrupts are disabled and will stay disabled until the Enable-Interrupt is restored to its state before the interrupt.  This re-enabling is done by the RETI  (return from interrupt) assembler instruction that ends compiled IRQs.   Calling blink() just puts the address of the next assembler instruction of the IRQ onto the stack, and puts this instruction into the program address (which is still in IRQ) when the blink() function ends.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

If it is a twisty knob encoder vs a encoder on a motor or suchlike, why are you using external interrupts? What is the maximum pulse rate? Can this be satisfied by reading the inputs in a timer tick?

 

No I can't. The primary interrupt (TIMER1_COMPA_vect) will be used to pump 8 bit values out to a port connected to an R-2R ladder to generate an analog waveform and the interrupt rate will be as high as 524288 interrupts per second. To generate a clean waveform, I can't have any other "running" interrupts because their ISRs will disable interrupts for their short time and "glitch" the analog waveform.

 

Anyway, I've been experimenting with the code and I found that clearing (actually setting) the interrupt flag bit helps a lot, but some bounces still get through.  The encoder decoder looks for specific bit patterns from the encoder, so it actually ignores most bounces.

 

But, if I don't clear the interrupt flag bit within the ISR and I "flick" the encoder knob (i.e. spin it really fast), it misses counts and sometimes even goes backwards!

 

Here's a piece of the code I've been working on:

 

 

ISR (PCINT0_vect)
{
    while (PCIFR & (1<<PCIF0)) {
        bounce++; // count how many times
        PCIFR |= (1<<PCIF0); // clear interrupt flag
    }
    updEncoder ();
}

void updEncoder (void)
{
    (ENC_INP & ENC_CLK) ? state |= (1<<2) : state &= ~(1<<2);
    (ENC_INP & ENC_DAT) ? state |= (1<<3) : state &= ~(1<<3);

    switch (state) {
        case 1:
        case 7:
        case 8:
        case 14: {
            encoderPosition++;
            break;
        }
        case 2:
        case 4:
        case 11:
        case 13: {
            encoderPosition--;
            break;
        }
        default: {
            break;
        }
    }

    state >>= 2;
}

 

See the "bounce" variable? With my "junk" encoder (a Chinese POS from Amazon), I get 3,5 to almost 20 bounce counts. With a good Grayhill optical encoder from DigiKey, I get zero bounce counts, no matter how fast I spin or "flick" the knob.

 

Of course, there's more code that's not seen here (to avoid clutter) but one of the things I have to do when I read the encoder is shut off interrupts (to make the read atomic) then take "position" and divide it by 4 because the junk encoder does 4 pulses per detent. Likewise, to set the position value, I multiply by 4 then set position (atomically also). Doing so glitches the output waveform, but that's OK because the encoder is just changing the analog output frequency (i.e. the TIMER1 rate).

 

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

In #11 you say :

And since the encoder outputs gray code ......

That mean that the encoder has drivers, and then there is something VERY wrong with your HW if that bounce!!! 

 

Gray code is a code where only 1 bit changes at a time. There are no "electronics" in the encoder. It just pulls one pin or the other to common.

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Each ISR should normally be called ALTERNATELY.

Sounds like a 2 bit quad encoder.

 

 Just use a state machine decode...it will not care about spurious inputs, since it can decide what inputs will be allowed to change states.

 

You're right, and since I'm now using a pin change interrupt (and both are in the same "block" of 0...7), there is only 1 ISR. But as you said, the state machine ignores invalid codes (as I could tell by temporarily sticking a "printf" into the default case which should never get called if only good codes go in).

 

My optical encoder never hits "default". The junk one does - a LOT.

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

ok point taken

 

For me a gray encoder is one that give an absolute position with something more than 6 bit 

 

 A quadrature encoder I would call it that and never a gray encoder. 

 

But I we need OP to tell us :)  

 

I said the encoder outputs gray code. I never called it a "gray encoder". wink

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, of course a dumb 2 bit knob will pump out plenty of spurious edges (just turn the knob verrrrry slowly & see).  Of course, that is exactly why it is made to pump out gray code  (00 01 11 10 00 01 11 10...), so you are able to completely ignore the spurries in your state sequencer decode.  00 then 01 00 01 00 01 then 11 01  11 01 11 01 11 then 10 11 10 ignores all the red and looks for the next needed state.

 

Forget doing that knob stuff in the IRQ...turning the knob is slow as dirt.  A state machine sequence detector in main can easily keep up with the edge sequence & know that you are turning your knob.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which AVR do you use. And speed ( 524288 HZ ISR's sound a bit fast for C)

 

Many of the new AVR have 2 level ISR's.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

Which AVR do you use. And speed ( 524288 HZ ISR's sound a bit fast for C)

 

Many of the new AVR have 2 level ISR's.

 

The testing is being done on a MEGA2560 at 22.1184 MHz. but the final project will run on a 1284p at 24.0 MHz.

 

The 2560 easily handles 500k/sec timer interrupts. 

 

BTW, you mentioned "2 level ISRs".  What is that?

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Forget doing that knob stuff in the IRQ...turning the knob is slow as dirt.  A state machine sequence detector in main can easily keep up with the edge sequence & know that you are turning your knob.

 

I suppose the encoder could just be read at regular intervals... and then there would be no need to worry about extra unwanted interrupts due to bounce. I'll experiment with that tomorrow.

 

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The AVR's you use have a flat ISR structure (1 level) meaning that no ISR can interrupt an other interrupt (unless you force it).

 

XMEGA's and newer AVR's that are based on same design have a 2 level structure, meaning that some ISR's can have high priority so they by nature can interrupt when in a low priority interrupt.

 

 

Are you sure that your 1284p can run 24MHz ?

It's one of the few AVR's that don't over clock well (Actually it's picky about the voltage at 16MHz, I guess it's the added RAM that is the problem)

Last Edited: Fri. Apr 3, 2020 - 11:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

(1) The AVR's you use have a flat ISR structure (1 level) meaning that no ISR can interrupt an other interrupt (unless you force it).

 

XMEGA's and newer AVR's that are based on same design have a 2 level structure, meaning that some ISR's can have high priority so they by nature can interrupt when in a low priority interrupt.

 

 

(2) Are you sure that your 1284p can run 24MHz ?

It's one of the few AVR's that don't over clock well (Actually it's picky about the voltage at 16MHz, I guess it's the added RAM that is the problem)

 

(1) Thanks for the explanation. I looked at an XMEGA datasheet and saw what you mean.

 

(2) Yes it runs fine at 24.0 MHz (full swing oscillator). In fact, it ran fine at 32.0 (that was just a test - I won't run it that fast!)

 

Lastly, based on all the suggestions not to use an interrrupt (as well as having one of those "on the verge of falling asleep" insights), I came up with this code which uses no interrupts and counts perfectly:

 

int16_t updEncoder (void)
{
    uint8_t n;
    uint8_t clk;
    uint8_t dat;

    n = 100; // debounce counter

    while (n--) {
        clk = (ENC_INP & ENC_CLK); // read clock pin (PINB bit 4)
        dat = (ENC_INP & ENC_DAT); // read data pin (PINB bit 5)
        // mismatch if either bounced
        if (clk != (ENC_INP & ENC_CLK) || dat != (ENC_INP & ENC_DAT)) {
            n = 100; // reset debounce counter
        }
    }

    if (!clk) {
        arm = 1; // re-arm if clock low
    }

    if (clk && arm) { // if clock high and armed
        arm = 0; // disarm
        encoderPosition += dat ? 1 : -1; // increment or decrement the position
    }

    return encoderPosition;
}

 

It works fine and doesn't miss any counts no matter how fast I spin the knob. And the debounce works (I put a temporary counter where the debounce count is reloaded and I saw between 1 bounce and 25 bounces).

 

Here's how I tested it:

while (1) {
    newval = updEncoder();
    if (newval != oldval) {
        oldval = newval;
        LCD.setCursor (0, 0);
        printf ("POSITION: %5d\n", newval);
    }
}

 

BTW, all the vars are ints (int16_t).

 

Any criticisms or critiques or comments welcomed.

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

100 loops at 24MHz is how long? This will vary depending of the interrupt rate of your other code. Use another timer and test the interrupt flag to get a consistent timebase. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

100 loops at 24MHz is how long? This will vary depending of the interrupt rate of your other code. Use another timer and test the interrupt flag to get a consistent timebase. 

 

Sorry, I don't understand what you are trying to say. The 100 tests may be a lot more, depending on how much bounce I get  Every bounce RESETS the counter... there must be 100 consecutive "good reads" in order for the thing to finish. Note that the code posted above uses no interrupts at all.  

 

Or am I missing the point?

 

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The 100 looping probably does little for you (doing: was there no mismatching for 100 tries in a very short unknown time)?

 

What really makes it work is the sudo-state machine you set up thereafter.  A state machine is what you need...it inherently eliminates (by preventing the reaction to) the effects of bounce.  Having that settling prefilter offers dubious, if any, benefit --if you have the proper state machine setup.

 

The only time you might need a prefilter is if both lines were bouncing at the same time...which by the electromechanical design of the encoder should be an impossibility.  The state machine relies on only one line being able to bounce at a time...that is the whole point of using gray code.

 

some "sudo code"

if mystate=="A" and pins=01:
     mystate="B"
elif mystate="B" and pins=11:
     mystate="C"
elif mystate="C" and pins=10:
     mystate="D"
elif mystate="D" and pins=00:
     mystate="A"
     forward_count++

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Apr 4, 2020 - 03:52 AM