#include <ioavr.h>
#include <inavr.h>
#define FOSC 16000000UL
#define N 8
volatile uint16_t ovfs;
volatile uint8_t state;
void setup_PE4_input();
void setup_INT4();
void setup_timer3();
void start_timer3();
void stop_timer3();
uint32_t timer3_freq;
// daca primesc semnal pe MB4 CS
// MB4CS = PE4
// PE4 = INT4
// folosesc timer3 pentru a masura
#pragma vector TIMER3_COMPA_vect
__interrupt TIMER3_COMPA_ISR(void){
// nu e nevoie sa setez tcnt3 pe 0 pentru ca oricum urmeaza sa dea overflow si reset aici
ovfs++;
}
#pragma vector INT4_vect
__interrupt INT4_vect_ISR(void){
uint8_t current_signal_edge = ((PINE & (1<<PE4)) !=0);
if(current_signal_edge == 0 ){
return;
} // vreau peak to peak
if(state == 0){
start_timer3();
state = 1;
}
else if(state == 1){
stop_timer3();
state = 2;
}
}
int main(){
setup_PE4_input();
setup_timer3();
setup_INT4();
__enable_interrupt();
while(1){
if(state == 2){
__disable_interrupt();
uint32_t current_ticks = TCNT3;
uint16_t current_OCR3A = OCR3A;
uint32_t total_ticks = (ovfs*(current_OCR3A+1UL)) + current_ticks;
uint32_t ticks_per_second = FOSC/N;
uint32_t F_SIG_hz = ticks_per_second / total_ticks;
TCNT3 = 0;
ovfs = 0;
state = 0;
__enable_interrupt();
}
}
return 0;
}
void setup_PE4_input(){
DDRE &= ~(1<<PE4);
PORTE |= (1<<PE4); // pullup
}
void setup_INT4(){
EIMSK |= (1<<INT4);
EICRB |= (1<<ISC40); // any logical input generates an input req
}
void setup_timer3(){
uint8_t SREG_cpy = SREG;
__disable_interrupt();
TCNT3 = 0;
uint32_t new_OCR3A = FOSC/(1000UL*N) - 1;
OCR3A = (uint16_t)(new_OCR3A); // compare match la fiecare msec
timer3_freq = (FOSC / N) / (new_OCR3A + 1);
// CTC mode 4 with TOP = OCR3A
TCCR3B |= (1<<WGM32);
// OVF overflow -- match cu OCR3A
TIMSK3 |= (1<<OCIE3A);
SREG = SREG_cpy;
}
void start_timer3(){
uint8_t SREG_cpy = SREG;
__disable_interrupt();
// prescaler 8
TCCR3B |= (1<<CS31);
SREG = SREG_cpy;
}
void stop_timer3(){
uint8_t SREG_cpy = SREG;
__disable_interrupt();
// prescaler 8 -- STOP
TCCR3B &= ~((1<<CS32) | (1<<CS31) | (1<<CS30));
SREG = SREG_cpy;
}