ATMega 8: _delay_ms(500) --> Unterschiedlich lange Wartezeiten

OP #4486607
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;
}
OP #4486617
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.
Gast #4486629
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
}
Moderator (Firma: Titel) Persönliche Seite #4486631
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.
Gast #4486650
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.
#4486652
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".
OP #4486671
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.
OP #4486682
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)
OP #4486804
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?
Moderator (Firma: Titel) Persönliche Seite #4486851
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...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren