mikrocontroller.net

Forum: Compiler & IDEs Timer und ADC bei Atmega16 mit WinAVR


Autor: L0rd (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen !

Ich habe C Code geschrieben, der eigenlich in AVR Studio macht was er 
soll nur Praktisch klappts halt nicht. Da ist irgendwo ein Wurm drin und 
ich such ihn schon seit 2 Tagen.

Ich benutze Atmega16 @ 16Mhz, Timer0 der ständig bei Overflow 
Einzelwandlung auf ADC anstösst dann wirds bisschen gerechnet und 
ausgegeben.

Bitte schaut mal drüber vielleicht fällt euch ja was auf, was ich nicht 
sehe.

Dnake !

Autor: wulf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Probier statt ISR() einfach SIGNAL(SIG_OVERFLOW0) {}
das hat bei mir mal Probleme gemacht

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
L0rd wrote:

> Praktisch klappts halt nicht. Da ist irgendwo ein Wurm drin

Das ist ja mal ne super konkrete Fehlerbeschreibung, damit kann jeder 
was anfangen ?????

Du willst wohl keine Antworten ?

Ohne Fehlerbeschreibung gibts auch keine Hilfe.

Also, was wird erwartet und was passiert statt dessen ?


Peter

Autor: L0rd (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Tip !
aber, nö :(,
mit

SIGNAL (TIMER0_OVF_vect)
SIGNAL(SIG_OVERFLOW0)
ISR(TIMER0_OVF_vect)

getestet - kein Unterschied.

Ich weiss nicht in wieweit man AVR Studio trauen kann, aber dort springt 
er (wenn Timer0 zähler von FF -> 0 geht ) in ISR und dann ruft 
rechnung(); auf und startet AD-Wandlung.... halt alles wie es sein soll.

Ich vermute dass mit AD-Wandler was nicht stimmt, weil ich kann/weiss 
nicht wie man mit AVR Studio am ADC eingang ein Wert simulliert und
nach dem Auslesen x = ADCH; wird ADIF nicht zurück auf 0 gesetzt. Ist 
aber net schlimm weil bei nächsten AD Start wird er automatisch 
zurückgesetzt.


Autor: L0rd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Peter Dannegger

sorry, am PortC sollte was rauskommen, kommt aber nicht - bleibt seit 
Anschalten auf 0.

In Avr Studio kommt erste 2 Overflows am PortC was raus, eine Grosse 
Zahl ich schätze über 128 und dann bei 2tem durchlauf ne 4 oder so und 
bei nächsten durchläufen bleibt auf 0 stehen.
Sieht so aus als AD-Wandler keine Werte liefert, und die Formeln rechnen 
mit "0"-Werten seit Initialisierung und gehen dann irgendwann gegen "0".

Autor: Tommy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tach.

Das Problem liegt mit Sicherheit an deiner Reglerberechnung. Ist glaub 
ich ein I Regler. Nun verhält der sich so, dass er die Abweichung auf 
null versucht zu ziehen. Da du aber in der digitalen welt lebst fallen 
die Nachkommastellen unter den Tisch. Und so passierts, das bei großen 
Regelabweichungen dein Algo was berechnet, nach der dritten ist schluss 
da der Wert <1 wird.

Versuch den Regler so umzustricken dass er Ganzzahlen in ausreichender 
Größe erhält, oder benutze Float, wenn das Dynamik und Speicher 
zulasssen.

Autor: L0rd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ein PID Regler vin RN.

Die Gleichung habe ich nocht nicht simuliert, mach ich aber noch.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ATMega16 und PORTC? Da klingelts sofort: Hast Du das JTAG deaktiviert?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> #include <avr/iom16.h>
Mach das nicht. Die Device-spezifische Headerdatei wird nie direkt 
eingebunden! Immer nur die io.h und dann im Makefile oder im AVRStudio, 
je nachdem, womit Du arbeitest, den Controllertyp angeben.

Autor: L0rd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@johnny.m
JTAG, wäre schön, aber son Spielzeug hab ich nicht. Ich öffne .elf-Datei 
(was von Make All "übrig bleibt")in AVR Studio und sehe dann mein C-Code 
den ich durchklicken kann. Und links sehe ich dann I/O Pins und die 
ganzen Register und wie die gesetzt werden je nach dem wo ich im Code 
bin.

#include <avr/iom16.h> habe ich irgendwo abgeschaut und vorsichtshalber 
rein genommen. In Makefile gebe ich sowieso Atmega16 an und alles was 
ich weiss angegeben, denn ich bin kein Linux freak um das alles zu 
wiessen, man denkt automatisch wenn was anzugegeben ist, dann ist das 
vielleicht wichtig. In AVR Studio gebe ich natürlich Simulator und 
Atmega16 an, kommst nicht drum herum.

Jetzt ist es bisi spät,ich werde dann morgen mich sammeln und nen rar 
mit Makefile und sonstigen Dateien und noch paar Bilder und Schaltplan 
vielleicht hier hochladen. Damit alle sehen können was ich hier gebaut 
habe :)

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> JTAG, wäre schön, aber son Spielzeug hab ich nicht.
Eben deswegen musst Du es deaktivieren (Fuse JTAGEN). Diese Fuse ist im 
Auslieferungszustand des ATMega16 gesetzt und das JTAG-Interface 
blockiert die 4 mittleren Pins von PORTC (Pins 5...2). Du musst diese 
Fuse unbedingt löschen, um PORTC benutzen zu können!

Autor: L0rd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JTAGEN ist deaktiviert,
PortC habe ich schon mit Rampen (einfach ne schleife die hochzählt und 
dann wieder von 0 anfängt) getestet, um Linearität des DAC zu testetn.
War alles OK.

Autor: Tommy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

vielleicht steh ich mal wieder auf dem Schlauch? oder mein Freund Jim 
Beam ist noch nicht aussem Kopf, aber so wie ich das sehe, "erzeugt" die 
Berechnung den Ausgabewert für PortC (8-Bit Wert). Dann würde ich 
zunächst verifizieren ob fest einprogrammierte Werte (ohne Wandler) den 
von dir per Hand Berechneten Ausgabewert erzeugen.
Feste Eingabewerte erzeugen korrekten ausgabewert?
Ja --> Berechnung OK
Nein --> Berechnung überprüfen

Als Debughilfe vielleicht die RS232 anschmeißen!

Nochn Tip: Bei Regelungsalgos immer auf Überlauf kontrollieren, sonst 
undefiniertes Verhalten.

Autor: Tommy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sehs grad nich? Hast du den ADC Pin als Eingang geschaltet?

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Tommy:
Die DDRx- und PORTx-Register haben einen Reset-Wert von 0, also Eingang 
ohne Pull-Up. Sollte kein Problem sein.

BTW: Der ATMega16 hat die sehr komfortable Möglichkeit, den ADC 
automatisch zu starten, wenn ein bestimmtes Ereignis auftritt (ADC Auto 
Trigger). Das geht z.B. auch mit dem Overflow von Timer 0. Schau Dir mal 
die ADTS-Bits im SFIOR an. Die Auswertung würde man dann über den 
ADC-Conversion-Complete-Interrupt machen. Musst nur dran denken, das 
Flag vom Timer0-Overflow jeweils entweder von Hand zu löschen oder einen 
leeren Interrupt-Handler einzubauen, weil das ganze sonst nur einmal 
funktioniert.

Ansonsten: Ich bin die Berechnung jetzt nicht komplett durchgegangen, 
aber die Variable y, die an PORTC ausgegeben werden soll, ist ein int 
(16 Bit). Bist Du sicher, dass da was Sinnvolles rauskommt?

Noch was: Du löschst das ADIF nie. D.h., so wie es da steht, 
funktioniert das Ganze nach dem Reset genau einmal. Das ADIF muss, wenn 
Du den Interrupt nicht aktiviert hast, von Hand gelöscht werden! Wenn Du 
den ADC unbedingt per Polling abfragen willst (also ohne Interrupt), 
dann am besten nicht das ADIF abfragen, sondern das ADSC-Bit. Das wird 
nämlich nach Abschluss der Wandlung automatisch zurückgesetzt. Ich 
vermute, das ist der eigentliche Fehler und die Ursache, warum Müll 
rauskommt. Also anstatt
while(!(ADCSRA & (1 << ADIF)));
besser
while((ADCSRA & (1 << ADSC)));

Autor: L0rd (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ja, an SFIOR habe ich schon gedacht, aber ich bin nicht so mächtig in C, 
wird auf jedenfall ne Zeit brauchen.

y sollte warscheinlich in char konvertiert werden, bevor der ausgegeben 
wird. Bei x=0 kommt y=3,496 raus und das wird bestimmt nicht als 0b11 
dargestellt, wie ich anfangs gehofft habe. Wir schauen auf AD-Wandler, 
doch
es könnte gut mölich sein, dass es an diesen Nachkommastellen liegt.
Hm, laut dieser Seite
http://www.math.uni-bayreuth.de/~rbaier/lectures/j...
nen int in char umzuwandeln ist nicht möglich :(
Kennt jemand nen Trick um Nachkommastellen abzuschneiden und vielleicht 
sogar noch zu runden ?

ADIF hatte ich schon mal von Hand gelöscht, hat auch keine änderung 
gebracht. Ich habe hier oben glaube ich schon mal geschrieben, dass ADIF
wird im letzten Augenblick automatisch gelöscht, wenn Wandlung startet.

while((ADCSRA & (1 << ADSC))); habe ich eben ausprobiert - bleibt dunkel 
:)

ich hänge hier noch nen .zip mit Bildern, Skizzzen und Schaltplännen vom 
Projekt.

Autor: Tommy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn du nen int nach einen char castest, fallen automatisch die oberen 
8bit weg. Um sicher zu gehen kanns ja mal im disassembly nachschaun.

Nicht nur das Endergebnis ist nicht mit Nachkommastellen gesegnet, 
sondern auch alle zwischenergebnisse werden beschnitten.
(10/3)*3 == 9 !! als beispiel

Autor: Tommy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab mir mal die Zip reingezogen. Cooles Projekt um Regelungen zu 
erlernen.

Ein PID Regler für die Aufgabe anzuwerfen scheint mir etwas 
hochgegriffen (zumindest für den Anfang) Versuchs mit nem einfachen 
P-Regler, der die LED einfach um die Differenz der zwischen 230 und 
tatsächlichem Eingang hochregelt.

Die nachkommastellen sind eigentlich kein problem, einfach die Werte 
erhöhen (Grenzen beachten) und am ende runterteilen. So wird dann zb aus 
3,496 3496.
Wenn du änderungen um 3,irgendwas brauchst, musst du dir grundsätzliche 
Gedanken über die Auflösung deiner Hardware machen.

Autor: L0rd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abend !

@Tommy ja ich wollte nun mal von Anfang bis Ende ne Regelung aufbauen. 
Berechnet habe ich schon ein paar, doch nie eine Aufgebaut.
Und ich finde es kommisch, dass es zum Thema "wie realisiere ich nen 
digitalen Regler" fast gar nichts im Netz zu finden gibt. Nur das hier
http://www.roboternetz.de/wissen/index.php/Regelungstechnik
Ich habe Strecke "1.Ordnung mit kleiner Totzeit" eigentlich wegen 
RC-Glied, und auf dieser Seite steht, wieso ich kein P-Regler genommen 
habe.

habe mich mit AD-Wandler beschäftigt (getestet) und rausgefunden dass
das hier geht:
// AD Wandlung und Berechnung
void rechnung(void)
{
  // Wandlung starten (1<<ADSC), Einzel.Wandl.
    ADCSRA |= (1<<ADSC);

    // Warten bis die AD-Wandlung abgeschloßen ist
    while ( !(ADCSRA & (1<<ADIF)) );

  x = ADCW;// 10-bit Wert nach x laden
  x = ~x>>2; // nur 8-bit davon Verwenden
  // Berechnung Anfang
  //e = 230 - x;
  //y = (yalt + 152*e - 303*ealt + 152*ealtt) / 10000;    //Reglergleichung
  //ealtt = ealt;
  //ealt = e;
  //PORTC=y; //Ausgabe
  //yalt = y;
  // Berechnung Ende
  
  PORTC = x; // 8-bit Ausgeben
  ADCSRA |= (0<<ADIF); // geht auch ohne, aber sicher ist sicher.

}
hab einfach mit Poti Werte simulier und am PortC kammen dieselben raus.
Wenn ich auch noch Formel rein nehme da kann ich so viel an dem Poti 
drehen wie ich will, PortC bleibt immer auf 11111111

Also es ist dann Kommazahlen und vielleicht auch die Rechnung(Formel).

Es muss nen Trick geben wie man aus Komma- Ganzzahlen macht. Auch wenn 
es genau so viel wie die Formel dauert.
Es steht ne Gesamtzeit ca 120us zur Verfügung, wobei Rechnung dauert ca. 
27us die meiste Zeit warten wir sowieso auf Overflow.




Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> PortC bleibt immer auf 11111111

Das wundert mich aber.
Eine Excel Simulation zeigt, das deine reglergleichung
spätestens nach der 3. Iteration immer 0 erreicht hat.
3 Iterationen hat der µC in Windeseile durch.

Komma oder Fix Point haben damit nichts zu tun.
Deine 'Reglergleichung' ist einfach Mist.



Autor: L0rd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl heinz Buchegger

das kann man nur mit Mathlab/Simulink oder anderen Regelungstechnischen 
Programm testen. Denn das ist nur der Regler und der kriegt nicht immer 
"0" drauf, dahinten kommt ja noch die Strecke (LEDs und 
Fototransistoren) die das ganze noch verändern. Wenn übertragung z.B. 
1:1 ist dann sollte bei zweitem schrit x=2 sein und nicht "0" und das 
sollte ganz andere werte ergeben, als Iteration gegen "0".

Kannst du bitte vielleicht random werte zwischen 0 und 255 mal 
draufgeben und dann kucken was an max und min rauskommt in deiner Excel 
Tab. ?
würde mich interessieren.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> das kann man nur mit Mathlab/Simulink oder anderen Regelungstechnischen
> Programm testen.

Quatsch.
Ich kann deine Gleichung nehmen und sie in Excel
einsetzen und druchrechnen lassen. Nichts anderes
macht auch der µC. Und da sehe ich, dass egal mit
welchem Wert für x ich anfange, y spätestens nach der
3. Iteration den Wert 0 erreicht hat. Das heist nach
dem 3. Overflow ist dein y Wert auf jeden Fall 0.
Egal welchen Wert ich für x annehme.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Denn das ist nur der Regler

Denk mal drüber nach.
Ein Regler soll ja eine Stellgröße einer Istgröße
nachführen. Deine Istgröße kommt vom ADC. Aber woher
kommt eigentlich der 2. Wert, die Stellgröße?
In deiner Gleichung ist davon nichts zu sehen. Die
berechnet immer nur aus dem ADC Wert und dem vorhergehenden
ADC Wert und dem davor einen Wert.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier hast du das Excel Sheet.
Dann kannst du selber damit spielen.

Übrigens hast du bei kleinen ADC Werten einen satten
Overflow in der Berechnung.

Autor: L0rd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für Excel ! Werde mir später anschauen.

Ich habe jetzt nen anderen Problemchen den PortC in meiner Schaltung 
gibt immer 11111111 aus wenn ich ADC Wert direckt Ausgeben will.

Gleiche schaltung gleiches Programm nur an PortD Ausgeben geht.

Stecke ich Atmega16 ins STK500 alles geht.

Stecke wieder in meine Schaltung geht auf 11111111.

Ein fester Wert wie
PORTC = 200;
oder
PORTC = 10;
geht.

Nur direkt
 PORTC=x;
da springt er auf 11111111. Auch wenn ich Fotodiode abdecke und 
einschalte,
wocher nimmt er sollche Werte ?

Hexerei :(

Autor: Philip Kottmann (praktikant)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>   x = ADCW;// 10-bit Wert nach x laden
>   x = ~x>>2; // nur 8-bit davon Verwenden


Der Atmega16 hat doch einen 10bit-AD-Wandler. Das heißt doch nur, dass 
er den Analogwert mit 10 bit Auflösung abfragt. Aber das Ergebnis, 
welches nachher im Ergebnisregister steht hat doch trotzdem nur 8bit 
Datenbreite?!?!?! Oder irre ich mich da?!

Gruß

der Praktikant

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Philip:
Und warum sollte er dann mit 10 Bit wandeln, wenn nur 8 Bit rauskommen? 
Ich hab doch in meinem Auto auch keinen Motor mit 200 PS drin, obwohl 
ich nur 100 PS davon benutze... Natürlich sind die vollen 10 Bit als 
Ergebnis verfügbar, nur eben aufgeteilt auf zwei 8-Bit-Register, weils 
nun mal nur 8-Bit-Register gibt. In C sind diese Doppelregister aber als 
ein 16-Bit-Wert verarbeitbar, weil der Compiler dem Programmierer den 
Doppelzugriff abnehmen kann.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja, es steht dem Programmierer natürlich frei, von den verfügbaren 
10 Bit nur 8 oder so zu verwenden für die Weiterverarbeitung (Bei 
höheren Samplingraten als den im Datenblatt für max. Auflösung 
angegebenen sind die LSB sowieso nicht mehr sinnvoll brauchbar).

Autor: OliverSo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"...meiner Schaltung gibt immer 11111111 aus "

Woher weisst du das? Gemessen? LED's? Wie angeschlossen?

Oliver
P.S. Die Regelungsrechung ist wirklich Unsinn.

Autor: Philip Kottmann (praktikant)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
johnny.m wrote:
> @Philip:
> Und warum sollte er dann mit 10 Bit wandeln, wenn nur 8 Bit rauskommen?
> Ich hab doch in meinem Auto auch keinen Motor mit 200 PS drin, obwohl
> ich nur 100 PS davon benutze... Natürlich sind die vollen 10 Bit als
> Ergebnis verfügbar, nur eben aufgeteilt auf zwei 8-Bit-Register, weils
> nun mal nur 8-Bit-Register gibt. In C sind diese Doppelregister aber als
> ein 16-Bit-Wert verarbeitbar, weil der Compiler dem Programmierer den
> Doppelzugriff abnehmen kann.

Dachte, das ist nur für die Auflösung nötig. Je höher der Wert, desto 
genauere Ergebnisse im Ergebnisregister.... Ist das nicht so, dass er 
dadurch einfach z.B. eine Differenz von 3V mit 2^10 Schritten auflösen 
kann, aber trotzdem das gewandelte Ergebnis in einem 8bit-Register 
ausgibt?!
Da hab ich aber grade eniges dazugelernt....

Gruß

der Praktikant

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habs mal in vmlab laufen lassen. Der meckert erst mal:

"[PC = $006D, Time =    0.27 ms, {ADC}]: ADC: Clock is recommended to be 
in the 50KHz-200KHz range"

Da du nur ADPS2 (Faktor 16) gesetzt hast, ergibt das 1MHz, und das ist 
deutlich mehr als die empfohlenen 200kHz.

Oliver

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.