Forum: Mikrocontroller und Digitale Elektronik PORTA setzen und wieder zurücksetzten


von Carsten Köditz (Gast)


Lesenswert?

Hallo zusammen,

Ich habs jetzt hingekriegt des ich den µC (atmel Atmega128)
programmieren kann . Jetzt wollt ich einfach mal zum test eine LED
blinken lassen dafür hab ich einfach den PORTA = 0x01 gesetzt ne for
Schleife reingemacht und wieder zurückgesetzt die LED blinkt zwar aber
immer im gleichen Rythmus egal wie lang ich die for Schleife mach kann
mir jemand sagen woran des liegt wäre super !
Vielen Dank schonmal !

Gruß
Carsten

von Frank Linde (Gast)


Lesenswert?

Ohne Deinen Sourecode gesehen zu haben, wird Dir das wohl niemand sagen
können. Aber raten kann man ja mal: Vielleicht optimiert der verwendete
Compiler die Schleife immer weg? => Compileroptionen prüfen. Es ist
jedenfalls erwiesen, dass man Zeitschleifen unterschiedlicher Länge für
die AVR programmieren kann. ;-)

Gruß, Frank

von Carsten Köditz (Gast)


Lesenswert?

Ok mein Source Code is

while (1)
{

if (PORTA == 0x00)
{
PORTA = 0x01;
for (i=0;i>=10000;i++)
{;}
}
else
{
PORTA = 0x00;
for (i=0;i>=10000;i++)
{;}
}
}

von Frank Linde (Gast)


Lesenswert?

Hhm, bin ja nicht gerade ein C-Freak, aber IMHO ist das soweit in
Ordnung. Mit welcher Taktfrequenz läuft denn Dein Chip und welche Werte
für die Schleife hast Du ausprobiert? Und wie schnell blinkt die LED
mit dem Schleifenwert 10000 ungefähr?

Gruß, Frank

von Carsten Köditz (Gast)


Lesenswert?

Mein Controller läuft mit 16 MHz.

Ich habe schon 10 000, 100 000, 1 mio, 2 mio ausprobiert,
aber da ändert sich nichts...

Die LED blinkt etwa 10 mal in der sek. habe die Frequenz nicht
gemessen.

Gruß

Carsten

von Fritz Ganter (Gast)


Lesenswert?

Du weisst schon dass das ein 8bit Prozessor ist, oder?
Also wenn i ein int ist, dann hat er nur 16bit, dh. bei 32667 ist
schluss.

von Daniel Jelkmann (Gast)


Lesenswert?

Hi Carsten,

Dein Code ist nicht ganz richtig.
Die For-Schleife wird kein einziges Mal durchlaufen, weil die
Abbruchbedingung "verkehrt rum" ist.
Anstatt
 for (i=0;i>=10000;i++)
hast Du wohl
 for (i=0; i < 10000; i++)
gemeint. Ich denke Du möchtest, dass er die Schleife 10.000 mal
durchläuft.

Und der zweite Punkt:
Ich vermute ganz stark, dass Frank recht hat und die Schleife komplett
wegoptimiert wird. Der Compiler erkennt, dass eine solche Schleife
keinen Sinn macht und entfernt sie...
Probier mal das folgende:
for (i=0; i < 10000; i++)
 asm volatile ("nop");

Das volatile verhindert, dass der Compiler das NOP (=no operation)
wegoptimiert.

Was mir noch einfällt: Ich weiss nicht, wie die Pins standardmässig
geschaltet sind, also ob als Ausgang oder als Eingang. Daher würde ich
vor der while()-Schleife sicherheitshalber den Pin mit der LED als
Ausgang schalten.

Bye
  Daniel Jelkmann

von Frank Linde (Gast)


Lesenswert?

@Daniel: Aua! Stimmt natürlich, habe ich aber auch nicht gesehen.
<schnarch> Aber egal, ob die Schleife nun wegoptimiert oder sowieso
nicht ausgeführt wird, warum blinkt die LED dann mit so einer niedrigen
Frequenz? Soooooooooooooooooooooo langsam kann C gegenüber ASM doch nun
wirklich nicht sein. ;-)

Gruß, Frank

von crazy horse (Gast)


Lesenswert?

könnte ein geweckter Wachhund sein, der zubeisst.

von Divison (Gast)


Lesenswert?

Versuchs doch mal damit!

#include <avr/io.h>


unsigned short waittime=1000;

#define AVR_CLK (8000000)
#define LOOPS_PER_US (AVR_CLK/4)
#define LOOPS_PER_MS (AVR_CLK/1000/4)

void delay_ms(unsigned short ms)
{
        if (!ms)
                return;

        /* the inner loop takes 4 cycles per iteration */
        _asm__ __volatile_ (
                "1:                     \n"
                "       ldi r26, %3     \n"
                "       ldi r27, %2     \n"
                "2:     sbiw r26, 1     \n"
                "       brne 2b         \n"
                "       sbiw %0, 1      \n"
                "       brne 1b         \n"
                : "=w" (ms)
                : "w" (ms), "i" (LOOPS_PER_MS >> 8), "i" (0xff &
LOOPS_PER_MS)
                );
}

void blink(){
  sbi(PORTB,1);
  delay_ms(waittime);
  cbi(PORTB,1);
  delay_ms(waittime);
  return 0;
}

int main(void){

PORTB = 0x00;
DDRB = 0xFF;

while(1){

  blink();

}

return 0;

}

von Carsten Köditz (Gast)


Lesenswert?

Guten Morgen!

Danke euch für eure Mühe!

Ich hab nun noch nen Ansatz. Ich hab versucht das über ein
"Unterprogramm" zu lösen.

while(1){

  if (PORTA = 0x01)
  { PORTA = 0x00;
    pause();
     }

     else
     { PORTA = 0x01;
       pause();
        }

}

}

void pause (void)

  {
  unsigned char i;
  for (i=0;i>=32667;i++);
  }

Kann mir einer von euch sagen wie ich die for-Schleife verschachteln
kann, so das ich doppelte oder dreifache oder x-fache Zeit raus
bekommen?

Benutze nach wie vor den ATmega128 von Atmel!

Gruß

Carsten

von crazy horse (Gast)


Lesenswert?

deine Abbruchbedingung ist wieder falsch :-)
Und was ist mit dem watchdog? Wenn dein 1. Programm geblinkt hat, ist
eigentlich die einzige Erklärung ein watchdogreset.
Schleifenzeit erhöhen ist keine grosse Sache, du kannst den Prozessor
innerhalb der Schleife mit irgendwas beschäfigen, jeder Behehl kostet
Zeit. Alternativ keine Int, sondern eine long-Variable verwenden.
Der bessere Weg wäre, einen Timer einzusetzen.
z.B. Timer0, erzeugt jede 1ms einen Timerinterrupt (Timer mit passendem
Vorteiler im CTC-Modus starten, passenden Wert ins OCR-Register
schreiben, in der ISR zählst du nur eine globale Variable hoch.)
im Hauptprogramm kannst du die Variable abfragen und somit definierte
Verzögerungen erzeugen.

von Daniel Jelkmann (Gast)


Lesenswert?

Hi nochmal...

Ich war gestern wohl halb blind ;)

if (PORTA = 0x01)
geht so nicht. Erstens ist das keine Abfrage auf Gleichheit, sondern
eine simple Zuweisung. Vom Sinn her war wohl eher PORTA == 0x01
gemeint.
Und zweitens geht das mit der Abfrage von PORTA nicht auf diese Weise,
wenn ich nicht irre. Ich würde mir da ne Variable nehmen, deren Zustand
sich abwechselnd von 1 auf 0 bzw von 0 auf 1 ändert und damit den Wert
der LED am Port wiederspiegelt.

DDRA = 0xFF;   // alle Pins als Ausgänge schalten
int toggle = 0;
while(1)
{
  if (toggle)
  {
    PORTA = 0x00;
    toggle = 0;
  }
  else
  {
    PORTA = 0x01;
    toggle = 1;
  }
  pause();
}

Hab das jetzt nicht probiert sondern einfach mal runtergeschrieben, ich
hoffe das läuft so ;)

Zum Thema Pause: es dürfte doch genug Delay-Routinen geben, die im Netz
rumschwirren oder sogar mit dem Compiler mitgeliefert werden. Warum das
Rad immer neu erfinden?

Bye
  Daniel Jelkmann

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.