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
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
> 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 | > #define ADCSR_DEFINED 0b10101011 |
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
:
Bearbeitet durch User
Tho Wes schrieb: > Potti Ich sehen, Du hast meinen Hinweis (http://www.thetford-europe.com/de/product/porta-po...) wohl nicht verstanden: das Ding heißt "Poti" als Kurzform von Potentiometer ... Gruß Dietrich
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_t tmp = 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.
:
Bearbeitet durch User
Der ADC kann das /4 aber auch selbst. Man kann das Ergebnis linksbündig in ADC einstellen lassen, dann sind die oberen 8 Bit schlicht ADCH. Dazu:
1 | ADMUX |= (1<<ADLAR); |
um "Left Adjust" einzuschalten.
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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.