Hier ist ein einfaches Frequenzmessgerät für Arduino bis 33kHz.
Da nicht jeder einen Frequenzgenerator hat, ist dieser zu Testen bereits eingebaut ![]()
Dann muss Pin 3 und Pin 4 verbunden werden.
// ______________________________________________________________________________________________
// ______________________________________________________________________________________________
//
// Frequenzgenerator + Frequenzmessgerät bis 33 kHz
//
// (C) Helmut Weber 2/2015
//
//
// Für Fortgeschrittene:
//
// An Pin 3 wird die Zeit / Frequenz eines externen Rechtecksignals gemessen
// Da nicht jeder über einen Frequenzgenerator verfügt, wird in einer vom Timer-1 angesteuerten
// Interrupt Routine eine Rechteckfrequenz an Pin 4 erzeugt.
// Es müssen dann Pin 4 (Sender) und Pin 3 (Empfänger) verbunden werden.
//
// Natürlich können an Pin 3 auch externe Frequenzquellen angschlossen werden
//
// Ergebnis: Periodendauer / Frequenzmesser 20 Hz - 33 kHz
// ______________________________________________________________________________________________
// ______________________________________________________________________________________________
// Anzahl der Messungen für Genauigkeit
// Für Frequenzen unter 1000 Hz entsprechend herabsetzen:
#define SAMPLES 1000
// Makros zum Setzen, Löschen / Testen von Bits
// ______________________________________________________________________________________________
// set bit
static inline void BIT_SET(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline));
static inline void BIT_SET(volatile uint8_t *target, uint8_t bit){
*target |= (1<<bit);
};
// clear bit
static inline void BIT_CLEAR(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline));
static inline void BIT_CLEAR(volatile uint8_t *target, uint8_t bit){
*target &= ~(1<<bit);
};
// test bit
static inline bool BIT_TEST(volatile uint8_t *target, uint8_t bit) __attribute__((always_inline));
static inline bool BIT_TEST(volatile uint8_t *target, uint8_t bit){
return(*target & (1<<bit));
};
// ______________________________________________________________________________________________
// Globale Variable
bool lastPin3=true; // Grundzustand: Taste an Pin 3 NICHT gedrückt
unsigned long lastChange3Time=micros();
unsigned long Period=micros();
// ______________________________________________________________________________________________
//Timer Interrupt Routine
// Wird entsprechend der eingestellten Zeit in SETUP
// zyklisch aufgerufen und toggelt Ausgabe an Pin 4
// Es ist gewissermaßen ein eigenes Programm.
ISR(TIMER1_COMPA_vect,ISR_NAKED)
{
//digitalWrite(4, !digitalRead(4));
if (BIT_TEST(&PORTD,4)) BIT_CLEAR(&PORTD,4);
else BIT_SET (&PORTD,4);
asm(" reti");
}
// ______________________________________________________________________________________________
// Interrupt Routine:
// Wird bei jedem Wechsel an Pin 3 aufgerufen, egal was das Hauptprogramm (LOOP) gerade
// macht. Es ist sozusagen ein eigenes Programm.
unsigned long m;
unsigned int lp;
unsigned long per;
ISR( PCINT2_vect) { // wird bei jeder Änderung am Pin 3 aufgerufen
//SAVE_CONTEXT; // bei kleinen Programmen organisiert der Compiler das
BIT_SET(&PORTB,1);
m=micros(); // Aktuelle Zeit in Mikrosekunden
per+=(m - lastChange3Time);
lp++;
if (lp==SAMPLES) {
Period=per; // SAMPLES-fache Periodendauer
lp=0; per=0;
}
lastChange3Time=m; // Sichern von dieser Zeit
BIT_CLEAR(&PORTB,1);
//RESTORE_CONTEXT;
//asm("reti");
}
// ______________________________________________________________________________________________
// Aufruf einmalig am Programm-Start:
void setup() {
Serial.begin(115200);
pinMode(4,OUTPUT); // Für Frequenzgenerator
pinMode(9,OUTPUT);
pinMode(3,INPUT_PULLUP);
// ============================================
// Timer 1 einrichten = Frequenz-Generator:
// Setup Timer1 IRQ für Pulse an Pin 4
// ============================================
cli();
TIMSK1 = (1 << OCIE1A);
TCCR1A = 0;
TCCR1B = (1 << WGM12 ) ; // Configure timer 1 for CTC mode
TCCR1B |= (( 1 << CS11 )); // Prescaler=8 => 500ns
// 20 Hz
//OCR1A = 49999; // 20 Hz
// 1000 Hz
//OCR1A = 999; // 1000 Hz
// 5000 Hz
//OCR1A = 199; // 5000 Hz
// 10000 Hz
//OCR1A = 99; // 10000 Hz (alle 50us 1 Interrupt!)
// 20000 Hz
OCR1A = 49; // 20000 Hz (alle 25us 1 Interrupt!)
// 20000 Hz
//OCR1A = 29; // 33333 Hz (alle 15us 1 Interrupt!)
sei();
// ============================================
// Eingang Pin 3 Interrupt einrichten
cli(); // Interrupt verbieten
PCICR |= 1<< PCIE2; // Interrupt für Pins an Port D erlauben
PCMSK2 |= 1<< PCINT19; // zusätzlich Pins auswählen: Interrupt für Pin 3 erlauben
sei(); // Interrupt erlauben
Serial.println("\n\nStart:");
}
// ______________________________________________________________________________________________
// Wird immer wieder neu aufgerufen = Hauptprogramm
float Freq;
void loop() {
unsigned long p;
float fp;
p=Period;
if (p>0) {
Serial.print("Perioden-Dauer(us): ");
fp=(float) 2.0*p/SAMPLES;
Serial.print(fp);
Freq=(1000000.0 / fp);
Serial.print(" Frequenz: ");
Serial.println(Freq);
}
Period=0;
delay(1000);
}