Forum: Mikrocontroller und Digitale Elektronik ATMega 8: _delay_ms(500) --> Unterschiedlich lange Wartezeiten


von Alexander G. (grossmann200)


Lesenswert?

Hallo,
zum Einstieg in die AVR-Programmierung des ATMega8 habe ich ein kleines 
Programm, dass in 500ms Abständen den PIN 0 am Port B zwischen high und 
low hin und her wechselt.

Wenn ich das Programm auf der Konsole mit make und selbst erstellter 
Makefile kompiliere stimmen die Zeitabstände von 500ms.

Nun bin ich gerade dabei zu Eclipse zu wechseln. Den Source-Code habe 
ich 1:1 übernommmen, aber nun sind die high/low Phasen nicht mir 500ms 
sondern ca. 10000ms lang.

Woran könnte dies liegen?


----------------------------------------------------------
Hier noch der Quellcode:
main.c:

#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
  unsigned char zwischenspeicher;
  DDRB = 0b00000001;
  while(1)
  {
  zwischenspeicher = PORTB;
  zwischenspeicher = zwischenspeicher ^ 0b00000001;
        PORTB = zwischenspeicher;
  _delay_ms(500);
}                    return 0;
}

von Peter II (Gast)


Lesenswert?

Alexander G. schrieb:
> Woran könnte dies liegen?

das du F_CPU vermutlich unterschiedlich definiert hast.

von Alexander G. (grossmann200)


Lesenswert?

Peter II schrieb:
> das du F_CPU vermutlich unterschiedlich definiert hast.

Daran habe ich schon gedacht und folgendes versucht:
Bei dem händischen Makefile einmal F_CPU=16000000 und dann F_CPU=8000000 
ausprobiert. In beiden Fällen hatte ich am Pin die 500ms Phasen. F_CPU 
scheint hier keinen Einfluss zu haben.

Was vielleicht noch Interessant ist, ist folgende Warnmeldung beim 
Ausführen von make:
/usr/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>"

Aber wahrscheinlich habe ich beim Makefile noch was falsch gemacht und 
muss noch irgendwo die F_CPU-Variable als Parameter übergeben ???


----- Makefile-------------------
TARGET=main
MCU=atmega8
F_CPU=16000000
CC=/usr/bin/avr-gcc
SOURCES=$(TARGET).c

PROGRAMMER=avrispmkII
PORT=-P usb
BAUD=-B 10

OPT = s

# -----------Ab hier nichts verändern ---------
OBJECTS=$(SOURCES:.c=.o)
CFLAGS=-c -Os
LDFLAGS=

all: hex eeprom

hex: $(TARGET).hex

eeprom: $(TARGET)_eeprom.hex

$(TARGET).hex: $(TARGET).elf
  avr-objcopy -O ihex -j .data -j .text $(TARGET).elf $(TARGET).hex

$(TARGET)_eeprom.hex: $(TARGET).elf
  avr-objcopy -O ihex -j .eeprom --change-section-lma .eeprom=1 
$(TARGET).elf $(TARGET)_eeprom.hex

$(TARGET).elf: $(OBJECTS)
  $(CC) $(LDFLAGS) -mmcu=$(MCU) $(OBJECTS) -o $(TARGET).elf

.c.o:
  $(CC) $(CFLAGS) -mmcu=$(MCU) $< -o $@

size:
  avr-size --mcu=$(MCU) -C $(TARGET).elf

program:
  avrdude -p$(MCU) $(PORT) $(BAUD) -c$(PROGRAMMER) 
-Uflash:w:$(TARGET).hex:a

clean_tmp:
  rm -rf *.o
  rm -rf *.elf
---------------------------------------------



Bei der Eclipse-Variante steht in der Makefile kein F_CPU drin. Ein 
händisches ändern habe ich hier bislang nicht hinbekommen, da Eclipse es 
beim kompilieren jedesmal überschreibt.

: Bearbeitet durch User
von Karl M. (Gast)


Lesenswert?

Alexander,

C hast Du bisher nicht gelernt ?

Alexander G. schrieb:
> Hallo,
> zum Einstieg in die AVR-Programmierung des ATMega8 habe ich ein kleines
> Programm, dass in 500ms Abständen den PIN 0 am Port B zwischen high und
> low hin und her wechselt.
>
> Wenn ich das Programm auf der Konsole mit make und selbst erstellter
> Makefile kompiliere stimmen die Zeitabstände von 500ms.
>
> Nun bin ich gerade dabei zu Eclipse zu wechseln. Den Source-Code habe
> ich 1:1 übernommmen, aber nun sind die high/low Phasen nicht mir 500ms
> sondern ca. 10000ms lang.
>
> Woran könnte dies liegen?
>
> ----------------------------------------------------------
> Hier noch der Quellcode:
> main.c:
>
> #include <avr/io.h>
> #include <util/delay.h>
>
> int main (void)
> {
>   unsigned char zwischenspeicher;
>   DDRB = 0b00000001;
>   while(1)
>   {
>   zwischenspeicher = PORTB;
>   zwischenspeicher = zwischenspeicher ^ 0b00000001;
>         PORTB = zwischenspeicher;
>   _delay_ms(500);
> }                    return 0;
> }

1
#define LED PB0
2
3
int main (void)
4
{
5
  DDRB  |= (1<<LED); // set LED to output
6
  // PORTB &= ~(1<<LED); // set LED output to low
7
  // PORTB |= (1<<LED); // set LED output to high
8
9
  while(1)
10
  {
11
    PORTB = (1<<LED); // toggle LED output
12
    _delay_ms(500);
13
  }
14
  return 0;
15
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Alexander G. schrieb:
> F_CPU scheint hier keinen Einfluss zu haben.
Sollte sie aber. Denn damit sagst du dem Compiler, womit dein Controller 
läuft...

> muss noch irgendwo die F_CPU-Variable als Parameter übergeben ???
Der Compiler muss wissen, welche Taktfrequnz verwendet wird. Also muss 
die F_CPU in die Compilerkommandozeile.

: Bearbeitet durch Moderator
von Karl M. (Gast)


Lesenswert?

Alexander G. schrieb:
> F_CPU=16000000

Besser F_CPU=16000000UL

von Karl M. (Gast)


Lesenswert?

Ups - Tastaturfehler.
1
PORTB ^= (1<<LED); // toggle LED output

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Oder du probierst es mal so:
#include <avr/io.h>
#define F_CPU 16000000ul
#include <util/delay.h>

von avr (Gast)


Lesenswert?

Alexander G. schrieb:
> .c.o:
>   $(CC) $(CFLAGS) -mmcu=$(MCU) $< -o $@

Hier wird der Compiler aufgerufen. Dort werden nur CFLAGS und 
-mmcu$(MCU) übergeben. Du kannst im dem Makefile so viel definieren wie 
du willst, wenn der Compiler das nicht übergeben bekommt, ändert sich 
nichts.
Defines übergibt man mit -Dname=abc.

von Carl D. (jcw2)


Lesenswert?

An welcher Stelle des Make-Files wird denn die "make-Variable" "F_CPU" 
verwendet, sprich an den Comiplier übergeben? Es sollte als 
Preprozessor-Makro ankommen, also müsste irgendwo ein "-DF_CPU=" stehen.
Z.B. könnte
CFLAGS=-c -Os
durch
CFLAGS=-c -Os -DF_CPU=16000000
ersetzt werden.
Wichtig aber, die Zahl sagt nur dem Compiler, was die Hardware tut. Also 
hier 16MHz Quarz/externer Oszilator mit "ohne DIV8 Fuse".

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

avr schrieb:
> Defines übergibt man mit -Dname=abc.
Siehe z.B. auch http://www.makerconnect.de/index.php?threads/f_cpu.2396/
(mit Google in 1 min. gefunden...)

von Alexander G. (grossmann200)


Lesenswert?

Carl D. schrieb:
> An welcher Stelle des Make-Files wird denn die "make-Variable"
> "F_CPU"
> verwendet, sprich an den Comiplier übergeben? Es sollte als
> Preprozessor-Makro ankommen, also müsste irgendwo ein "-DF_CPU=" stehen.
> Z.B. könnte
> CFLAGS=-c -Os
> durch
> CFLAGS=-c -Os -DF_CPU=16000000
> ersetzt werden.
> Wichtig aber, die Zahl sagt nur dem Compiler, was die Hardware tut. Also
> hier 16MHz Quarz/externer Oszilator mit "ohne DIV8 Fuse".

Dies scheint mir doch ein sehr guter Hinweis. Vor Allem zeigt sich nun 
folgendes:

**** Ohne F_CPU=16000000 (CFLAGS=-c -Os) ****
Man bekommt die Warnmeldung
/usr/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>"

Aber die Phasen sind tatsächlich die gewünschten 500ms lang

**** Mit F_CPU=16000000 (CFLAGS=-c -Os -DF_CPU=16000000) ****
Keine Fehlermeldung mehr, aber statt 500ms sind die Phasen ca. 10Sek 
lang.

**** Mit F_CPU=8000000 (CFLAGS=-c -Os -DF_CPU=8000000) ****
Die Phasen sind ca. 5Sek lang.

von Peter II (Gast)


Lesenswert?

Alexander G. schrieb:
> Dies scheint mir doch ein sehr guter Hinweis. Vor Allem zeigt sich nun
> folgendes:

Mit welchem Takt betreibst du denn dein Atmega?

von Alexander G. (grossmann200)


Lesenswert?

Peter II schrieb:
> Mit welchem Takt betreibst du denn dein Atmega?

Das ist mir gerade auch durch den Kopf gegangen. Diesen ATMega8-16PU 
hatte ich hier noch rumliegen (seit 7 Jahren) ... und ich habe keine 
Ahnung, ob ich damals irgendwelche "Taktfrequenzen" geändert habe. Bin 
gerade dabei im Datenblatt nachzusehen, wo man das einstellt (aber noch 
nix gefunden). Jedenfalls habe keinen externen Quarz oder sowas dran.

(Dies sind halt meine ersten Schritte der AVR-Programmierung)

: Bearbeitet durch User
von Alexander G. (grossmann200)


Lesenswert?

Im Datenblatt über den ATMega8 findet man auf S.26:

The device is shipped with CKSEL = “0001” and SUT = “10” (1 MHz Internal
RC Oscillator, slowly rising power).

--> D.h. also, obwohl es ein 16Mhz Mikrocontroller ist, wird er 
werkseitig mit 1Mhz ausgeliefert.

Setzt man F_CPU=1000000 dann stimmt auch alles.

Jetzt stellt sich mir nur noch die Frage: wie/wo kann ich in Eclipse 
eine Einstellung für das Makefile machen, das dort auch F_CPU Einträge 
erscheinen?

von Alexander G. (grossmann200)


Lesenswert?

Lothar M. schrieb:
> Oder du probierst es mal so:
> #include <avr/io.h>
> #define F_CPU 16000000ul
> #include <util/delay.h>

Funktioniert!

nur dass ich nun statt 16000000ul die 1000000ul einsetzen muss.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Alexander G. schrieb:
> Funktioniert!

ja, aber das ist eine ganz schlechte Idee. Das müsstest du in jedem C 
file machen und das ist die große Gefahr das du verschiedene Werte hast, 
wenn du mal die Taktfrequenz änderst.

von Harry L. (mysth)


Lesenswert?

Wenn du Eclipse mit AVR nutzt, kann ich dir dieses Plugin wärmstens 
empfehlen:
http://avr-eclipse.sourceforge.net/wiki/index.php/The_AVR_Eclipse_Plugin

Da kannst du F_CPU direkt bei den Projekteinstellungen festlegen.

: Bearbeitet durch User
von Alexander G. (grossmann200)


Lesenswert?

Das AVR-Plugin habe ich bereits installiert und nehmen an, dass ich 
deswegen nun auch in den Project-Properties unter C/C++ Build -> 
Environment bei der Variable AVRTARGETFPU die Taktfrequenz angeben kann.

... und das funktioniert auch wunderbar :-)

von W.A. (Gast)


Lesenswert?

Karl M. schrieb:
> Besser F_CPU=16000000UL

Wieso "Besser"?
Entweder der Compiler versteht es ohne "UL" richtig oder nicht.

Ein bisschen schwanger gibt es nicht.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Alexander G. schrieb:
> Funktioniert!
Dann überleg mal, warum. _delay_ms() muss die Taktfrequenz kennen. Der 
eine Weg ist es, das dafür nötige define von Hand zu machen, der bessere 
Weg ist es, dieses define über die Kommandozeile festzulegen.

Und natürlich musst du in diesem define genau die Frequenz angeben, 
mit der der Controller tatsächlich läuft. Du kannst ihn mit dieser 
Einstellung nicht auf die "Wunschtaktfrequenz" umstellen. Diese 
Einstellung passiert woanders.

Karl M. schrieb:
> Besser F_CPU=16000000UL
Im Makefile ist das unnötig, dort wird das UL sowieso noch angehängt...

: Bearbeitet durch Moderator
von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Alexander G. schrieb:
> deswegen nun auch in den Project-Properties unter C/C++ Build ->
> Environment bei der Variable AVRTARGETFPU die Taktfrequenz angeben kann.

Falsche Stelle!

Da gehört das hin, wenn du das Plugin verwendest.

von Alexander G. (grossmann200)


Lesenswert?

Harry L. schrieb:
> Da gehört das hin, wenn du das Plugin verwendest.

Danke dir, Harry.
:-)

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.