Das ist ein Programm wie aus dem Lehrbuch.
Aus dem Und-so-schon-gar-nicht-Kapitel.
Das kann gar nicht funktionieren.
1 | ISR (TIMER1_CAPT_vect)
|
2 | {
|
3 | ADMUX |= (1<<MUX0);
|
4 | ADCSRA |= (1<<ADSC);
|
5 | while (ADCSRA & (1<<ADSC));
|
6 | ADC1 = ADC;
|
7 | ADMUX &=~ (1<<MUX0);
|
8 | }
|
Was passiert da?
while (ADCSRA & (1<<ADSC));
Du lässt deinen Controller in einer ISR warten, bis das langsamste Teil
auf demselben, mit seiner Arbeit fertig ist. 13 x 128 = 1664 Takte.
In einer ISR, die alle 1600 Takte aufgerufen wird. Und zwischendurch
soll er noch einen weiteren Interrupt bedienen. Das schafft nicht mal
die 100GHz-32-Core-mit-Hyperthreading-und-1000-Terabyte-RAM-Granate
unter deinem Schreibtisch.
Ich gehöre auch nicht zu den ISR-so-kurz-wie-möglich-Dogmatikern, die
Flags setzen und dann 2 Ports in der main schalten. Kleinigkeiten kann
man auch gleich an Ort und Stelle erledigen. Und ein bisschen rechnen
ist auch OK.
AAAAAABER in einer ISR warten, bis ein verschissener AD-Wandler mit
seiner verschissenen Wandlung fertig ist, ist nicht das Allerletzte
sondern noch Lichtjahre darüber hinaus.
Du schreibst jetzt tausend mal: "In einer ISR wird nicht gewartet. Und
schon gar nicht auf verschissene AD-Wandler".
Verlassen wir den technisch sachlichen Teil.
Dein Programm ist recht ausführlich kommentiert. Aber die Kommentare
sind sowas von überflüssig.
1 | usart_init (); // USART initialisieren
|
Also ich hätte jetzt glatt gedacht, damit wird eine LED zum blinken
gebracht. Aber da steht ja Gott sei Dank "USART initialisieren" hinter.
Lass solche überflüssigen Kommentare. Das ist jedem klar, was die
Funktion machen soll. Und deine Oma versteht das Programm auch mit
Kommentar nicht. Und wer es versteht, für den liest sich das schwerer
als mit ohne.
Deine Interrupt-Konstruktionen: Das ist nun auch nicht gerade das gelbe
vom Ei. Wenn du einen Interrupt nicht brauchst, schalte ihn ab.
Deine Funktionen: Funktionen sind notwendig. Alles, was man mehr als
einmal benötigt, kommt in eine Funktion. Alles, was über mehr als eine
Bildschirmseite geht, könnte man, der Übersichtlichkeit halber, in ein
paar Funtionen aufteilen. Natürlich nur, wenn das auch sinnvoll ist.
Manchmal geht es aber auch nicht. Dann ist das eben so.
Aber man kann es auch übertreiben. Eine Funktion, die einen Mittelwert
ermittelt, welch ein Audruck, kann diesen auch gleich fertig verpackt
und verschnürt zurück liefern. Da muss man nicht noch eine weitere
Funktion aufrufen, die den Wert erst noch durch 10 teilt.
Und wenn man die OCR-Register neu schreibt, kann man das auch direkt
tun. Es hindert dich niemand daran, den Registern Aliasnamen zu geben.
1 | #define PWM1 OCR1A //definiere PWM1 als OCR1A
|
2 | #define PWM2 OCR1B //definiere PWM2 als OCR1B
|
Hatte ich das mit den bescheuerten Kommentaren schon geschrieben?
Mittelwert: So macht man das nicht. Erstmal teilt man das nicht durch
10. Sondern durch 8 oder 16. Da muss der Controller nämlich nicht
rechnen, sondern nur um 3 oder 4 Bit nach rechts verschieben. Das kann
ein AVR zwar auch nicht besonders gut. Aber immer noch besser als
dividieren.
Und dann nimmt man nicht n Werte auf, addiert die und teilt sie dann
durch n, sondern man nimmt einen Wert und liefert sofort den Mittelwert.
???
Man schreibt die einzelen Werte in ein Array von der Größe n.
Dann subtrahiert man den ältesten Wert von der Mittelwertsumme und
addiert den neuesten, teilt durch n und ab dafür. Die ersten n-1 Werte
liegen natürlich daneben. Aber das geht schnell vorbei.
Wenn du mit dem tausend mal "In einer ISR..."-Schreiben fertig bist,
guckst du dir in deinem C-Buch an, wie man Funktionen einsetzt, wie man
Parameter übergibt und was Rückgabewerte sind. Und dann noch, wie oft
oder besser wie selten, man globale Variablen benutzt.
Warum bist du eigentlich von den 25Hz auf 10KHz gegangen. Also ich und
wahrscheinlich jeder andere auch, hätte erstmal 50, 100, 200 Hz und so
weiter probiert.
mfg.