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); } }
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 | }
|
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
@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
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ß
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.
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.
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.
@Karl Heinz Setzt der Compiler das richtig um? (weil man doch eigentlich nur PINC lesen soll/darf).
> weil man doch eigentlich nur PINC lesen soll/darf
Wo steht das?
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...
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.
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!
> 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.
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 :)
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.
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).
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)
@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?
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.