A small problem with Input Capture on Timer 1 using Atmega16

Thread Starter

johndo

Joined Sep 12, 2009
2
Hello,

I've made myself a small project that simply counts up by 1 from a starting number of 0.

I'm using Input Capture from Timer 1, and generating a square wave on Timer 0 since the input capture is edge triggered.

My problem is that when I plug the battery in, it shows the LCD 'welcome screen' just fine and then it starts counting up. Like this:

Number: 000 --> Number: 001 --> Number: 002

My problem is that this is a input capture interrupt, it should not trigger at all and not count up unless there is a edge triggered signal in the ICP pin (PD6). So in other words I'm expecting the LCD to simply blink the cursor by default if there is no input at PD6. Like this:
# <-- This is the flashing cursor on an empty LCD

In Timer 0 I've created a 25 khz square wave signal that is also run under interrupt. This signal comes out of PD5 and under my expectation UNLESS this signal via a wire is connected to PD6 the LCD should not count up and remain at the cursor as shown above.

However from testing this is what I'm getting:

1) Upon connecting the battery it shows the welcome screen on the LCD and starts counting up by itself, even when there is no wire connected to PD6!

2) So I then make a wire connection from PD5 to PD6 (the ICP pin). The LCD still continues to count up.

3) I then remove the connection and the LCD stops counting. EG:

Number: 020 --> Number: 020 --> Number: 020

4) If I make a connection between PD6 and PD5 once more it then starts counting like:

Number: 021 --> Number: 022 --> Number: 023

5) And if I remove the wire connection it stops counting up and stays at the same number and etc...

I've included my code here, so can anyone please tell me where I'm going wrong because I'd like it to not count at all *unless* a signal via PD5 is sent to PD6 (ICP pin) that is carrying the edge triggered square wave.

Rich (BB code):
#include <avr/io.h> 
#include <avr/interrupt.h> 
#include <util/delay.h> 
#include "lcd.h" 
 
#define F_CPU 12000000UL 
 
// Define Global Variables here 
int NUMBER = 0; 
unsigned char i; 
 
// Define Function Prototypes here 
int welcome(); 
int numberLCD(int NUMBER); 
 
int main(void) 
{ 
 
// Initialize the LCD 
InitLCD(LS_BLINK|LS_ULINE); 
 
//Clear the screen    
LCDClear(); 
 
welcome(); // Welcome the user to the device 
 
sei(); // Enable Global Interrupts 
 
TIMSK = 0x22; // Allows input capture, enables Timer 0 COMPA interrupt 
TCCR1A = 0x00; 
TCCR1B = 0x41; // Enable leading edge input capture, prescaler = 1 
TCCR0 = 0xA; // Enable CTC interrupts, prescaler = 8 
OCR0 = 30; // 25khz pulse with duty cycle at 50% for square pulse 
DDRD |= (1 << PD5); // Set bit 5 as output 
 
while(1) 
{ 
} 
 
return 0; 
} 
 
ISR(TIMER1_CAPT_vect) 
{ 
// Capture Interrupt Routine 
NUMBER++; 
numberLCD(NUMBER); 
} 
 
ISR(TIMER0_COMP_vect) 
{ 
// Compare Match Interrupt Routine 
PORTD ^= 0x20; // Toggle PD5 
 
} 
 
int welcome() 
{ 
   // Simple string printing 
   LCDWriteString("Welcome! "); 
 
   // Delay to show text 
   for(i=0;i<125;i++) _delay_loop_2(0); 
 
   // Clear the screen 
   LCDClear(); 
 
   return 0; 
} 
 
 
int numberLCD(int NUMBER) 
{ 
   LCDWriteString("Number:"); 
 
   // Print the current number with a field length of 3 
   LCDWriteIntXY(10,0,NUMBER,3); 
 
   for(i=0;i<30;i++) _delay_loop_2(0); 
 
   // LCDClear(); 
   return 0; 
}
Also by the way the signal generated at PD5 is large enough in volts as it goes through some amplification. Oh yeah and im using atmega32.

thanks everyone

PS: I made a post related to the receiver hanging.
 
Last edited:

hgmjr

Joined Jan 28, 2005
9,027
I have a few recommendations that you can consider.

First, I would move the sei(); enable global interrupts instruction to just prior to the entry into your while(1) forever loop. It is safer not to enable the interrupt system until you have completed setting up the various interrupt resources you plan to use in your program.

Second, I would not use Input Capture as your interrupt to be triggered by your edge from the 25 KHz square wave from PD5. I would use INT0 or INT1 as the trigger signal input and set up the interrupt for whichever of these you choose to use.

Third, It is a good idea to avoid invoking a function from within an interrupt service routine, especially one that implements a delay such as your numberLCD() function does. The amount of time spent in the servicing of an interrupt reduces the frequency with which that interrupt service routine can be executed. Perhaps you could call your numberLCD() function from your while(1) loop instead. Of course that will mean that you will be updating the LCD all the time but that should not cause any harm.

Hope this helps you get closer to success with your program.

hgmjr
 

hgmjr

Joined Jan 28, 2005
9,027
Below highlighted in red are some code change suggestions. I did not try to compile the code so there may be an error or two but from your code so far I detect that you are no stranger to programming AVR micros in C-language.

hgmjr

Hello,

Rich (BB code):
#include <avr/io.h> 
#include <avr/interrupt.h> 
#include <util/delay.h> 
#include "lcd.h" 
 
#define F_CPU 12000000UL 
 
// Define Global Variables here 
int NUMBER = 0; 
unsigned char i; 
 
// Define Function Prototypes here 
int welcome(); 
int numberLCD(int NUMBER); 
 
int main(void) 
{ 
 
// Initialize the LCD 
InitLCD(LS_BLINK|LS_ULINE); 
 
//Clear the screen    
LCDClear(); 
 
welcome(); // Welcome the user to the device 
 
TIMSK = 0x02; // enables Timer 0 COMPA interrupt 
TCCR1A = 0x00; 
TCCR1B = 0x00; 
TCCR0 = 0xA; // Enable CTC interrupts, prescaler = 8 
OCR0 = 30; // 25khz pulse with duty cycle at 50% for square pulse 
DDRD |= (1 << PD5); // Set bit 5 as output 
 
GICR = (1<<INT0);  // Enable INT0 interrupts...
MCUCR |= (1<<ISC01) | (1<<ISC00); // Set interrupt on rising edge of INT0...
 
TIFR |= TIFR;  // Clear any pending interrupt flags...
 
sei(); // Enable Global Interrupts 
 
while(1) 
{ 
numberLCD(NUMBER); // Moved from its location in the ISR 
} 
 
return 0; 
} 
 
ISR(INT0_vect) 
{ 
// External Interrupt input 0...
NUMBER++; 
} 
 
ISR(TIMER0_COMP_vect) 
{ 
// Compare Match Interrupt Routine 
PORTD ^= 0x20; // Toggle PD5 
 
} 
 
int welcome() 
{ 
   // Simple string printing 
   LCDWriteString("Welcome! "); 
 
   // Delay to show text 
   for(i=0;i<125;i++) _delay_loop_2(0); 
 
   // Clear the screen 
   LCDClear(); 
 
   return 0; 
} 
 
 
int numberLCD(int NUMBER) 
{ 
   LCDWriteString("Number:"); 
 
   // Print the current number with a field length of 3 
   LCDWriteIntXY(10,0,NUMBER,3); 
 
   for(i=0;i<30;i++) _delay_loop_2(0); 
 
   // LCDClear(); 
   return 0; 
}
 

hgmjr

Joined Jan 28, 2005
9,027
thanks mate
I assume that you solved your problem. Can you tell us for the sake of future similar issues what you had to do to get it to work?

Can you post your final operating code so that others may learn from your experience?

hgmjr
 
Top