A small problem with Input Capture on Timer 1 using Atmega16

Discussion in 'Embedded Systems and Microcontrollers' started by johndo, Sep 12, 2009.

  1. johndo

    Thread Starter New Member

    Sep 12, 2009

    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.

    Code ( (Unknown Language)):
    1. #include <avr/io.h>
    2. #include <avr/interrupt.h>
    3. #include <util/delay.h>
    4. #include "lcd.h"
    6. #define F_CPU 12000000UL
    8. // Define Global Variables here
    9. int NUMBER = 0;
    10. unsigned char i;
    12. // Define Function Prototypes here
    13. int welcome();
    14. int numberLCD(int NUMBER);
    16. int main(void)
    17. {
    19. // Initialize the LCD
    22. //Clear the screen    
    23. LCDClear();
    25. welcome(); // Welcome the user to the device
    27. sei(); // Enable Global Interrupts
    29. TIMSK = 0x22; // Allows input capture, enables Timer 0 COMPA interrupt
    30. TCCR1A = 0x00;
    31. TCCR1B = 0x41; // Enable leading edge input capture, prescaler = 1
    32. TCCR0 = 0xA; // Enable CTC interrupts, prescaler = 8
    33. OCR0 = 30; // 25khz pulse with duty cycle at 50% for square pulse
    34. DDRD |= (1 << PD5); // Set bit 5 as output
    36. while(1)
    37. {
    38. }
    40. return 0;
    41. }
    43. ISR(TIMER1_CAPT_vect)
    44. {
    45. // Capture Interrupt Routine
    46. NUMBER++;
    47. numberLCD(NUMBER);
    48. }
    50. ISR(TIMER0_COMP_vect)
    51. {
    52. // Compare Match Interrupt Routine
    53. PORTD ^= 0x20; // Toggle PD5
    55. }
    57. int welcome()
    58. {
    59.    // Simple string printing
    60.    LCDWriteString("Welcome! ");
    62.    // Delay to show text
    63.    for(i=0;i<125;i++) _delay_loop_2(0);
    65.    // Clear the screen
    66.    LCDClear();
    68.    return 0;
    69. }
    72. int numberLCD(int NUMBER)
    73. {
    74.    LCDWriteString("Number:");
    76.    // Print the current number with a field length of 3
    77.    LCDWriteIntXY(10,0,NUMBER,3);
    79.    for(i=0;i<30;i++) _delay_loop_2(0);
    81.    // LCDClear();
    82.    return 0;
    83. }
    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: Sep 15, 2009
  2. hgmjr

    Retired Moderator

    Jan 28, 2005
    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.

  3. hgmjr

    Retired Moderator

    Jan 28, 2005
    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.


  4. johndo

    Thread Starter New Member

    Sep 12, 2009
    thanks mate
  5. hgmjr

    Retired Moderator

    Jan 28, 2005
    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?