More Interrupt Madness

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

I have designed a test box utilizing an ATMEGA2560 with several 4-digit 7-segment displays, 2 encoders, switches, etc.  I have the display scanning and updating routines and encoders functioning.  I originally had the encoders serviced by an ISR from INT0, but am trying to separate it out and poll it in MAIN instead.  This was due to display flicker when spinning the encoder. 

 

I have moved the encoder routine into MAIN and am attempting to poll the interrupt flag for INT0, update some variables, and display the results, then clear the INT0 flag.  I have been banging my head on the wall for several days and just cannot see the evil of my ways in this routine.  I have attached the MAIN loop for reference and am hoping you experts can set me straight.  All thoughts are appreciated - thanks!

int main(void){
	
setup();	// Initialize peripherals, setup ports and parameters.

	while(1){
		
		if (INTF0){
				
			if ((FREQ_DIR == 0) && (freq_setting >= 10)){			// If count >= 10, increment x10.
				freq_setting += 10;
				}else if ((FREQ_DIR == 0) && (freq_setting < 10)){		// If count < 10, increment x1.
				freq_setting ++;
			}

			if ((FREQ_DIR != 0) && (freq_setting <= 10)){			// If count <= 10, decrement x1.
				freq_setting --;
				}else if ((FREQ_DIR != 0) && (freq_setting > 10)){		// If count > 10, decrement x10.
				freq_setting -= 10;
			}

			if (freq_setting < FREQ_MIN){			// Set lower limit of frequency range:
				freq_setting = FREQ_MIN;
				}else if (freq_setting > FREQ_MAX){		// Set upper limit of frequency range:
				freq_setting = FREQ_MAX;
			}
				update_freq_timer();	// Check range and adjust prescaler if necessary.
				Update_Displays();		// Refresh frequency display digits.
				EIFR = (1 << INTF0);	// Clear interrupt flag for INT0.
					
				}else{
				freq_setting = freq_setting;
				}
								
	}
	
}

 

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

Full of things not defined in the code you showed so the rest of us can only guess even if you know what they are!

 

But you can't just do :

if (INTF0){

INTF0 is a bit number between 0 and 7 so that says something like:

if (3){

if INTF0 happens to be 0 then none of the code that follows will ever run (or even be built). If it's 1..7 then that just says:

if (true){

so always executes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
if (INTF0)

What do you think this is doing?  I'm guessing INTF0 is a bit position, defined as 0.

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

Thanks clawson - my apologies for not posting more of the code, but there are over 550 lines and I didn't want to overwhelm everyone.

 

Sooo. . .

 

What is the proper way to check the INT0 flag for (true) and clear it in this routine?  I have been all over the internet looking for answers, but surprisingly, I'm not finding anything that helps.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
if (EIFR & (1<<INTF0))

This ANDs EIFR with a bit mask that has a '1' in the INTF0 bit position.  The condition will be true if INTF0 is set.

 

EDIT: You're clearing the flag correctly, by writing a '1' into the INTF0 bit position.  But as a general rule, I like to clear such flags much earlier in the code, like in the first line.

Last Edited: Fri. Sep 29, 2017 - 04:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

That was it kk6gm!  That simple change was all it needed to run.  Obviously, I was trying to read the INT0 flag bit completely wrong and it was never entering the IF statement.  Makes sense.  Are there other ways to check the flag bit?  Thanks for your help.

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

C permits an infinite number of ways to do any operation (I'm sure that Turing or Dykstra or one of the CS gods proved this!). What were you looking for? Easy to write? Easy to read? Easy to maintain? Efficient? Something else? (the line already given does the job!)

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

Schlepper wrote:

That was it kk6gm!  That simple change was all it needed to run.  Obviously, I was trying to read the INT0 flag bit completely wrong and it was never entering the IF statement.  Makes sense.

Funny that you applied the 1<<INTF0 paradigm correctly later in your code.  Anyway, glad you got it working.

 

Quote:
Are there other ways to check the flag bit?  Thanks for your help.

I'll answer a different question, which is "Is there a more standard way to do this?"  That "more standard" way is to set a flag (declared as 'volatile') in the ISR, and then poll (and clear) that flag in your background code, exactly like you polled for the INTF0 flag.  This gives the added flexibility of being able to run some short and time-critical code in the ISR itself, while off-loading longer code into the background (via the flag set/test).  In your example, I'd guess that all your freq_setting code could happily live in the ISR, and only the update and display-related code could be pushed into the background.  Give that a try and see if your display stops flickering.

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

LOL - Very well stated clawson.  I guess I always like to look at options when programming.  Now I still have to figure out why the displays flicker a bit when turning the encoders fast.  Just as a general question, what is the proper way to keep your encoder read routine from affecting your display scanning routine during adjustments?  I have my displays being multiplexed by a timer ISR routine giving them priority while the encoders are polled, but there is still interaction.  I know this is probably way too general a question.  Any thoughts would be appreciated - thanks.

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

In your example, I'd guess that all your freq_setting code could happily live in the ISR, and only the update and display-related code could be pushed into the background.  Give that a try and see if your display stops flickering.

 

Hmmmm. . . interesting.  My ISR for the display scanning is quite large, maybe that's where I'm getting into trouble.  I know my encoder routines worked beautifully in there respective ISR's.  I think I'll give your suggestion a try kk6gm.  You guys ROCK!

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

Schlepper wrote:

My ISR for the display scanning is quite large, maybe that's where I'm getting into trouble.

"...quite large..." This will cause you grief 99% of the time.  Live by this rule and you'll have much less trouble: Inside the ISR, short and sweet.  Any other interrupt-related code, set a flag and do the code in the background.  Also keep in mind that display code is the least time-critical code in most applications.  It's more important that the device run properly, even if the user has to wait another 10ms for an updated display.

Last Edited: Fri. Sep 29, 2017 - 10:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now I still have to figure out why the displays flicker a bit when turning the encoders fast.

Isn't that the answer to your question...or do you mean something else by "flicker"...As mentioned, always keep your ISR code short an sweet...if the flicker is due to a lot of different values being displayed, you could simply update the display less often, say once a second, regardless of how fast the values are changing.  You could take an average of the values so that they are displayed in a"less jumpy" output.  If the flicker is due to the actual running of the segments, ensure that you enable or disable each segment only as needed (versus clearing all segments, then lighting the needed ones).  Refreshing the segments too slowly can cause it too---so ensure you are never "waiting" for encoder pulses.

When in the dark remember-the future looks brighter than ever.

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

Thank you gentlemen, this is excellent info.  With some tuning and code shuffling I have the displays running flicker-free and the encoders performing smoothly.  Thanks again for the help!