Verzögerung funktioniert nicht (avr attiny 26, delay.h)

Ich versuche zu lernen, wie man Programme auf Mikrocontroller schreibt, und begann mit sehr einfachen Dingen wie LED, die mit einer bestimmten Frequenz blinken oder per Taste gesteuert werden. Ich habe jedoch Probleme mit der Verwendung von _delay_ms() aus delay.h. Soweit ich verstanden habe, sollte für die korrekte Arbeit dieser Funktion die Optimierung eingeschaltet sein . Wenn ich ein Programm auf den Mikrocontroller schreibe, wird die LED nicht blinken, sondern ständig mit geringer Helligkeit eingeschaltet. Als ich versuchte, es einfach ohne Verzögerungen einzuschalten, ist die Helligkeit viel höher, also sieht es so aus, als ob der Mikrocontroller aus irgendeinem Grund eine mittelmäßige Niederspannung liefert, ich frage mich, warum und was das Problem sein könnte. Im Folgenden beschreibe ich, was ich genau gemacht habe. Code (main.c) sieht so aus (ich verwende attiny26 und gehe davon aus, dass es bei 1 MHz funktioniert).

#define F_CPU 1000000UL // 1 MHz clock speed
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
     DDRA |= (1<<PA0);  //A0 as output
     while(1) //infinite loop
     {
          PORTA |= (1<<PA0);// LED at A0 ON
          _delay_ms(1000); // 1 second delay
          PORTA &= ~(1<<PA0); //LED at A0 OFF
          _delay_ms(1000); // 1 second delay
          }
 }

Ich mache Objektdatei mit

avr-gcc -mmcu=attiny26 -O1 -c main.c

wobei -O1 für Stufe 1 der Optimierung steht. Dann

avr-objcopy -O ihex main.o main.hex

und in den Mikrocontroller schreiben:

sudo avrdude -c usbasp -p t26 -B 100 -U flash:w:main.hex:i

Alle Schritte waren völlig ohne Fehler oder Warnungen. Wie ich oben sagte, ist das resultierende Verhalten seltsam: LED ist ständig an mit geringer Helligkeit. Wenn ich in der Zwischenzeit in ein Mikrocontroller-Programm schreibe, in dem ich nur die LED einschalte (alle Verzögerungen entfernen), wird die LED mit voller Helligkeit eingeschaltet. Ich habe überlegt, ob die Optimierung selbst ein Problem sein kann, aber im Regime ohne Verzögerungen funktioniert das Programm in jedem Fall korrekt - mit oder ohne Optimierung.

Die Steuerung von irgendetwas mit der Schaltfläche würde eine Entprellung und die gleiche _delay_ms () -Funktion erfordern, die bei mir nicht funktioniert.

UPD : Das Auskommentieren #define F_CPU 1000000ULoder Erhöhen des Arguments von _delay_ms()hilft nicht. Eine Erhöhung der Verzögerungszeit durch Iteration for (i=0; i<100000; i++) {_delay_ms(1000);}führt jedoch dazu, dass die LED ständig mit voller Helligkeit eingeschaltet wird. Getestete kleinere Iterationszeiten (10, 100, 1000, 10000) ergeben keine volle LED-Helligkeit.

Die Tatsache, dass es ohne die Verzögerung heller ist, lässt den Eindruck entstehen, dass die Verzögerung funktioniert, aber so schnell ist, dass die LED nur gedimmt wird. Was passiert, wenn Sie auskommentieren #define F_CPU 1000000UL?
Die LED blinkt, aber sie blinkt so schnell, dass sie für Ihre Augen nur schwach aussieht. Versuchen Sie, die Verzögerungszeit um den Faktor 10 oder mehr zu erhöhen.
Der Code sieht gut aus. Wie sind deine Sicherungseinstellungen?
@DigitalNinja, ich bekomme eine Warnung /usr/lib/avr/include/util/delay.h:90:3: warning: #warning "F_CPU not defined for <util/delay.h> [-Wcpp] # warning "F_CPU not defined for <util/delay.h>"und es ändert nichts - ich sehe dieselbe gedimmte LED. Laut delay.h wäre die F_CPU sowieso standardmäßig gleich:#ifndef F_CPU /* prevent compiler error by supplying a default */ # warning "F_CPU not defined for <util/delay.h>" # define F_CPU 1000000UL #endif
@kkrambo, ich habe versucht, es um den Faktor 10 und noch viel mehr zu erhöhen: hat nichts geändert. Aber dann habe ich mich gefragt, ob es ein Problem mit dem möglichen maximalen Argument von geben kann _delay_ms(). Anstatt dem ein sehr großes Argument zu geben _delay_ms(), habe ich versucht, es mit Iteration zu tun: for (i=0; i<100000; i++) {_delay_ms(1000);}. Ich habe es auf 10, 100, 1000, 10000, 100000 Wiederholungen überprüft. Bei hohem Faktor 100000 wirkt die LED so hell wie ohne Verzögerung, aber immer noch eingeschaltet.
@kkrambo , Für die getesteten Faktoren 10, 100, 1000, 10000 hat es immer noch nicht die volle Helligkeit. Ich frage mich also, ob es sein kann, dass es bei Faktor 100000 immer noch schnell genug blinkt, um den Zustand "Aus" nicht zu sehen, aber langsam genug, um es mit hoher Helligkeit zu sehen? Und sollte das Argument von _delay_ms die tatsächliche Verzögerungszeit sein, oder die Zeit, die dann durch geteilt wird F_CPU?
@BruceAbbott, meinst du Informationen über Sicherungen, die mir nach dem Schreiben an den Mikrocontroller Avrdude geben? Es sagtavrdude: safemode: Fuses OK (E:FF, H:F7, L:E1)
Der Mikrocontroller kann am gpio-Pin keine mittlere niedrige Spannung liefern. Es ist entweder an oder aus. Wenn Sie also schwach sehen, blinkt es sehr schnell. Ihre Verzögerungsfunktion funktioniert nicht wie erwartet. Ich weiß nicht warum. Probieren Sie etwas anderes aus oder gehen Sie es mit dem Debugger durch und finden Sie heraus, was passiert.

Antworten (2)

Das Problem ist, dass Sie eine Objektdatei erstellen, aber nicht verknüpfen. Ohne Verknüpfung werden Verzweigungsbefehle im Maschinencode nicht mit den erforderlichen Zieladressen gefüllt, sodass der Code einfach linear ausgeführt wird, bis er vom Ende in den nicht zugeordneten Speicher „fällt“. Schließlich erreicht es das Ende des Speichers und springt auf Null, um Ihren Code erneut auszuführen. Das Endergebnis ist, dass die LED mit einem sehr niedrigen Arbeitszyklus blinkt.

Die einfachste Lösung besteht darin, die -cOption einfach aus Ihrem Kompilierungsbefehl zu entfernen, dh: -

avr-gcc -mmcu=attiny26 -O1 main.c

Dadurch wird eine ELF-Datei mit dem Namen "a.out" erstellt, die Sie in HEX konvertieren mit: -

avr-objcopy -O ihex a.out main.hex

Die maximale Verzögerung, die Sie mit _delay_ms() erreichen können, sollte 262,14 ms / F_CPU in MHz nicht überschreiten. Das sind in Ihrem Fall 262,14 ms. Ansehen

void _delay_ms(double __ms)

in diesem Link für weitere Informationen.

Eine Problemumgehung besteht darin, mehrere Male für eine kürzere Zeitspanne zu verzögern.

Zum Beispiel:

for(int i=0; i<5; i++)
   delay_ms(200);
Dieser Link besagt, dass das 262.14-Limit für _delay_loop_2 gilt. Das Limit für _delay_ms ist 65535, was 6,5535 Sekunden entsprechen sollte.
@kkrambo In seinem Fall, wenn der an _delay_ms übergebene Wert größer als 262 ms ist, wird er automatisch durch 10 geteilt. Also _delay_ms(1000);eine Verzögerung von 100ms.
@kkrambo Also, um die Verzögerung von 6,5535 Sekunden zu erhalten, sollte er tippen_delay_ms(65535);