Forum: Mikrocontroller und Digitale Elektronik ATmega8 / Radio Gaga / Poti->ADC->TimerCTC-> Lautsprecher


von Tho W. (tommyprog)


Angehängte Dateien:

Lesenswert?

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
von doppelschwarz (Gast)


Lesenswert?

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.

von Tho W. (tommyprog)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Tho W. (tommyprog)


Lesenswert?

> 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.

von Tho W. (tommyprog)


Angehängte Dateien:

Lesenswert?

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
von Dietrich L. (dietrichl)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von Bastler (Gast)


Lesenswert?

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.

von Tho W. (tommyprog)


Lesenswert?

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
Noch kein Account? Hier anmelden.