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


von L0rd (Gast)


Angehängte Dateien:

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 !

von wulf (Gast)


Lesenswert?

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

von Peter D. (peda)


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

von L0rd (Gast)


Angehängte Dateien:

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.


von L0rd (Gast)


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

von Tommy (Gast)


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.

von L0rd (Gast)


Lesenswert?

Das ist ein PID Regler vin RN.

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

von johnny.m (Gast)


Lesenswert?

ATMega16 und PORTC? Da klingelts sofort: Hast Du das JTAG deaktiviert?

von johnny.m (Gast)


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.

von L0rd (Gast)


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 :)

von johnny.m (Gast)


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!

von L0rd (Gast)


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.

von Tommy (Gast)


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.

von Tommy (Gast)


Lesenswert?

Ich sehs grad nich? Hast du den ADC Pin als Eingang geschaltet?

von johnny.m (Gast)


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
1
while(!(ADCSRA & (1 << ADIF)));
besser
1
while((ADCSRA & (1 << ADSC)));

von L0rd (Gast)


Angehängte Dateien:

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/java_multimedia_ws2004_05/html/node25.html
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.

von Tommy (Gast)


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

von Tommy (Gast)


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.

von L0rd (Gast)


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:
1
// AD Wandlung und Berechnung
2
void rechnung(void)
3
{
4
  // Wandlung starten (1<<ADSC), Einzel.Wandl.
5
    ADCSRA |= (1<<ADSC);
6
7
    // Warten bis die AD-Wandlung abgeschloßen ist
8
    while ( !(ADCSRA & (1<<ADIF)) );
9
10
  x = ADCW;// 10-bit Wert nach x laden
11
  x = ~x>>2; // nur 8-bit davon Verwenden
12
  // Berechnung Anfang
13
  //e = 230 - x;
14
  //y = (yalt + 152*e - 303*ealt + 152*ealtt) / 10000;    //Reglergleichung
15
  //ealtt = ealt;
16
  //ealt = e;
17
  //PORTC=y; //Ausgabe
18
  //yalt = y;
19
  // Berechnung Ende
20
  
21
  PORTC = x; // 8-bit Ausgeben
22
  ADCSRA |= (0<<ADIF); // geht auch ohne, aber sicher ist sicher.
23
24
}
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.




von Karl H. (kbuchegg)


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.



von L0rd (Gast)


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.

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


Angehängte Dateien:

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.

von L0rd (Gast)


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
1
PORTC = 200;
oder
1
PORTC = 10;
geht.

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

Hexerei :(

von Philip K. (praktikant)


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

von johnny.m (Gast)


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.

von johnny.m (Gast)


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

von OliverSo (Gast)


Lesenswert?

"...meiner Schaltung gibt immer 11111111 aus "

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

Oliver
P.S. Die Regelungsrechung ist wirklich Unsinn.

von Philip K. (praktikant)


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

von Oliver (Gast)


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

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.