Also die Hardware läuft jetzt fehlerfrei.
Jetzt gibt nur noch in der Software ein paar Probleme.
Hab mal den Basic-Code von http://home.arcor.de/output/elektronik/5ton-AVR.pdf versucht zu verwenden; klappt "eigentlich" auch. "Eigentlich" deswegen, weil die erkannte Frequenz nicht mit der wirklichen übereinstimmt.
Im angefügten Code muss ich von den #defines für FTONx noch etwas abziehen, damits stimmt.
Also werden z.B. 1060 Hz gesendet, werden diese als ca. 1040 erkannt; bzw. ich muss 1080 senden, damit 1060 erkannt werden.
Evtl ne Idee dazu? Ich denk mal, dass diese zusätzliche Zeit einfach dadurch zustande kommt, dass die ISR ja erst mal aufgerufen werden muss etc.
EDIT: Mal wieder den Code vergessen:
Code:
// µC: ATMega8
// Takt: 8MHz intern
// Pwr: 5 VDC
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include "glob_type.h" // Datentypen ui8_t, ui16_t, etc.
#define FTON1 1060 -20
#define FTON2 1160 -20
#define FTON3 1270 -20
#define FTON4 1400 -20
#define FTON5 1530 -23
#define FTON6 1670 -25
#define FTON7 1830 -25
#define FTON8 2000 -25
#define FTON9 2200 -25
#define FTON0 2400 -30
#define FTONR 2600 -30
#define VSF_IS_NEW (statusflags & 0x01)
#define VSF_IS_VALID (statusflags & 0x02)
#define VSF_IS_GOTOMAIN (statusflags & 0x04)
#define VSF_SET_VALNEW() (statusflags |= 0x01)
#define VSF_SET_VALOLD() (statusflags &= ~0x01)
#define VSF_SET_GOTOMAIN() (statusflags |= 0x04)
#define VSF_CLR_GOTOMAIN() (statusflags &= ~0x04)
#define VSF_SET_VALID() (statusflags |= 0x02)
#define VSF_SET_INVALID() (statusflags &= ~0x02)
#define TIMEOUT_MAX_VALUE 40 // Max. Timeout-Zyklen
#define AVG_VALUES 15 // Anzahl Werte für Durchschnittsbildung
ui32_t lgFreq; // "Rohfrequenz" nach 1. Berechnung
ui32_t lgFreqSum; // Summe für Durchschnittswert-Bildung
volatile ui16_t T1Value; // Gemessener Zählwert von T1 bei Signal an INT0
ui16_t freqs[AVG_VALUES]; // Array für Mittelwertbildung
ui16_t freq_avg; // Durchschnittsfrequenz
ui16_t fBorderLo;
ui16_t fBorderHi;
ui8_t TimeOut; // Timeout-Variable
volatile ui8_t statusflags; // Enthält Status-Bits (Value status flags, VSF):
// Bit 0: Neuer Messwert per INT0 eingegangen
// Bit 1: Messwert ungültig (max. Zähldauer überschritten)
// Bit 2: "Goto Main"-Ersatz
ui8_t Sequence[5]; // enthält empfangene Sequenz
ui8_t SeqCnt; // Anzahl Töne in Sequenz
ui8_t Tone; // Aktuell korrekt erkannter Ton
ui8_t Tone_Old; // Zuletzt korrekt erkannter Ton
ui8_t icnt; // allg. Zählvariable
int main(void)
{
// einige Pins von PortC als Ausgang für Status-LEDs:
DDRC |= (1 << PC0) | (1 << PC1) | (1 << PC2) | (1 << PC3) | (1 << PC4) | (1 << PC5);
DDRB |= (1 << PB1) | (1 << PB2) | (1 << PB3) | (1 << PB4) | (1 << PB5);
// Timer 1 setzen
TCCR1A = 0; // Standard Timer
TCCR1B = (1 << CS10); // Prescaler 1
TCNT1 = 0; // Startwert 0
TIMSK |= TOIE1; // Interrupt für Überlauf aktiv
// INT0 auf steigender Flanke
GICR |= (1 << INT0);
MCUCR |= (1 << ISC01) | (1 << ISC00);
// Interrupts global zulassen
sei();
// ************************************************************************************************
// MAIN LOOP START
// ************************************************************************************************
PORTC = (1 << PC5); _delay_ms(100); PORTC = 0;
PORTC = (1 << PC4); _delay_ms(100); PORTC = 0;
PORTC = (1 << PC3); _delay_ms(100); PORTC = 0;
PORTC = (1 << PC2); _delay_ms(100); PORTC = 0;
PORTC = (1 << PC1); _delay_ms(100); PORTC = 0;
PORTC = (1 << PC0); _delay_ms(100); PORTC = 0;
PORTB = (1 << PB5); _delay_ms(100); PORTB = 0;
PORTB = (1 << PB4); _delay_ms(100); PORTB = 0;
PORTB = (1 << PB3); _delay_ms(100); PORTB = 0;
PORTB = (1 << PB2); _delay_ms(100); PORTB = 0;
PORTB = (1 << PB1); _delay_ms(100); PORTB = 0;
while(1)
{
VSF_CLR_GOTOMAIN();
_delay_ms(1); // kleine Pause
// Prüfen, ob T1Value in sinnvollem Bereich liegt:
// 800 Hz => T1Value = 10000
// 3000 Hz => T1Value = 2666
if ((VSF_IS_VALID) && (VSF_IS_NEW))
{
if ((T1Value > 10000) || (T1Value < 2666))
{
// Wenn Wert ausserhalb: ungültig:
VSF_SET_INVALID();
}
}
// Folgendes nur, wenn: Wert gültig + in sinnvollem Bereich
if ((VSF_IS_VALID) && (VSF_IS_NEW))
{
if (T1Value != 0) { lgFreq = F_CPU / T1Value;} // "Rohfrequenz" berechnen
T1Value = 1; // Worst Case: Division durch 0 verhindern.
TimeOut++;
if (TimeOut >= TIMEOUT_MAX_VALUE)
{
memset(Sequence, 0x00, 5);
Tone_Old = 0;
TimeOut = 0;
SeqCnt = 0;
PORTB = 0;
PORTC = 0;
}
// Wertearray weiterschieben; ältesten Wert verwerfen
for (icnt = AVG_VALUES-1 ; icnt > 0 ; icnt--)
{
freqs[icnt] = freqs[icnt-1];
}
// Errechnete Frequenz in Array ablegen
freqs[0] = (ui16_t) lgFreq;
// Durchschnitt berechnen
lgFreqSum = 0;
for (icnt = 0 ; icnt < AVG_VALUES ; icnt++)
{
lgFreqSum += freqs[icnt];
}
freq_avg = lgFreqSum / AVG_VALUES;
// Überprüfen, ob Durchschnitt "gehalten" wird
fBorderLo = ((ui16_t) lgFreq) - 10;
fBorderHi = ((ui16_t) lgFreq) + 10;
if ((freq_avg > fBorderLo-1) && (freq_avg < fBorderHi+1))
{
Tone = 0;
if ((freq_avg > FTON1 - 10 ) && (freq_avg < FTON1 + 10)) { Tone = '1'; }
else if ((freq_avg > FTON2 - 10 ) && (freq_avg < FTON2 + 10)) { Tone = '2'; }
else if ((freq_avg > FTON3 - 10 ) && (freq_avg < FTON3 + 10)) { Tone = '3'; }
else if ((freq_avg > FTON4 - 10 ) && (freq_avg < FTON4 + 10)) { Tone = '4'; }
else if ((freq_avg > FTON5 - 10 ) && (freq_avg < FTON5 + 10)) { Tone = '5'; }
else if ((freq_avg > FTON6 - 10 ) && (freq_avg < FTON6 + 10)) { Tone = '6'; }
else if ((freq_avg > FTON7 - 10 ) && (freq_avg < FTON7 + 10)) { Tone = '7'; }
else if ((freq_avg > FTON8 - 10 ) && (freq_avg < FTON8 + 10)) { Tone = '8'; }
else if ((freq_avg > FTON9 - 10 ) && (freq_avg < FTON9 + 10)) { Tone = '9'; }
else if ((freq_avg > FTON0 - 10 ) && (freq_avg < FTON0 + 10)) { Tone = '0'; }
else if ((freq_avg > FTONR - 10 ) && (freq_avg < FTONR + 10)) { Tone = 'R'; }
else
{ VSF_SET_GOTOMAIN(); }
}
else
{
VSF_SET_GOTOMAIN();
}
if (!VSF_IS_GOTOMAIN)
{
switch (Tone)
{
case '1':
PORTB = 0;
PORTC = (1 << PC5);
break;
case '2':
PORTB = 0;
PORTC = (1 << PC4);
break;
case '3':
PORTB = 0;
PORTC = (1 << PC3);
break;
case '4':
PORTB = 0;
PORTC = (1 << PC2);
break;
case '5':
PORTB = 0;
PORTC = (1 << PC1);
break;
case '6':
PORTB = 0;
PORTC = (1 << PC0;
break;
case '7':
PORTB = (1 << PB5);
PORTC = 0;
break;
case '8':
PORTB = (1 << PB4);
PORTC = 0;
break;
case '9':
PORTB = (1 << PB3);
PORTC = 0;
break;
case '0':
PORTB = (1 << PB2);
PORTC = 0;
break;
case 'R':
PORTB = (1 << PB1);
PORTC = 0;
break;
default:
PORTB = 0;
PORTC = 0;
}
}
// Wert abgearbeitet und damit alt:
VSF_SET_VALOLD();
}
}
// ************************************************************************************************
// MAIN LOOP ENDE
// ************************************************************************************************
return(0);
}
ISR (SIG_OVERFLOW1) // Interrupt Timer 1 Überlauf
{
//Letzter Impuls liegt zu lange zurück => Wert verwerfen/ungültig
VSF_SET_INVALID();
}
ISR (SIG_INTERRUPT0)
{
T1Value = TCNT1; // Wert sichern
VSF_SET_VALID(); // Wert gültig
VSF_SET_VALNEW(); // Neuer Wert
TCNT1 = 0; // Timer zurücksetzen
}
Lesezeichen