0
votes

I am trying to set up one interrupt and one counter/timer. The interrupt is external, reading low logic from pin. Timer should increment every 100 us and add up to count variable. I've set up the interrupt, which is working fine however, after setting up a timer, neither interrupt nor timer works. The code is such:

volatile boolean allowCount = false, timerFlag = false;
volatile unsigned int counter;
boolean pulseLow = false;


void setup(){

Serial.begin(9600);

// initialize external pin interrupt.
PCICR =  0b00000010; // 1. PCIE1: Pin Change Interrupt Enable 1
EICRA |= bit (ISC10);    // set wanted flags (low logic level causes interrupt)
PCMSK1 = 0b00010000; // Enable Pin Change Interrupt for  A4


// TODO Interrupt settings not working together


// initialize Timer1
cli();          // disable global interrupts
TCCR1A = 0;     // set entire TCCR1A register to 0
TCCR1B = 0;     // same for TCCR1B

// set compare match register to desired timer count:
OCR1A = 0x18;
// turn on CTC mode:
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 64 prescaler:
TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS11);
// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);


}

void loop(){
    if (allowCount == true)
    {   timer100_uS();

        if (counter > 50 && pulseLow == false){
            DDRC |= (1 << DDC3 ); // sets bit DDC3 to 1 within register DDRC        
            //set pin 3(A3) ouput as sourcing Vcc(HIGH)
            PORTC |= (1 << PORTC3);
            timerReset();
            pulseLow = true;
        }
        if (pulseLow == true){
            timer100_uS();
            if (counter >= 500){
                //set pin3 of port C to LOW (A3);
                PORTC &= ~(1 << PORTC3); 
                pulseLow = false
                timerReset();
        }

    }
// external pin interrupt
ISR(PCINT1_vect){
    if (allowCount == false)
    allowCount = true;
}
// timer/counter interrupt
ISR (TIMER1_COMPA_vect)
{
    if (timerFlag == true){
        counter++;
    }
}

void timer_100uS(void){
    timerFlag = true;
    cli();
}

void timerReset(void){
    sei();
    timerFlag = false;
    counter = 0;
}

Value of OCR0A is calculated to be 24 (0x18) with prescaler 64 and 16 MHz processor based on this formula:

OCRn =  [ (clock_speed / Prescaler_value) * Desired_time_in_Seconds ] - 1

How to set up different interrupts so that they don't overlap eachother ? Or better yet, is it possible to set up timer so that it does not use interrupt ? Thanks for reading !

2
just dont set the interrupt enable in the timers control register yes? and then poll the status register(s) to see if the timer has done whatever you were waiting for it to do. - old_timer
can you use them separately only do one thing or the other but not both, does the interrupt work for each situation? what is the source of your external interrupt (a button or a signal from some other device)? If a button how are you dealing with bounce? - old_timer
@old_timer How would reading timer/counter value from status register look ? counterValue = SREG ? External interrupt reads zero crossing analog signal, it works every time. - flowian
a few seconds looking at the manual there is an interrupt flag register for tc0 and tc1 you simply read them and the description from the manual determines when the are set. and the manual implies you can simply write them to clear. usually a write one to clear is used for such registers, but each vendor/designer is different. - old_timer
looks like the external interrupts have an interrupt flag register as well. Now I have not dug out an avr to try all of this that is your job. sometimes there are status registers that only reflect interrupts that are enabled, and that is very common, but some processors dont have another enable layer and that one level causes interrupts in the processor. sometimes not, depends on the chip vendor, design, etc. ideally there is another layer and in the core or closer to it is another layer you can poll and clear without actually interrupting. but you have to sort that out for this chip. - old_timer

2 Answers

0
votes

As I can see, you are using ATMega328 with Arduino libraries. Your problem is that Arduino library internally uses Timer 1 for its internal purposes. Therefore if you add your own interrupt handler for Timer 1, you override Arduino's interrupt handler for Timer 1 which breaks the library.

If you want to stay with Arduino library, use the library also to control the timer: Arduino Timer1

0
votes

Thank you for answers @old_timer, @klasyc. Quite late, but I solved it by using timer0 instead of timer1 with following settings in setup:

// initialize external pin interrupt.
PCICR =  0b00000010; // 1. PCIE1: Pin Change Interrupt Enable 1
EICRA |= bit (ISC10);    // set wanted flags (falling edge causes interrupt)
PCMSK1 = 0b00001000; // Enable Pin Change Interrupt for A3

TCCR0B = 0;
TCCR0A = 0;
//set CTC mode
TCCR0A = ( 1 << WGM01 );

// set OCR0A value for 1 us counter (OCRxn = (freq/prescaler)*desired_value)-1
OCR0A = 15;

// set compare match counter
TIMSK0 |= (1 << OCIE0A);


//set prescaler
TCCR0B |= ( 1 << CS00);

and outside the loop:

ISR(TIMER0_COMPA_vect){
  counter++;
}