Servus zusammen,
folgendes Problem.
hab von nen myAVR Lehrbuch das "Radio gaga" nachprogrammieren wollen,
aber es gibt in der Software probleme.
Es wird wie folgt realisiert:
Poti_2 (analog) --> AD_wandler (analog zu digital --> Konvertierung von
10Bit ADC in 8 bit ADC mithilfe von right-shift Operatoren (sprich
bildlich 2 Bits in 8 bits "reinschieben") ----Wert für Timer--> Timer2
im CTC Modus, der bis zu diesen Wert zählt--> Timer2 schaltet über
interrupt Lautsprecher ein (toggelt)
zu hören ist ein ton der selben sehr hohen Frequenz, ein drehen am
POTI_2 Bringt nichts.
Der Code ist im Anhang.
Mehrere Vermutungen, was den Fehler betrifft:
- Prescaler vom AD und Prescaler vom Timer2 müssen vlt. gleich sein?
- Verschiebungen nicht korrekt? Wobei ich davon ausgehe, dass die
Reihenfolge so stimmt
- ADMUX Register falsch bestimmt
Könnte bitte jemand über den Code schauen?
Es wurde bereits im Thread
Beitrag "Ton mit Atmega8 erzeugen"
ein ähnliches Problem behandelt. Bei mir funktioniert allerdings die
Ausgabe an den Lautsprecher und scheinbar die Konvertierung oder
Wertzuweisung des ADCs an den OCR nicht richtig.
Danke schonmal im Voraus.
Mfg,
TommyProg
Tho Wes schrieb:> Verschiebungen nicht korrekt? Wobei ich davon ausgehe, dass die> Reihenfolge so stimmt
Hier sehe ich mindestens einen Fehler, denn Du schiebst zwar die Werte
(leider falsch), aber verbindest nicht High mit Low:
> ADCH_erste_verschiebung=(1>>ADCH);
Hier schiebst Du die 1 um den Wert von ADCH nach rechts, Du willst es
eigentlich andersherum:
ADCH_erste_verschiebung=(ADCH >> 1); // schiebt ADCH um eine Stelle nach
rechts
Zur fehlenden Verknüpfung: Du musst die Zahl, die beim Schieben von ADCH
rausgeschoben wird, in ADCL reinschieben, das geht nicht automatisch.
Hier kurz der einfache Weg über eine 16-Bit-Variable:
volatile uint16_t ADC_zwischenspeicher; // 16 Bit große Variable
volatile uint16_t ADC_zwischenspeicher2; // 16 Bit große Variable
ADC_zwischenspeicher = (ADCH << 8) + ADCL; // schiebt High um 8 nach
links und addiert Low, vergleichbar wie aus 5 und 3 wird 53
ADC_zwischenspeicher2 = ADC_zwischenspeicher >> 2; // schiebt 2 mal nach
rechts
ADC = (uint8_t)ADC_zwischenspeicher2; // typecast, macht aus 16 Bit
wieder eine 8-Bit-Zahl, es werden dabei die untersten 8 Bit genommen
Schau Dir am besten im Tutorial mal die Bitoperationen an, dann
verstehst Du es besser.
Weiter habe ich den Code nicht angeschaut.
doppelschwarz schrieb:> Tho Wes schrieb:>> Verschiebungen nicht korrekt? Wobei ich davon ausgehe, dass die>> Reihenfolge so stimmt>> Hier sehe ich mindestens einen Fehler, denn Du schiebst zwar die Werte> (leider falsch), aber verbindest nicht High mit Low:>> ADCH_erste_verschiebung=(1>>ADCH);> Hier schiebst Du die 1 um den Wert von ADCH nach rechts, Du willst es> eigentlich andersherum:> ADCH_erste_verschiebung=(ADCH >> 1); // schiebt ADCH um eine Stelle nach> rechts> Zur fehlenden Verknüpfung: Du musst die Zahl, die beim Schieben von ADCH> rausgeschoben wird, in ADCL reinschieben, das geht nicht automatisch.> Hier kurz der einfache Weg über eine 16-Bit-Variable:> volatile uint16_t ADC_zwischenspeicher; // 16 Bit große Variable> volatile uint16_t ADC_zwischenspeicher2; // 16 Bit große Variable> ADC_zwischenspeicher = (ADCH << 8) + ADCL; // schiebt High um 8 nach> links und addiert Low, vergleichbar wie aus 5 und 3 wird 53> ADC_zwischenspeicher2 = ADC_zwischenspeicher >> 2; // schiebt 2 mal nach> rechts> ADC = (uint8_t)ADC_zwischenspeicher2; // typecast, macht aus 16 Bit> wieder eine 8-Bit-Zahl, es werden dabei die untersten 8 Bit genommen>> Schau Dir am besten im Tutorial mal die Bitoperationen an, dann> verstehst Du es besser.>> Weiter habe ich den Code nicht angeschaut.
Danke dir. Das ist wohl schon etwas her, aber ich versuchs dann morgen
mit nen neuen Code
Mfg,
tommyProg
doppelschwarz schrieb:> Zur fehlenden Verknüpfung: Du musst die Zahl, die beim Schieben von ADCH> rausgeschoben wird, in ADCL reinschieben, das geht nicht automatisch.> Hier kurz der einfache Weg über eine 16-Bit-Variable:> volatile uint16_t ADC_zwischenspeicher; // 16 Bit große Variable> volatile uint16_t ADC_zwischenspeicher2; // 16 Bit große Variable> ADC_zwischenspeicher = (ADCH << 8) + ADCL; // schiebt High um 8 nach> links und addiert Low, vergleichbar wie aus 5 und 3 wird 53> ADC_zwischenspeicher2 = ADC_zwischenspeicher >> 2; // schiebt 2 mal nach> rechts> ADC = (uint8_t)ADC_zwischenspeicher2; // typecast, macht aus 16 Bit> wieder eine 8-Bit-Zahl, es werden dabei die untersten 8 Bit genommen
es wäre viel einfacher, wenn er die Sache einfach seinem Compiler
überlässt, anstelle selbst zu schieben. Der Compiler weiss schon, dass
das ADC Ergebnisregister eigentlich aus 2 8 Bit Werten besteht und dass
die zu einem 16 Bit Wert miteinander verknüpft werden und wie man das
macht.
1
OCR2=ADC/4;
und fertig ist die Sache. ADC ist das (virtuelle) 16 Bit Ergebnis des
ADC. Den Rest macht der Compiler. Die ganzen 7 Millionen Hilfsvariablen
und sonstigen Schnickschnack braucht kein Mensch.
1
ISR(ANA_COMP_vect)
genau. Der Interrupt Vector heisst irgendwas mit COMP wie 'Comperator',
weil da das Ergebnis vom Analog Digital Wandler vorliegt und nicht vom
Comperator.
So was
1
#define ADCSR_DEFINED 0b10101011
kontrollier nicht mal ich mehr. So masochistisch bin ich nicht mehr,
dass ich mich da durch die Bits durchkämpfe. Schreibs ordentlich, so
dass man zur Kontrolle nicht Scroll-Orgien im Datenblatt braucht, dann
a) kontrolliert das auch wer
b) machst du weniger Fehler
> Schau Dir am besten im Tutorial mal die Bitoperationen an, dann> verstehst Du es besser.
Und wenn du schon dabei bist:
Im AVR-GCC-Tutorial gibt es auch vernünftige ADC Routinen, die
auch ttsächlich funktionieren. In vernünftiger Schreibweise. ADC
Interrupt braucht nämlich in diesem Beispiel auch kein Mensch (so wie in
mehr als 80% aller anderen Beispiele, in denen der ADC zum Einsatz
kommt). So schnell kannst du gar nicht an deinem Poti drehen, dass der
Mega das nicht auch ohne Interrupt mitkriegen würde. Zumindest den
Fehler mit dem falschen Interrupt Vektor hättest du dir damit locker
erspart.
> es wäre viel einfacher, wenn er die Sache einfach seinem Compiler> überlässt, anstelle selbst zu schieben. Der Compiler weiss schon, dass> das ADC Ergebnisregister eigentlich aus 2 8 Bit Werten besteht und dass> die zu einem 16 Bit Wert miteinander verknüpft werden und wie man das> macht.
Okay, gut zu wissen^^.
> So was>
1
>#defineADCSR_DEFINED0b10101011
2
>
> a) kontrolliert das auch wer> b) machst du weniger Fehler
Hab jetzt meinen Programmierstil geändert, und benutze nun die "(1<<XX)
Variante. Da hast du recht, das erspart einen die Datenblattsuche etwas
mehr.
> Und wenn du schon dabei bist:> Im AVR-GCC-Tutorial gibt es auch vernünftige ADC Routinen, die> auch ttsächlich funktionieren. In vernünftiger Schreibweise. ADC> Interrupt braucht nämlich in diesem Beispiel auch kein Mensch (so wie in> mehr als 80% aller anderen Beispiele, in denen der ADC zum Einsatz> kommt). So schnell kannst du gar nicht an deinem Poti drehen, dass der> Mega das nicht auch ohne Interrupt mitkriegen würde. Zumindest den> Fehler mit dem falschen Interrupt Vektor hättest du dir damit locker> erspart.
Merci auch für den Tipp.
Heinz, danke dir nochmals für den Tipp mit den "/4" "konvertieren".
Hab deine Methode benutzt, und läuft sauber(bis auf ein kleines Problem,
vlt. von mir)
Meiner eigenen Interesse wollte ich es auch mit shiften ausprobieren,
somit ist das auch im Code.
Mein Problem ist, dass ich bei einer sehr hohen Frequenz (LAUTSPRECHER,
falls irgendjemand hier im Forum was dazu sagen sollte! xD),
trotz drehen des Pottis nach rechts, keine niedrigen Frequenzen mehr
hören kann.
"Das Potti hängt sich so gesehen auf". Unter Atmel Studio 6 auf "Apply"
beim DEvice einlesen, reicht ein klick, dass ich wieder in Ruhe drehen
kann.
Dieses Problem ist bei einer niedrigeren Frequenz nichtmehr STARK
vorhanden.
Während man am Potti dreht, braucht das Blinken immer eine sehr kurze
Weile.
Vermute, entweder, dass der Timer schuld ist, oder ich irgendwo noch
mein ISR- Management verbessern muss.
Liege ich da richtig?
ADC- Wert Randbedingungen ahbe ich mit eingebaut, jedoch ist das Problem
nicht gelöst.
Mfg,
tommyProg
Tho Wes schrieb:> ADC- Wert Randbedingungen ahbe ich mit eingebaut,
Nein hast du nicht.
Dein Check Funktion macht de facto überhaupt nichts.
Wie soll denn der korrigierte Wert aus der Funktion rauskommen?
C Grundlagen!
Argumente an Funktionen übergeben. Rückgabewerte.
Und zersplittere dein Programm nicht so dermassen heftig in Funktionen.
Man kann alles übertreiben und dann dreht sich der Effekt um. Übertreibt
man es mit den Funktionen, wird das Eergebnis nicht übersichtlicher
sondern unübersichtlicher. Du hast den Punkt schon lange überschritten,
wo du dir ein ganz einfaches Programm so aufgebläht hast, dass man ohne
heftiges Scrollen nichts mehr sieht.
Was ist an
1
ISR(ADC_vect)//Interrupt, wenn der AD- Wandler fertig ist
2
{
3
uint8_ttmp=ADC/4;
4
5
if(tmp<2)
6
tmp=2;
7
8
OCR2=tmp;
9
}
schlimm?
Eben. Gar nichts. Das muss man nicht in 2 Funktionshierarchien
einbetten.
Danke euch beiden.
Das haut zwar nicht genau so hin, also ich muss die Grenzen nicht bei
der 2 sondern bei der 4 machen, aber es geht dann.
Mfg,
TommyProg