I have written a simple program
It uses a timed interrupt to update a variable n, n represents how many seconds have elapsed
In the main while loop I want to generate a square wave output with an on time of 120 seconds and an off time of 120 seconds
the interrupt simple fires every second to update the count
I started with this code
#include <avr/io.h>
#include <avr/interrupt.h>
volatile int n; // n is a global variable updated in timed interrupt to represent time
void Setup_Timer(void);
int main(void)
{
DDRB|= 0x1F; // Data direction register B = 0b 0001 1111 = 1 (set PB0..PB5 as output)
Setup_Timer();
while(1)
{
}
}
ISR(TIMER1_COMPA_vect)
{
PORTB ^= 0x04;
n=n+1;
if(n>=240)
{
n=0;
}
}
void Setup_Timer(void)
{
TCCR1B|= (1<<WGM12); // Timer 1 CTC mode (clear on timer compare)
TIMSK1|= (1<<OCIE1A); // Output compare interrupt enable
sei(); // Enable global interuppts
OCR1A = 3905; // CTC compare value 0.5 Hz @1MHz CPU with 256 Prescale
TCCR1B|=(1<<CS12); //Start timer 1 control register B Prescale value of 256 (CS12 bit =1) (if prescale of 1 then Timer clock=cpu clock) see pg 137 ATMega 328p datasheet
}
And if I measure PB2 pin it is high for one second and then low for one second (the EXOR operator inverts the pin state) which is really easy to understand
I then add a simple piece of code (in bold) to give me the 120 second high and 120 second low on PB0
#include <avr/io.h>
#include <avr/interrupt.h>
volatile int n; // n is a global variable updated in timed interrupt to represent time
void Setup_Timer(void);
int main(void)
{
DDRB|= 0x1F; // Data direction register B = 0b 0001 1111 = 1 (set PB0..PB5 as output)
Setup_Timer();
while(1)
{
if(n<120){
PORTB |=0x01;
}
else {
PORTB &=0xFE;
}
}
}
ISR(TIMER1_COMPA_vect)
{
PORTB ^= 0x04;
n=n+1;
if(n>=240)
{
n=0;
}
}
void Setup_Timer(void)
{
TCCR1B|= (1<<WGM12); // Timer 1 CTC mode (clear on timer compare)
TIMSK1|= (1<<OCIE1A); // Output compare interrupt enable
sei(); // Enable global interuppts
OCR1A = 3905; // CTC compare value 0.5 Hz @1MHz CPU with 256 Prescale
TCCR1B|=(1<<CS12); //Start timer 1 control register B Prescale value of 256 (CS12 bit =1) (if prescale of 1 then Timer clock=cpu clock) see pg 137 ATMega 328p datasheet
}
The 120 second high/low does seem to be working however this is affecting the PB2 output and instead of the 1 second high/low the state of the pin glitches
I immediately thought its a problem with the logic but after going through it I can not see a problem, the EXOR should still invert the state of the pin but for some reason it (sometimes) isnt working right
Looking at it it is such a simple piece of code yet I can't figure out how
PORTB |=0x01; can have an effect on
PORTB ^= 0x04;
PORTB |=0x01 this should OR 0000 0001 with XXXX XXXX which leads to XXXX XXX1
i.e PB0 is set high no matter if it was low or high previously
PORTB ^= 0x04; this should EXOR 0000 0100 with XXXX XXXX which leads to XXXX X/XXX
(/X) means not X!
So only bit 3 should change
Any help is much appreciated