I am using an ATMEGA88 running at 8.192 Mhz and I'm having difficulties with making a basic frequency counter.
I'm using a 555 timer to create fairly low frequency signals (0 to 1000 Hz). Unfortunately, I'm unable to get this to work.
Here is my code:
#include#include #include #include #define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) #define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT)) #define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT)) #define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT)) //8.192 MHz xtal #define F_CPU 8192000 //Define functions //====================== static int uart_putchar(char c, FILE *stream); static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); //====================== #define BAUD 9600 #define MYUBRR (F_CPU/16/BAUD-1) volatile unsigned int pulses = 0; volatile unsigned long long int overflow1 = 0; volatile unsigned int overflow0 = 0; void ioinit (void) { //USART Baud rate: 9600 // This simply sets the baud rate to 9600. // UBRR0H / L is an 8-bit register, so we need to treat it like a 16-bit UBRR0H = MYUBRR >> 8; UBRR0L = MYUBRR; UCSR0B = (1<<RXEN0)|(1<<TXEN0); // Enable Receiving / Transmission stdout = &mystdout; //Required for printf init } static int uart_putchar(char c, FILE *stream) { if (c == '\n') uart_putchar('\r', stream); loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = c; return 0; } int uart_putnum(uint16_t num) { // Accepts upto 8 bytes unsigned char c[8]; for(int i = 0; i<8; ++i) { itoa(num, (char*)c, 10); if(c[i] == '\0' || c[i] == ' ') break; loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = c[i]; } return 0; } ISR(TIMER1_CAPT_vect) { pulses++; } ISR(TIMER1_OVF_vect) { pulses = 0; overflow1++; } ISR(TIMER0_OVF_vect) { overflow0++; } uint8_t uart_getchar(void) { while( !(UCSR0A & (1<<RXC0)) ); return(UDR0); } int main(void) { ioinit(); printf("Test\n"); DDRB = 0b11111110; // PORTB output DDRD = 0x00; // PIND input PORTB = 0xFF; // Turn off all LEDs // Timer1: Counter // Timer0: Timer TCCR0B = (1<< CS02); //F_CPU/256 Prescaler TIMSK0 = (1 << TOIE0); // Enable overflow interrupt TCNT0 = 0; TIMSK1 = (1 << TOIE1) | (1 << ICIE1); // Enable overflow interrupt TCNT1 = 0; //Noise canceller, without prescaler, rising edge TCCR1B = 1 << CS10 | 1 << ICNC1 | 1 << ICES1; sei(); CLEARBIT(PORTB, 5); for (;;) { if(overflow0 >= 125) { cli(); uart_putnum(pulses + overflow1*65536); printf("\n"); overflow0 = 0; overflow1 = 0; TCNT0 = TCNT1 = 0; ICR1 = 0; pulses = 0; sei(); } } return 0; }
Timer 0 is an 8-bit timer running with a prescaler of 256.
I am using the 16-bit Timer1 (no prescaler) with the input capture unit.
My thoughts were that if timer0 overflows 125 times that would be 1 second. The number of pulses counted by the input capture unit would then give me the frequency.
Unfortunately I have tried this for a few different frequencies and it doesn't seem to work.
For 65 Hz frequency I get 0
For 2.8 Hz frequency I get 0
For ~650 Hz I get ~5 Hz
Unfortunately I don't have any instruments to verify that the 555 timer is given anything close to the ideal output frequency, but I am using an LED to see the lower frequencies (2.8, 10 Hz etc)
Does anyone see what I am doing incorrectly with my code?