Forum: Compiler & IDEs Hallo Welt macht nicht was es soll


von Andre Fischer (Gast)


Lesenswert?

Hallo,

ich fange gerade an mit avr c-programmierung und wollte mit dem hallo
welt/ led blink starten. (ich nutze das gcc Plugin für das AVR-Studio
in der grundinstallation)

Wenn ich im Debugmodus schrittweise das Programm durchlaufe passiert
erstmal das was passieren soll.
1. Pin wird als Ausgang gesetzt
2. Schleife startet
3. Pin wird 0 gesetzt
4. es wird in die delay.h gesprungen und 500ms gewartet

Jetzt jedoch sollte der pin 1 gesetzt werden und dann wieder in die
delay.h gesprungen und gewartet werden.
Was jedoch passiert ist:

1.es wird NICHT in die delay.h gesprungen
2. es wird aber trotzdem gewartet
3. der Pin wird erst NACH dem warten 1 gesetzt

Da jetzt die Schleife von neum startet wir der Pin sofort wieder 0
gesetzt und man kann nur ganz ganz kurz sehen das der pin zwischendurch
auf 1 geht.

Das ist das was ich beobachtet habe... Was mache ich falsch? Passiert
das bei jemand anders genauso?
Was muss ich ändern damit es so läuft wie es eigentlich sollte (erst
pin auf 1 setzen, DANN das zweite mal warten (vielleicht sogar MIT dem
Sprung in die delay.h Datei wie beim ersten aufruf von Delay))??

Der Code ist so kurz das ich ihn gleich hier einfüge.
Sorry wenn es nur ein dummer Anfängerfehler von mir ist, ich würde mich
aber freuen wenn mir jemand helfen kann (irgendwo muss man ja anfangen
:))


#include <avr/io.h>
#include <inttypes.h>
#ifndef F_CPU
#define F_CPU 3686400UL
#endif
#include <util/delay.h>



int main(void)
{
DDRC|= (1 << 5);
while (1) {
PORTC&= ~(1 << 5);
_delay_ms(500);
PORTC|= (1 << 5);
_delay_ms(500);
}
}

von MasterFX (Gast)


Lesenswert?

Also gucken wird doch mal deinen Quellcode an:
1
int main(void)
2
{
3
   DDRC|= (1 << 5);
4
   while (1) {
5
     PORTC&= ~(1 << 5);
6
     _delay_ms(500);
7
     PORTC|= (1 << 5);
8
     _delay_ms(500);
9
   }
10
}
Dein Problem ist, dass du mit &= arbeitest. bla &= 5 bedeutet ja nichts
anderes als bla = bla & 5. Beim AVR ist PORTC aber nicht zum lesen
gedacht, sondern dafür sind PINC. Sonst liest du den internen Zustand
der Pull-Up Widerstände
Du musst also machen:
1
int main(void)
2
{
3
   DDRC |= (1 << 5);
4
   while (1) {
5
     _delay_ms(500);
6
     PORTC = PINC ^ (1 << 5);
7
   }
8
}

von Andre Fischer (Gast)


Lesenswert?

Danke erstmal für die schnelle Antwort.
Das versteh ich aber nicht so ganz.

1. ich habe es umgeändert und das Problem mit dem Delay ist immernoch
das selbe (es hat sich also nicht wirklich was geändert (habe neu
compiliert))

2. Wenn ich das richtig verstanden habe dann dürfte ja DDRC |= (1 <<
5); ebenfalls nicht funktionieren (ist doch das gleiche Prinzip oder?)

3. Die Anweisung PORTC&= ~(1 << 5); zum löschen eines bits steht doch
aber genau so sogar in dem AVR GCC Tutorial auf mikrocontroller.net
dann sollte das doch eigentlich auch funktionieren oder?

Danke schonmal für weite Hilfe

von Peter D. (peda)


Lesenswert?

@MasterFX,

das ist Quatsch mit Soße.

Will man einen Ausgang ändern, muß man natürlich das Ausgangsregister
lesen, damit die anderen Pins unbeeinflußt bleiben.

Beim Lesen des Eingaberegisters würde man dagegen z.B. ner Taste an nem
anderen Pin den Pullup klauen.


Peter

von ich (Gast)


Lesenswert?

hallo,
Registername &= ~(1 << 5) löscht schon das Bit. Aber den Zustand eines
Pins liest man wie MasterFX schon sagte mit dem __PIN__X-Register. Da
hift nur das Kapitel über die Portregister im Datenblatt noch einmal
ganz genau zu lesen

Gruß

von johnny.m (Gast)


Lesenswert?

Und wieder mal: Die _delay_ms-Funktion kann keine 500ms auf einmal! Die
max. Verzögerung ist 262,14ms/F_CPU [in MHz]! Macht also bei Deinen
3,6864MHz ungefähr 71 ms maximal... Müsstest dann mit ner for-Schleife
mehrere Aufrufe hintereinander machen.

von Karl H. (kbuchegg)


Lesenswert?

Dein Programm ist grundsätzlich in Ordnung,
nur gibt es 1 klitzekleine Nebenbedingung
im Zusammenhang mit Delay.

Du kannst mit _delay_ms keine 500 ms warten!
Die maximale Zeit ist in delay.h dukomentiert und ist von der CPU
Frequenz abhängig. Du kannst aber mal davon ausgehen, dass
das nicht mehr als 20 ms sein werden. (Schau doch mal in
delay.h hinein. Ist auch nur eine Textdatei)

Entweder packst du also den _delay_ms Aufruf in eine Schleife
oder du machst einfach ein paar _delay_ms() hintereinander, wobei
jeder einzelne nicht länger als 20 ms dauern darf.

PS: Das mit PIN und PORT so wie MasterFX das gemeldet hat, ist
natürlich Unsinn. Du willst ja den momentanen Zustand des
AUsgangsports lesen um dort ein Bit zu toggeln. So wie du das
hast, ist das schon richtig.

von Karl H. (kbuchegg)


Lesenswert?

Ach ja.
Da ist noch was. Hast du am PORTC das JTAG Interface abgeschaltet?
Da sind ein paar Pins am C-Port die per default auf JTAG geschaltet
sind und dann in der echten Hardware für Ärger sorgen. Also
entweder JTAG per Fuse abschalten oder einen anderen als den
C-Port benutzen.

von MasterFX (Gast)


Lesenswert?

@Karl Heinz
Setzt der Compiler das richtig um? (weil man doch eigentlich nur PINC
lesen soll/darf).

von Rolf Magnus (Gast)


Lesenswert?

> weil man doch eigentlich nur PINC lesen soll/darf

Wo steht das?

von johnny.m (Gast)


Lesenswert?

PORTC ist ein normales Read-Write-Register und lässt sich als solches
selbstverständlich lesen. Wäre auch für viele Anwendungen schlimm,
wenns nicht ginge. Ich z.B. möchte in manchen Fällen schon gerne
wissen, welchen Zustand mein Ausgangstreiber hat, v.a. dann, wenn er in
ISRs verändert werden kann...

von MasterFX (Gast)


Lesenswert?

Also wenn der Port auf Eingang gestellt ist darf man den Status nicht
mit PORTx abfragen,weil man dann nur den Zustand der Pullup Widerstände
abfragt. Ich hatte gedacht bei Output wäre das ähnlich bzw. es gäbe evtl
Probleme wenn nicht der gesamte Port als Ausgang konfiguriert sind.

von johnny.m (Gast)


Lesenswert?

Das kommt drauf an, ob Du den Eingangswert abfragen willst oder ob Du
wissen willst, ob Deine Pull-Ups eingeschaltet sind! Denk doch bitte
mal nach, was Du da überhaupt schreibst! Wo wird denn bitteschön oben
auch nur irgendein Eingangszustand abgefragt??? Es soll lediglich der
aktuelle Stand von PORTC mit einem neuen Wert versehen werden, und das
geht genau so wie Andre es geschrieben hat!

von Rolf Magnus (Gast)


Lesenswert?

> Also wenn der Port auf Eingang gestellt ist darf man den Status
> nicht mit PORTx abfragen,weil man dann nur den Zustand der Pullup
> Widerstände abfragt.

Man darf schon, eben genau wenn man den Status der Pullup-Widerstände
abfragen will.

> Ich hatte gedacht bei Output wäre das ähnlich bzw. es gäbe evtl
> Probleme wenn nicht der gesamte Port als Ausgang konfiguriert
> sind.

Man liest halt von PORTC das, was man beim letzten mal reingeschrieben
hat. Welche Pins da als Eingang und welche als Ausgang definiert sind,
spielt dabei keine Rolle.

von Andre Fischer (Gast)


Lesenswert?

Also ich habe jetzt die Dlayanweisung geaendert und zwar in nur 20ms
(von 500).
Das Problem ist leider nach wie vor das gleiche.

1. Es wird nur beim ersten aufruf von delay in die delay.h gesprungen.
(ich meine nicht nur ein einziges mal sondern immer nur das delay was
als erstes in der Schleife erscheint)
2. es wird trotzdem (auch bei dem zweiten delay) gewartet (ich glaube
aber es wird immer gleich lange gewartet egal ob ich 20ms oder 500
angebe)
3. erst NACH dem warten wird der Pin 1 gesetzt (und somit, weil die
Schleife an der Stelle ja von vorn losgeht, sofort wieder auf 0)

Kann es sein das das was ich im Dbugmodus sehe sich "in Echt" dann
anders verhaelt? Das nur der Simulator irgendwie ein Problem hat und
wenn ich das ganze wirklich auf den ATMega spiele richtig funktioniert?
(ich habe mein "Spiel-board" naemlich noch nicht und probiere nur mit
AVR-Studio rum)

Danke schonmal fuer weitere Tipps,wuerde mich freuen wenn ich das
kleine Anfaengerprogramm dazu ueberreden koennte genau das zu tun was
es eigentlich soll :)

von johnny.m (Gast)


Lesenswert?

Wenn Du im Debugger/Simulator einfach auf 'Run' geklickt hast und
keine Breakpoints an den entsprechenden Stelle gesetzt hast, dann hinkt
die Anzeige sowieso hinterher und zeigt in den meisten Fällen alles an,
nur nicht den aktuellen Zustand. Du musst es dann entweder mit
Breakpoints machen oder das ganze im Einzelschritt-Modus durchspielen.
Dann weißt Du genau, was passiert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Delays in der Simulation sind immer übel.  Außerdem ist das
inline-Code, damit hat jeder Debugger mehr oder minder Probleme
in der Anzeige (da ja mitten in der Funktion die Quelldatei
umschaltet).

von Andre Fischer (Gast)


Lesenswert?

Das was ich beschrieben habe habe ich im Einzelschrittmodus
festgestellt.

Also die Stelle auf die es ankommt:

- ende des ersten delays (die delay.h wird verlassen)
- (click naechster Schritt)
    --> es wird nicht in die delay.h gesprungen
    --> es wird gewartet
    --> nach dem Warten wird der Pin 1 gesetzt und der gelbe Pfeil
springt wieder hoch zu der Zeile wo der Pin wieder 0 gesetzt wird
- wenn ich nochmal auf naechster Schritt clicke wird der Pin dann
wieder 0 gesetzt (was ja an der Stelle auch in Ordnung ist)

von Andre Fischer (Gast)


Lesenswert?

@Joerg Wunsch:

es ist also wahrscheinlich das der Debugger nur Probleme hat mir den
korrekten aktuellen Zustand anzuzeigen und korrekt zwischen den Datein
zu wechseln, mein AVR wuerde aber richtig agieren?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ja.

von Andre Fischer (Gast)


Lesenswert?

OK in ca 10 Tagen bekomme ich mein MyAVR board und dann werd ich das mal
"in Echt" probieren und gucken was passiert.


@MasterFX:
Ich weiss jetzt was Du meinst.
Wenn Du ein als Eingang gesetzten Pin lesen willst (also wissen willst
was da von aussen anliegt) dann musst Du PINX nehmen (weil Du mit PORTX
den PullUp lesen wuerdest).
Wenn Du aber wissen willst welchen Wert ein momentan als Ausgang
gesetzter pin hat (und das wollen wir ja an der Stelle damit wir das
nutzen koennen um den Zustand zu aendern [wie Du ganz oben beschrieben
hattest]) DANN musst Du PORTX benutzen.
Was man nutzen muss haengt also davon ab ob der Pin als Ausgang oder
als Eingang gesetzt ist.

Wenn das so stimmt wie ich es jetzt geschildert habe kann ja nochmal
jemand kurz ein OK geben, wenn es falsch ist bitte berichtigen.

Danke

Andre

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

OK.

Du kannst natürlich auch bei einem auf Ausgang geschalteten
Pin PINx lesen, dann liest du den realen Wert am Pin, nicht
das Ausgaberegister.  Das kann ein Unterschied sein -- wenn
jemand einen Kurzschluss am Ausgang gebaut hat. ;-)

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.