Forum: Mikrocontroller und Digitale Elektronik Anfängerfrage AVR GCC


von Thomas (Gast)


Lesenswert?

Hallo zusammen,

seit langer Zeit wollte ich mal wieder etwas programmieren und merke 
nun, dass ich die Grundlagen nicht mehr beherrsche ...

Ich habe ein STK500 mit einem Atmega8, Taster and PC, LED an PD und 
lasse darauf die folgenden Zeilen laufen (inzwischen auf das Kernproblem 
vereinfacht):
1
int main( void )
2
{
3
  DDRD  |= (1 << DDD0);  // Pin 0 von Port D als Ausgang
4
  PORTD |= (1 << PD0);    // PD0 im PORTD setzen
5
    
6
  for(;;) {                                       // main loop
7
  }
8
  return (0);
9
}
Ergebnis: wenn ich "PORTD |= (1 << PD0);" weg lasse brennt die LED0, 
warum?

Nächster Versuch:
1
int main( void )
2
{
3
  DDRD  |= (1 << DDD0);  // Pin 0 von Port D als Ausgang
4
  PORTD |= (1 << PD0);    // PD0 im PORTD setzen
5
  PORTC |= (1 << DDC0);   // internen Pull-Up an PC7 aktivieren
6
  
7
  for(;;) {                                       // main loop  
8
    
9
  if ( PINC & (1<<PINC0) )
10
  PORTD = PIND ^ ( 1 << PD0 );  // LED an Port PD0 an- bzw. aus  
11
  
12
}
13
  return (0);
14
}
Ergebnis: Die LED brennt wieder, auch wenn ich die Tast PC0 nicht 
gedrückt habe, warum?

Wahrscheinlich fällt das unter die Rubrik "hätte ich auch selber drauf 
kommen können", aber ...

Vielen Dank schon mal für einen Tip, wie ich hier weiter komme!

Gruß
Thomas

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Lesenswert?

Thomas schrieb:
> Ergebnis: wenn ich "PORTD |= (1 << PD0);" weg lasse brennt die LED0,
> warum?

Ist Dein RS232 vom STK500 verbunden? PD0 ist beim ATmega8 RX-Pin.

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


Lesenswert?

Thomas schrieb:
> Nächster Versuch:
Bitte setze bei weiteren Versuchen selbständig die [c] Tags um deinem 
Code. So wie es über jeder Eingabebox beschrieben ist.

Thomas schrieb:
> Ergebnis: wenn ich "PORTD |= (1 << PD0);" weg lasse brennt die LED0,
> warum?
Wie ist die LED am Portpin angeschlossen?

> Ergebnis: Die LED brennt wieder, auch wenn ich die Tast PC0 nicht
> gedrückt habe, warum?
Wie ist der Taster angeschlossen? Und was passiert, wenn du den Taster 
drückst?

Merke: es ist sinnvoll, den Pegel an den Portpins mit einem Messgerät 
gegen Masse zu messen und sich nicht auf "sekundäre" Elemente wie "LED 
leuchtet" oder "Taster ist gedrückt" zu verlassen. Es kann nämlich sein, 
dass die LED leuchtet, wenn der Pin low ist. Oder dass am Pin ein low 
anliegt, wenn der Taster gedrückt ist.

: Bearbeitet durch Moderator
von Thomas (Gast)


Lesenswert?

@Walter: ja, RS232 ist verbunden, macht aber keinen Unterschied wenn ich 
denn Stecker abziehe.

@Lothar:

[c] Tags ...  Eingabebox ? Was meinst Du?

Die LEDs sind auf dem STK500 mit dem PORTD über das Flachbandkabel 
verbunden. Genauso die Taster mit PORTC. Beides funktioniert auch 
einwandfrei, z.B. mit dem Entprellprogramm von Peter D.

Solange ich den Taster gedrückt halte geht die LED aus. Wenn ich im 
falschen Moment drücke, bleibt sie an, aber das ist ja auch ok so.

von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Thomas schrieb:
1
> [c] Tags ...  Eingabebox ? Was meinst Du?
Lies einfach beim nächsten Posten mal den Text, der über Deinem 
Eingabefenster steht, siehe auch Screenshot.

Auf Deutsch: Du sollst beim nächsten Mal Deinen C-Code in
1
[c]......[/c]
einbetten, damit man ihn auch lesen kann. Sehr wichtig für 
Proportionalschrift-Leser.

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

Thomas schrieb:
> Ergebnis: Die LED brennt wieder, auch wenn ich die Tast PC0 nicht
> gedrückt habe, warum?

Sie leuchtet aber nur mit 50% Helligkeit.


Thomas schrieb:
> Ergebnis: wenn ich "PORTD |= (1 << PD0);" weg lasse brennt die LED0,
> warum?

Ein Blick in das Manual des STK500 zeigt, daß Tasten und LEDs low aktiv 
sind.

von Thomas (Gast)


Lesenswert?

@Frank: OK, C-Formatierung, verstanden

@Peter: Da liegt das Problem!


Danke für die schnelle Hilfe!!!

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


Lesenswert?

Frank M. schrieb:
> Auf Deutsch: Du sollst beim nächsten Mal Deinen C-Code ...
> einbetten, damit man ihn auch lesen kann.
Und gratis gibts dazu dann noch das Hochlicht namens 
"Syntax-Highlighting".

Thomas schrieb:
> Die LEDs sind auf dem STK500 mit dem PORTD über das Flachbandkabel
> verbunden. Genauso die Taster mit PORTC.
Das war es nicht, was ich mit "Beschaltung" gemeint habe.
Sondern ich meinte, bei welchem Pegel am Pin die LED leuchtet: leuchtet 
sie, wenn du 0/low/0V ausgibst, oder leuchtet sie wenn du 1/high/5V 
ausgibst?
Und welchen Pegel bekommst du am Pin, wenn du den Taster drückst? Und 
welchen, wenn du den Taster nicht drückst.

Und wenn du das herausgefunden hast, dann siehst du dir den Schaltplan 
an und überlegst, ob das alles soweit zusammenpasst.

> Solange ich den Taster gedrückt halte geht die LED aus. Wenn ich im
> falschen Moment drücke, bleibt sie an, aber das ist ja auch ok so.
Wenn du dieses Verhalten von deinem Code erwartest, dann ist ja alles 
gut. Auf jeden Fall macht der µC das, was du programmiert hast. Auch 
wenn sich das nicht unbedingt mit dem deckt, was du erwartest.

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

Thomas schrieb:
> for(;;) {
>    // main loop
> }

Die leere Main loop ist nicht notwendig, denn der Compiler fügt sie ggf. 
automatisch in den Maschinencode ein. Wenn da aber sinnvoller Code drin 
steht, ist sie natürlich notwendig.

> return (0);

Das return Statement ist nutzlos, weil die main() Funktion niemals 
endet.

von F*ck (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das return Statement ist nutzlos, weil die main() Funktion niemals
> endet.

Aber wenn man eine Funktion definiert die einen Return-Wert
ergibt dann schreibt man "anständigerweise" auch eine
Return-Operation hin. Bei nicht-main Funktionen geht das
Weglassen sowieso nicht.

Ältliche und voll-warnende Compiler melden an dieser Stelle
zumindest eine Warning wenn nix zurückgegeben wird. YMMV.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Die leere Main loop ist nicht notwendig, denn der Compiler fügt sie ggf.
> automatisch in den Maschinencode ein.

Eine leere Endlosschleife ist prinzipiell bei µCs richtig, um den µC 
gezielt an einer Stelle anzuhalten.

Dass bei AVRs tatsächlich nach Verlassen der main-Funktion eine 
Endlosschleife ausgeführt wird, ist hier zufälligerweise richtig. Denn 
es ist überhaupt nicht garantiert bei irgendewelchen 
µC-Laufzeitumgebungen. Von daher halte ich Deinen Hinweis für 
überflüssig - überflüssiger jedenfalls als die Endlosschleife selbst. 
Abgesehen davon ist Deine Aussage in der Allgemeinheit sogar falsch.

> Das return Statement ist nutzlos, weil die main() Funktion niemals
> endet.

Da die main()-Funktion vom Typ int ist, geziemt es sich durchaus, auch 
ein formales return-Statement vorzusehen - auch wenn neuere C-Standards 
mittlerweile fordern, dass ein fehlendes return in der main-Funktion 
(und nur in der main-Funktion!) implizit vom C-Compiler hinzugefügt 
wird. Aber das macht ein selbst eingefügtes return-Statement *nicht 
falsch*.

: Bearbeitet durch Moderator
von Einer K. (Gast)


Lesenswert?

F*ck schrieb:
> Ältliche und voll-warnende Compiler melden an dieser Stelle
> zumindest eine Warning wenn nix zurückgegeben wird.
Und moderneren kann man ein "No Return" Attribut mitgeben.

Stefan ⛄ F. schrieb:
> Die leere Main loop ist nicht notwendig, denn der Compiler fügt sie ggf.
> automatisch in den Maschinencode ein.
Blanker Unsinn!

Quelle:
1
int main(){}


Kompilat:
1
00000080 <main>:
2
int main(){}
3
  80:  90 e0         ldi  r25, 0x00  ; 0
4
  82:  80 e0         ldi  r24, 0x00  ; 0
5
  84:  08 95         ret

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Arduino Fanboy D. schrieb:
> Blanker Unsinn!

Halber Unsinn, sie wird nach dem Return ausgeführt ;-)

"Eingefügt" wird sie jedenfalls nicht vom Compiler, denn sie ist mit 
drin in der avr-libc. Von daher ist es natürlich Unsinn, was Stefanus 
schreibt.

von Einer K. (Gast)


Lesenswert?

Frank M. schrieb:
> sie wird nach dem Return ausgeführt ;-)
Du meinst:
1
00000086 <_exit>:
2
  86:  f8 94         cli
3
4
00000088 <__stop_program>:
5
  88:  ff cf         rjmp  .-2        ; 0x88 <__stop_program>
Wo dann auch der Return landet.
1
  74:  0e 94 40 00   call  0x80  ; 0x80 <main>
2
  78:  0c 94 43 00   jmp  0x86  ; 0x86 <_exit>

Das hat aber nichts mit main() und einfügen zu tun.
Das Ende ist immer da.
Und nicht
Stefan ⛄ F. schrieb:
> ggf.
"Immer" ist nicht ggf.

Frank M. schrieb:
> Von daher ist es natürlich Unsinn, was Stefanus
> schreibt.
So ist es.

von Stefan F. (Gast)


Lesenswert?

F*ck schrieb:
> Aber wenn man eine Funktion definiert die einen Return-Wert
> ergibt dann schreibt man "anständigerweise" auch eine
> Return-Operation hin. Bei nicht-main Funktionen geht das
> Weglassen sowieso nicht.
>
> Ältliche und voll-warnende Compiler melden an dieser Stelle
> zumindest eine Warning wenn nix zurückgegeben wird. YMMV.

Dann würden sie aber etwas monieren, was im Standard ausdrücklich 
vorgesehen ist:

"The body of the main function does not need to contain the return 
statement: if control reaches the end of main without encountering a 
return statement, the effect is that of executing return 0;"

https://en.cppreference.com/w/cpp/language/main_function

von Stefan F. (Gast)


Lesenswert?

Frank M. schrieb:
> Dass bei AVRs tatsächlich nach Verlassen der main-Funktion eine
> Endlosschleife ausgeführt wird, ist hier zufälligerweise richtig. Denn
> es ist überhaupt nicht garantiert

Es ist garantiert, siehe oben.

Arduino Fanboy D. schrieb:
> Blanker Unsinn!

Frank M. schrieb:
> Von daher ist es natürlich Unsinn, was Stefanus
> schreibt.

Ihr seid ja komisch drauf. Habt gerade meine Aussage bestätigt* aber 
nennt sie immer noch Unsinn. Tssss

*) Ich schrieb:
Stefan ⛄ F. schrieb:
> Die leere Main loop ist nicht notwendig, denn der Compiler fügt sie ggf.
> automatisch in den Maschinencode ein.

Ich habe nicht geschrieben, dass der code in die main()-Funktion 
eingefügt wird.

Ja, die Endlosschleife wird nicht in main() eingefügt, sondern direkt 
hinter der Stelle, wo sie aufgerufen wurde. Das ist natürlich ein 
Himmwelweiter - nein ein Galaxieweiter - Unterschied.

Man kann sich auch die Hose mit der Kneifzange anziehen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> *) Ja, die Endlosschleife wird nicht in main() eingefügt, sondern direkt
> hinter der Stelle, wo sie aufgerufen wurde. Das ist natürlich ein
> Himmwelweiter - nein ein Galaxieweiter - Unterschied.

Wie ich schon schrieb: Das ist bei der AVR-Libc zufälligerweise so - 
dokumentiert und damit garantiert ist dies nicht!

Für andere µC gilt Deine Aussage auch nicht. Von daher sollte man sich 
nicht darauf verlassen und immer eine eigene Endlosschleife vorsehen.

> Man kann sich auch die Hose mit der Kneifzange anziehen.

Man kann auch portabel programmieren und muss nicht jedes 
undokumentierte Schmankerl ausnutzen.

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

Frank M. schrieb:
> Für andere µC gilt Deine Aussage auch nicht.

Habe ich auch nicht behauptet.

In der Doku zur avr-lib befinden sich übrigens zahlreiche Beispiele, wo 
main() nicht in einer Endlosschleife endet. Insofern betrachte ich diese 
Eigenart doch als (indirekt) dokumentiert.

Beispielsweise https://www.nongnu.org/avr-libc/user-manual/FAQ.html

von Walter T. (nicolas)


Lesenswert?

Ist euch auch langweilig? Wir könnten hier "Schiffe versenken" spielen. 
Da gewinnt wenigstens einer.

von Stefan F. (Gast)


Lesenswert?

A4

von Cyblord -. (cyblord)


Lesenswert?

So ist das Stefan. Will man andere lehren so muss man präzise Ausführen. 
Und deine Ausführungen zur main() waren einfach falsch. Eine 
Endlosschleife wird danach eingefügt. Du schriebst aber was anderes. So 
einfach ist das manchmal. Den Fehler dann bockig nicht einsehen zu 
wollen zeugt nicht gerade von Größe.

: Bearbeitet durch User
von Thomas (Gast)


Lesenswert?

Also mein Tag ist gerettet:
1
int main( void )
2
{
3
  DDRD  |= (1 << DDD0);  // Pin 0 von Port D als Ausgang
4
  PORTD |= (1 << PD0);    // PD0 im PORTD setzen weil LEDs active low bei STK500
5
    
6
  PORTC |= (1 << DDC0);    // internen Pull-Up an PC0 aktivieren
7
  
8
  for(;;) {                                       // main loop
9
    
10
    while (!(PINC & (1 << PINC0)))  {    // Prüfen ob PC0 low !!!
11
      PORTD = PIND ^ ( 1 << PD0 );       // LED an
12
    }
13
    PORTD |= (1 << PD0);  // LED aus
14
    
15
  }
16
  return (0);
17
}

Das Programm tut was es soll und ich verstehe es soweit :)

Beitrag #6487341 wurde vom Autor gelöscht.
von Cyblord -. (cyblord)


Lesenswert?

Thomas schrieb:

>       PORTD = PIND ^ ( 1 << PD0 );       // LED an

Eher nicht.

> Das Programm tut was es soll und ich verstehe es soweit :)

Eher nicht.

Darum schreibt man einfach gleich:

PORTD &= ~( 1 << PD0 );
und
PORTD |= ( 1 << PD0 );

Und spart sich den ganzen Rest mit der PIND abfrage.

: Bearbeitet durch User
von Thomas (Gast)


Lesenswert?

OK, OK ...

von Johannes S. (Gast)


Lesenswert?

Sehr schöne Fehler gibt es wenn das main() verlassen wird und dann C++ 
Objekte zerstört werden wenn sie auf dem main Stack lagen.

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> *) Ich schrieb:
> Stefan ⛄ F. schrieb:
>> Die leere Main loop ist nicht notwendig, denn der Compiler fügt sie ggf.
>> automatisch in den Maschinencode ein.
>
> Ich habe nicht geschrieben, dass der code in die main()-Funktion
> eingefügt wird.
Nein?

> Die leere Main loop
Das ist das Subjekt des Satzes.

> sie
Bezieht sich auf das Subjekt
Ist also eine Wiederholung des
> Die leere Main loop

Das ist falsch!
Eine irreführende Information.
Siehe:
> Ich habe nicht geschrieben, dass der code in die main()-Funktion
> eingefügt wird.
Doch, hast du wohl.
Denn wenn eine main loop nicht in der Main sein soll, wo ist sie denn 
dann eingefügt worden?

> ggf
ggf sagt, dass es Alternativen gibt. Dass es Situationsabhängig ist.
Das "gegebenenfalls" ist an der Stelle falsch.
Eine irreführende Information.
Denn das wird nicht Fall abhängig eingefügt.

Du merkst:
1. Du hast dich geirrt.
2. Bist berichtigt worden
3. Und jetzt uneinsichtig.

Johannes S. schrieb:
> Sehr schöne Fehler gibt es wenn das main() verlassen wird und dann
> C++
> Objekte zerstört werden wenn sie auf dem main Stack lagen.
Und/Oder zwischendurch die Interrupts abgeschaltet werden, weil man ja 
keine main loop braucht, denn sie wird ja "ggf automatisch eingefügt".

von Oliver S. (oliverso)


Lesenswert?

Johannes S. schrieb:
> C++

In C++ kann es schon vorher mit einer leeren Schleife am Ende von main 
sehr schöne Effekte geben, da so etwas UB ist.

Oliver

von Stefan F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Ein Endlosschleife wird danach eingefügt. Du schriebst aber was anderes
Wo? Bitte zitiere das.

von Stefan F. (Gast)


Lesenswert?

Cyblord -. schrieb:
>>       PORTD = PIND ^ ( 1 << PD0 );       // LED an
> Eher nicht.

Unsinn, das funktioniert tadellos. Nur weil man auch PORTD anstelle von 
PIND schreiben kann, muss man es nicht.

Das ist mit bereits um 13:00 aufgefallen, aber ich kann im Gegensatz zu 
dir über unwichtige Details hinweg sehen.

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Cyblord -. schrieb:
>> Ein Endlosschleife wird danach eingefügt. Du schriebst aber was anderes
> Wo? Bitte zitiere das.

Merksatz:
> Irren ist menschlich.
> Im Irrtum verharren, ist Dummheit

Wenn es vorher ein Irrtum oder eine unglückliche Formulierung war, jetzt 
wird es, nach den Hinweisen darauf und durch dein unbeirrt fortgesetztes 
Beharrungsvermögen, zu einer dummdreisten Lüge.

Alles rumeiern wird dir nicht helfen, du bist überführt.

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Alles rumeiern wird dir nicht helfen, du bist überführt.

Weiter behaupten ohne Nachweis ist auch nicht besser.

Du und dein Kumpel Cyblord, ihr könnten auch einfach mal zugeben, dass 
ihr etwas missverstanden habt. Da ihr mich nicht leiden könnt, ist das 
nur natürlich.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Weiter behaupten ohne Nachweis ist auch nicht besser.

Hier bitte:

Stefan ⛄ F. schrieb:
> Die leere Main loop ist nicht notwendig, denn der Compiler fügt sie ggf.
> automatisch in den Maschinencode ein.

Der Compiler fügt aber keine "leere Main-Loop" ein. Denn diese müsste in 
main() stehen, um "Main-Loop" zu heißen.

Außerdem fügt der Compiler da sowieso nichts ein. Wenn, dann der Linker, 
denn die Endlosschleife nach Aufruf von main() wird nicht vom Compiler 
erzeugt, sondern vom Linker aus der avr-libc hinzugefügt. Und das ist 
unabhängig davon, ob Du in der main-Funktion selbst eine 
Endlosschleife stehen hast oder nicht. Das hat mit der Formulierung 
"ggf." überhaupt nichts zu tun.

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

Der Maschinencode ist das Ergebnis des Compilers. Dort wird die finale 
Endlosschleife eingefügt.

Wollen wir jetzt darüber diskutieren, ob der Compiler oder der Linker es 
einfügt? Das wird mir echt zu blöd.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Der Maschinencode ist das Ergebnis des Compilers. Dort wird die
> finale Endlosschleife eingefügt.

Falsch. Der Compiler übersetzt C-Files. Die finale Endlosschleife steht 
aber in libc.a. Dieser Code wird vom Linker hinzugefügt.

Immerhin nennst Du die "Main Loop" nun nicht mehr so, denn auch der 
Linker kann keine "Main Loop" in main() selbst einfügen.

Aber für mich ist hier EOD - diese Diskussion ist mir zu blöd.

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

28 von 34 Beiträgen am Thema vorbei. Ich bereue, dazu beigetragen zu 
haben.

Könnte ein anderer Moderator diesen Thread bitte schließen?

von Cyblord -. (cyblord)


Lesenswert?

Frank M. schrieb:
> Aber für mich ist hier EOD - diese Diskussion ist mir zu blöd.

Stefan, als Oberlehrer KANN Fehler nicht zugeben.

von Stefan F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Stefan, als Oberlehrer KANN Fehler nicht zugeben.

Du kannst nicht aufhören, immer wieder nachzutreten.

von HildeK (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Cyblord -. schrieb:
>>>       PORTD = PIND ^ ( 1 << PD0 );       // LED an
>> Eher nicht.
>
> Unsinn, das funktioniert tadellos. Nur weil man auch PORTD anstelle von
> PIND schreiben kann, muss man es nicht.

Nein, das war schon richtig erkannt von Cyberlord.
IMHO toggled diese Anweisung den PORTD0.
  PORTD = PIND ^ ( 1 << PD0 );
Sie macht das selbe wie
  PORTD ^= (1 << PD0);
und (fast) dasselbe wie
  PIND = (1 << PD0);
Fast, weil bei der 3. Variante PIND0 konstant bleibt, bei den beiden 
anderen wird das gegenläufig mit getoggled.

Dass beim TO die LED mit dem Befehl leuchtet liegt daran, dass sie in 
schneller Folge ein- und ausgeschaltet wird, solange die Taste gedrückt 
wird - eben dann mit reduzierter Leuchtkraft. Das fällt meist nicht auf.

Richtig ist zur Einschalten am STK500, wie Cyberlord schrieb:
  PORTD &= ~( 1 << PD0 );
wobei dieser Befehl den Port nur setzt:
  PIND ^= (1 << PD0);
also die STK500-LEDs diese ausschaltet.

Zumindest behauptet das der Simulator in meinem AVR-Studio so ...

von Cyblord -. (cyblord)


Lesenswert?

HildeK schrieb:
> Stefan ⛄ F. schrieb:
>> Cyblord -. schrieb:
>>>>       PORTD = PIND ^ ( 1 << PD0 );       // LED an
>>> Eher nicht.
>>
>> Unsinn, das funktioniert tadellos. Nur weil man auch PORTD anstelle von
>> PIND schreiben kann, muss man es nicht.
>
> Nein, das war schon richtig erkannt von Cyberlord.
> IMHO toggled diese Anweisung den PORTD0.

Korrekt. Nicht mal Bitoperationen kann Stefan fehlerfrei bewerten. Seit 
wann setzt man bits mit XOR? Und seit wann liest man dafür die 
Inputwerte eines Ports zurück? Das ist beides Unsinn den man lassen 
sollte.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Das bringt nix....
Stefan ⛄ F. schrieb:
> Da ihr mich nicht leiden könnt, ....
Da er meint, wir könnten ihn nicht leidern, wird er uns nicht zuhören, 
oder gar Irrtümer einsehen.

von Stefan F. (Gast)


Lesenswert?

Ich war davon ausgegangen, dass er die LED toggeln wollte.

Das ist falsch zitiert:
> PORTD = PIND ^ ( 1 << PD0 );       // LED an

Der Kommentar lautet:
>  // LED an Port PD0 an- bzw. aus

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> Cyblord -. schrieb:
>>>       PORTD = PIND ^ ( 1 << PD0 );       // LED an
>> Eher nicht.
>
> Unsinn, das funktioniert tadellos. Nur weil man auch PORTD anstelle von
> PIND schreiben kann, muss man es nicht.

Das sind zwei völlig verschiedene Operationen.

Einfach und problemlos ist nur die Verwendung von PORTD als Quelle des 
Bits. Das hat dort halt sicher den Zustand, der zuletzt gesetzt wurde.

Bei PIND sieht das aber völlig anders aus. Das ist der Status des 
Eingangs. Da sind zwei Sachen zu berücksichtigen:

1) Der Einfluß der äußeren Beschaltung. Das ist fundamental. Mit 
hinreichend idiotischer äußerer Beschaltung kann man jede beliebige 
Abweichung von der Idee "PINyx=PORTyx" locker hinbekommen.

2) Selbst wenn außen garnix dranhängt, hängt der Status von PINxy 
mindestens einen Systemtakt-Tick dem von PORTxy hinterher. D.h.:

ldi R16,0
out PORTB,R16
ldi R16,1
out PORTB,R16
in R16,PINB

wird im niederwertigsten Bit von R16 NICHT 1 liefern, sondern 0. 
Ergänzt man hingegen so:

ldi R16,0
out PORTB,R16
ldi R16,1
out PORTB,R16
nop
in R16,PINB

dann wird es 1 liefern, obwohl NOP lt. Definition nix tut, außer einen 
Takt Zeit zu verbrauchen...

Du mußt noch sehr, sehr viel lernen...

von Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> Du mußt noch sehr, sehr viel lernen...

Der Unterschied ist mir durchaus bekannt, für die Anwendung des TO 
jedoch irrelevant.

Möchte noch jemand Nachtreten? Kommt schon, ich bin gerade in Stimmung. 
Hier versammelt sich gerade die creme de la creme des Forums.

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> Der Unterschied ist mir durchaus bekannt, für die Anwendung des TO
> jedoch irrelevant.

Du bist also auch noch Hellseher? Ich habe jedenfalls im Thread kein 
Schaltschema des TO entdecken können, was eine abschließende Bewertung 
zur Relevanz ermöglicht hätte...

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Möchte noch jemand Nachtreten? Kommt schon, ich bin gerade in Stimmung.
Kein Problem....

Stefan ⛄ F. schrieb:
> Ich war davon ausgegangen, dass er die LED toggeln wollte.

Dann tut man das so:
PIND = (1 << PD0);
(aber das auch wurde schon gezeigt)

von Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> Du bist also auch noch Hellseher?

Warum fragst du nicht den TO, was er beabsichtigt hatte?

Die folgenden zwei Anweisungen tun in seiner Anwendung effektiv da 
gleiche:

PORTD = PIND ^ ( 1 << PD0 );
PORTD = PORTD ^ ( 1 << PD0 );

Nur darum ging es bei meiner Aussage

> Nur weil man auch PORTD anstelle von
> PIND schreiben kann, muss man es nicht.

Hier in diesem Thread sieht man mal wieder sehr deutlich, dass 
missverstanden wird, wenn man missverstehen will. Bzw. man findet Fehler 
wenn man danach sucht.

Ihr kritisiert, dass ich den TO falsch lehre. Glaubt ihr im Ernst, dass 
er aus euren Beiträgen etwas gelernt hat? Ich glaube, er hat gelernt, 
mit wem er besser nicht diskutiert.

Die Frage des TO interessiert euch kein bisschen mehr. Ich habt euch 
darauf eingeschossen, mich bloß zu stellen. Und das zieht ihr jetzt 
knallhart durch. Völlig egal, ob damit irgend wem geholfen wird.

Es hilft weder euch noch mir. Am Ende verfestigt sich nur unsere 
gegenseitige Abneigung. Seid ihr darauf Stolz?

Ich bin es nicht. Wie gesagt: ich bereue das alles längst.

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> aber die folgenden drei Anweisungen tun in seiner Anwendung
> effektiv da gleiche:
>
> PORTD = PIND ^ ( 1 << PD0 );
> PORTD = PORTD ^ ( 1 << PD0 );

Nein, das sind sie eben nicht notwendigerweise. Ich habe dir 
detaillierte Gegenindikationen vorgestellt.

Begreifst du das nichtmal dann, wenn man es dir förmlich "mit der 
nackten Faust ins Gesicht rammt"?

Oder bist du nur nicht bereit, darüber auch nur nachzudenken?

Oder weißt du inzwischen, dass du falsch lagst, willst es nur nicht 
zugeben?

Fragen über Fragen...

von Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> Nein, das sind sie eben nicht notwendigerweise. Ich habe dir
> detaillierte Gegenindikationen vorgestellt.

Welche in der Anwendung des TO keine Rolle spielen.

von Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> Begreifst du das nichtmal dann, wenn man es dir förmlich "mit der
> nackten Faust ins Gesicht rammt"?

Auf diese Art begreifst du gar nichts.

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> c-hater schrieb:
>> Nein, das sind sie eben nicht notwendigerweise. Ich habe dir
>> detaillierte Gegenindikationen vorgestellt.
>
> Welche in der Anwendung des TO keine Rolle spielen.

Was du woher genau weißt?

Es steht ja schließlich immer noch das Problem des fehlenden Schemas der 
Hardware, was aber nach der Erkenntnis, dass die halt bei der Verwendung 
der Eingänge zwingend eine entscheidende Rolle spielt, doch deutlich 
störend für eine Bewertung ist, inwiefern die Verwendung von PIND statt 
PORTD eine Rolle spielt.

Also doch Hellseher-Syndrom...

Oder, noch schlimmer: bist du etwa (auch) der TO? Wäre logisch 
denkbar...

Dann kennst du natürlich die Schaltung, wärest aber ein unsäglicher 
Troll...

von Stefan F. (Gast)


Lesenswert?

Frag doch den TO, anstatt meine Annahmen zu kritisieren.

> bist du etwa der TO?

nein.

Aber interessant, dass du mir hier zutraust, so eine Show abzuziehen: 
Erst eine Frage stellen und mir dann selbst antworten.

Wie kommst du auf diese Idee, machst du so etwas etwa?

von unglaublich (Gast)


Angehängte Dateien:

Lesenswert?

Der TE ist längst weg

von Cyblord -. (cyblord)


Lesenswert?

Es macht IMO absolut keinen Sinn mehr über technische Dinge mit Stefan 
zu diskutieren. Die offensichtlichsten Fakten werden ignoriert und 
geleugnet. Die einfachsten Dinge unmöglich verkompliziert. Ich erkenne 
auch keine Fachkompetenz. Nur ein wenig Halbwissen und viel Starrsinn.

Gerade Anfänger werden hier durch solche Nutzer stark verunsichert. 
Anfänger brauche eine klare Ansage wie es zu machen ist. Und keine 
verschwurbelten Diskussionen unter welchen unwahrscheinlichen Umständen 
irgendeine falsche Lösung vielleicht doch mal richtig sein könnte. Das 
hilft niemandem. Nur Stefans Ego. Echt ärmlich.

: Bearbeitet durch User
von thomas (Gast)


Lesenswert?

...und ich dachte, ich hätte eine ganz einfache Frage gestellt...

habe in meinem Code nun das
PORTD = PIND ^ ( 1 << PD0 );
durch
PORTD &= ~( 1 << PD0 );
ersetzt.
Damit funktioniert es so wie ich das wollte, solange die Taste gedrückt 
ist leuchtet die LED, sonst ist sie aus:
1
for(;;) {                                       // main loop
2
    
3
    while (!(PINC & (1 << PINC0)))  {    // Prüfen ob PC0 low !!!
4
      PORTD &= ~( 1 << PD0 );       // LED an
5
    }
6
    PORTD |= (1 << PD0);  // LED aus
7
    
8
  }

Das ganze war auch nur eine Übung für mein Verständnis, weil ich 
folgendes realisieren wollte:
1
int main( void )
2
{
3
    
4
  PORTC |= (1 << DDC0) | (1 << DDC0);    // interne Pull-Up an PC0 und PC1 aktivieren
5
  
6
  // Timer 1
7
  DDRB = (1<<DDB1);               // use PB1 for output
8
  // Timer1 CTC Mode, Toggle OC1A on compare match
9
  TCCR1A = (1<<COM1A0) ;
10
11
  // Prescaler 64 --> 4MHz/64 = 62500Hz
12
  TCCR1B =  (1<<WGM12) | (1<<CS11) | (1<<CS10);
13
  
14
  // preset timer0 high/low byte
15
  OCR1A = 624;   // 624 enspricht 50Hz, 830 entspricht 37Hz, 500 entspricht 62Hz
16
  // Ende Timer 1
17
  
18
  for(;;) {                                       // main loop
19
    
20
    OCR1A = 625;    // 50 Hz
21
    
22
    while (!(PINC & (1 << PINC0)))  {    // Prüfen ob PC0 low !!!
23
      OCR1A = 500;      // 62 Hz
24
    }
25
    
26
    while (!(PINC & (1 << PINC1)))  {    // Prüfen ob PC1 low !!!
27
      OCR1A = 830;    // 37 Hz
28
    }
29
    
30
  }
31
  return (0);
32
}

Und das tut zu meiner Freude auch!

Seltsam ist nur, dass es manchmal (d.h. nicht immer) beim Umschalten der 
Frequenz hakt. Es braucht dann ca. eine Sekunde bis das Oszi das 
Rechtecksignal und die Frequenz wieder anzeigt.
Könnte es daran liegen, wann ich im CTC Zyklus die Taste drücke?

von Peter D. (peda)


Lesenswert?

thomas schrieb:
> Könnte es daran liegen, wann ich im CTC Zyklus die Taste drücke?

Ja.
Du mußt die Umschaltung mit dem Timer synchronisieren.

von HildeK (Gast)


Lesenswert?

thomas schrieb:
> Seltsam ist nur, dass es manchmal (d.h. nicht immer) beim Umschalten der
> Frequenz hakt. Es braucht dann ca. eine Sekunde bis das Oszi das
> Rechtecksignal und die Frequenz wieder anzeigt.

Vielleicht liegt es daran, dass du z.B. den PINC1 zu einem Zeitpunkt 
loslässt, wo der TCNT1 schon über 500 oder 625 ist, aber noch unter 830 
steht. Dann wird TCNT1 einmal komplett durchzählen mit Überlauf bei 
65535. Das dauert bei 62kHz schon etwas mehr als eine Sekunde.

Es könnte auch sein, dass da das Skope eine Triggerpause macht. 
Unwahrscheinlich.
Zum Testen könntest du mit dem Prescaler das Ganz so langsam machen, 
dass du die Frequenzänderung direkt am LED-Blinken sehen kannst.

von thomas (Gast)


Lesenswert?

Danke!

Denke so geht's:
1
for(;;) {                                       // main loop
2
    
3
    if (TCNT1 == 0)
4
    OCR1A = 625;    // 50 Hz
5
    
6
    while (!(PINC & (1 << PINC0)))  {    // Prüfen ob PC0 low !!!
7
      if (TCNT1 == 0)
8
      OCR1A = 500;      // 62 Hz
9
    }
10
    
11
    while (!(PINC & (1 << PINC1)))  {    // Prüfen ob PC1 low !!!
12
      if (TCNT1 == 0)
13
      OCR1A = 830;    // 37 Hz
14
    }
15
    
16
  }

Jetzt muss nur noch ein Poti über den ADC die Grundfrequenz von 50Hz 
feinfühlig bis zu +/- 2Hz verstellen können...

von Joachim B. (jar)


Lesenswert?

HildeK schrieb:
> Vielleicht liegt es daran, dass du z.B. den PINC1 zu einem Zeitpunkt
> loslässt

was ist mit Tastenprellen?
IMHO ohne Entprellung wird das doch eh nix?

Diese Art der Programmierung ohne Entprellung ist IMHO nicht 
zielführend.
Es gibt so schöne SW dafür, zwar mit Unsicherheiten -> Entprellzeit ist 
aber bei Tastenabfrage unvermeidlich, entweder wird zu früh erkannt wenn 
gedrückt wird oder zu spät wenn losgelassen wird.

https://www.mikrocontroller.net/articles/Datei:Entprellen.png
https://www.mikrocontroller.net/articles/Entprellung#Timer-Verfahren_.28nach_Peter_Dannegger.29

: Bearbeitet durch User
von thomas (Gast)


Lesenswert?

Joachim B. schrieb:
> was ist mit Tastenprellen?

Dachte ich erst auch, aber da ich die Tasten ja gedrückt halte brauche 
ich es vermutlich doch nicht. Habe ich auch in verschiedenen Posts so 
gelesen...

von Arno (Gast)


Lesenswert?

Wenn es egal ist, dass auch der Ausgang potentiell prellt (also beim 
Drücken der Taste von 50Hz auf 37Hz auf 50Hz auf 37Hz springt) und erst 
nach ein paar zig Millisekunden stabil auf 37Hz liegt, brauchst du dir 
um Prellen in dieser Anwendung keine Sorgen zu machen. Bei den 
Frequenzen fällt das wahrscheinlich noch nichtmal auf, bei dem 
LED-Beispiel vorher hättest du halt fast 1:1 das Prellen an die LED 
durchgereicht. Der das auch nichts ausmacht.

Eine ziemlich undefinierte Entprellung hast du jetzt bei der 
Frequenzumschaltung aus Versehen ja auch schon dabei, weil du wartest, 
bis der Timer 0 erreicht.

MfG, Arno

von Einer K. (Gast)


Lesenswert?

Ach da gibts noch ganz andere Probleme....

thomas schrieb:
> TCNT1 == 0
Dann kann/wird zu Sorgen führen, wenn noch weitere Sachen erledigt 
werden wollen.
z.B. der ADC steht noch auf dem Plan.

Dann die 2 While Schleifen...
Schön ist das nicht.

Mein erster Gedanke wäre:
1. 3 Zustände
2. Tasten gesteuert
Das schreit nach einem endlichen Automaten. Sei er auch noch so 
primitiv.

Das kostet etwas Hirnschmalz, und auch Flash.
Aber dafür schafft es den Zeitraum für viele viele weitere Abhandlungen.
In dem Zuge kann man auch das entprellen und Flanken erkennen abhandeln. 
Ist ja auch nur ein weiterer kleiner Automat.

von HildeK (Gast)


Lesenswert?

Arno schrieb:
> Eine ziemlich undefinierte Entprellung hast du jetzt bei der
> Frequenzumschaltung aus Versehen ja auch schon dabei, weil du wartest,
> bis der Timer 0 erreicht.

Ja.
Aber selbst wenn man ganz nahe am Überlauf drückt und die Prellung zum 
Überlaufzeitpunkt noch nicht abgeklungen ist, dann wird schlimmstenfalls 
noch eine Periode mit der alten oder der Frequenz bei 'nichts gedrückt' 
ausgegeben.
Ob das stört, hängt von der Anwendung ab.

von Stefan F. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Es macht IMO absolut keinen Sinn mehr über technische Dinge mit Stefan
> zu diskutieren.

Wie oft willst du noch nachtreten?

von OMG (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wie oft willst du noch nachtreten?

Es hätte gereicht wenn du ganz am Anfang einfach mal die
Fresse gehalten hättest.

Nicht weil der eine oder der andere Recht hat sondern weil du
zu jedem Thema einfach deinen Senf dazu geben musst obwohl
ihn keiner braucht.

von Stefan F. (Gast)


Lesenswert?

OMG schrieb:
> weil du zu jedem Thema einfach deinen Senf dazu geben musst

Das ist nicht einmal Ansatzweise wahr.

Wenn mich jemand missverstanden hat (evtl. weil ich mich unklar 
ausgedrückt habe), dann scheint mir eine Klarstellung durchaus für 
Sinnvoll. gewisse Personen nutzen solche Fälle allerdings als 
Gelegenheit, andere regelrecht nieder zu machen - nicht nur mich.

Ich denke nicht, dass ich daran direkt Schuld bin. Jedoch habe ich 
bereits zweimal geschrieben, dass ich bereue, diesen Scheißdreck 
ausgelöst zu haben.

von OMG (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> dass ich bereue, diesen Scheißdreck ausgelöst zu haben.

Dann halt doch endlich mal die Fresse.
Einfach einstecken und gut is.

von Karl B. (gustav)


Lesenswert?

Hi,
Also,
dann lass mal den Debugger (Simulator) im ATMEL Studio drüber laufen.
(Hab WinAVR gerade nicht installiert. So wäre es für mich nötig, in ASM 
rückzuübersetzen.) Dann sieht man, was da passiert.
Da war jemand schneller.
HildeK schrieb:
> Zumindest behauptet das der Simulator in meinem AVR-Studio so ...

Lothar M. schrieb:
> Frank M. schrieb:
>> Auf Deutsch: Du sollst beim nächsten Mal Deinen C-Code ...
>> einbetten, damit man ihn auch lesen kann.
> Und gratis gibts dazu dann noch das Hochlicht namens
> "Syntax-Highlighting".

Und ich speicher die Programmschnipsel immer als Textdatei ab und nenne 
sie dann in *.asm um, oder was gerade gefordert wird. (Das Gedöns mit 
den Tags klappt bei mir nicht. Ich kann weder fett noch irgendwas 
anderes editieren.)
Dann lade ich sie als Anlage hoch.
Sonst wird bei etwas umfangreicheren Beispielen die Sache (gerade bei 
Smartphoneusern) hier extrem unübersichtlich.

ciao
gustav

von Einer K. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich denke nicht, dass ich daran direkt Schuld bin.


Du hast Unsinn geschrieben.
Gibst es nicht zu.

Und daran sind natürlich die anderen Schuld.
(ihr liebt mich nicht)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan, ich bitte Dich direkt am Anfang, diesen Beitrag erst *dreimal 
gründlich durchzulesen*, bevor Du wieder innerhalb weniger Minuten 
reflexartig antwortest. Mir drängt sich nämlich immer bei Deinen 
schnellen Antworten der Verdacht auf, dass Du die Antworten auf Deine 
Beiträge immer nur querliest und nur die Hälfte mitbekommst.

Stefan ⛄ F. schrieb:
> OMG schrieb:
>> weil du zu jedem Thema einfach deinen Senf dazu geben musst
>
> Das ist nicht einmal Ansatzweise wahr.

Deinen ursprünglichen Erst-Beitrag hättest Du Dir einfach sparen sollen.

Begründung:

1. Endlosschleife

Deine Info, auf eine explizite eigene Endlosschleife zu verzichten, ist 
komplett überflüssig und sogar schädlich. Jeder nutzt eine eigene 
Endlosschleife, wenn er einen µC anhalten will und nutzt dafür nicht 
eine zufällige Eigenschaft irgendeiner libc - hier der avr-libc. 
Schließlich fehlte auch von Dir die Anmerkung, dass dieses "Feature" 
auch nur bei AVRs so funktioniert und der TO bei einem Wechsel zu einer 
anderen Mikroconcontroller-Familie durchaus auf die Nase fliegen kann.

Deine Erklärung, dass der Compiler ggf eine Main-Loop einfügt, war 
nicht zutreffend. Hier muss man schon ganz genau sein, um den 
Sachverhalt zu erklären. Sonst setzt sich Deine nicht zutreffende 
Schilderung in den Köpfen der geneigten Leser fest. Genau daran haben 
sich einige hier gestört. Das hat auch nichts mit persönlichen Angriffen 
zu tun.

2. Return in main()

Wie ich schon schrieb, ist es grundsätzlich nicht falsch, ein eigenes 
return in main() zu verwenden - schon gar nicht schädlich. Ältere 
Compiler meckern sogar, wenn das return in main() fehlt, denn erst 
neuere Compiler kennen diese neue C-Regel.

Fazit:

Dein Beitrag war einfach hyperfluid und erweckt den Eindruck an den TO, 
er hätte zwei Fehler gemacht. Hat er aber nicht - ganz im Gegenteil. Er 
hat es - was Endlosschleife und Return betrifft - absolut richtig 
gemacht.

So wie Du es vorschlugtest, macht man es jedenfalls nicht. Und nein, 
man muss nicht für jeden Sachverhalt seinen eigenen Senf hinzugeben - 
jedenfalls nicht dann, wenn man es gar nicht so genau weiß.

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

Frank M. schrieb:
> Deinen ursprünglichen Erst-Beitrag hättest Du Dir einfach sparen sollen.

Das ist mir schon lange klar. Ich weise jetzt zum vierten mal darauf 
hin, dass es mir leid tut.

Frank M. schrieb:
> man muss nicht für jeden Sachverhalt seinen eigenen Senf hinzugeben -
> jedenfalls nicht dann, wenn man es gar nicht so genau weiß.

Richtig. Manchmal glaubt man allerdings, es zu wissen. Und manchmal 
macht man (mit oder ohne Absicht) den Fehler, nicht die korrekten Worte 
zu verwenden.

Was das return(0) angeht:
Hinter einer Endlosschleife ist es sinnlos. Diese Zeile wird nie 
erreicht. Manche Quelttext-Checker meckern das sogar an (unreachable 
statement). Java würde so etwas nicht einmal compilieren.

Ihr dürft diese Info gerne "Unsinn" nennen, und das so oft wiederholen 
wir ihr wollt. Mich überzeugt ihr damit nicht.

von thomas (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
>Ach da gibts noch ganz andere Probleme....

Das ist leider nur allzu richtig!

Die while Schleifen sind zwar nicht schön, aber sie hatten für meine 
Zwecke ausreichend gut funktioniert bis ich den ADC mit Interupt 
eingeschaltet habe :(

Für den "endlichen Automaten" könnte ich gut noch einen Tip oder ein 
Beispiel gebrauchen...
Mein Hirnschmalz ist ohnehin schon ziemlich dünnflüssig.

Letztendlich soll das die Ansteuerung eines Synchronmotors von einem 
alten russischen Teleskop werden der mit 50Hz läuft. Mit den Tasten will 
ich ihn schneller oder langsamer drehen lassen können, mit dem Poti die 
50Hz gegebenenfalls etwas regulieren. Ich denke, dass die Anwendung ein 
paar Ungenauigkeiten schon verkraftet, wenn nach dem Einstellen die 
eingestellte Frequenz durchläuft.

von Joachim B. (jar)


Lesenswert?

Stefan ⛄ F. schrieb:
> Was das return(0) angeht:
> Hinter einer Endlosschleife ist es sinnlos. Diese Zeile wird nie
> erreicht. Manche Quelttext-Checker meckern das sogar an (unreachable
> statement).

aber meist ist main auch als int definiert und andere 
"Quelttext-Checker" oder Quältext-Checker? meckern dann das es kein 
return gibt.
Also sauber programmiert ist es immer mit return auch wenn das nie 
erreicht wird!

Verstehe eine die Programmierer die mal das Eine und mal das Andere 
monieren!

: Bearbeitet durch User
von Karl B. (gustav)


Lesenswert?

thomas schrieb:
> Für den "endlichen Automaten" könnte ich gut noch einen Tip oder ein
> Beispiel gebrauchen...

Hi,
leider nur ASM.
Aber Suchbegriff "Job"register könnte evtl. weiterhelfen.

ciao
gustav

von HildeK (Gast)


Lesenswert?

thomas schrieb:
> Die while Schleifen sind zwar nicht schön, aber sie hatten für meine
> Zwecke ausreichend gut funktioniert bis ich den ADC mit Interupt
> eingeschaltet habe :(

Sie sind auch nicht nötig. In der jetzigen Routine fragst du die Tasten 
ja bei jedem Durchlauf ab.
Es reicht, wenn man bei den Tasten feststellst, ob sich deren Zustand 
geändert hat. Und nur dann änderst du entsprechend OCR1A. Jetzt wird 
aber eine Entprellung notwendig sein.
ADC-Interrupt? Kann man nehmen, muss man aber nicht. Immer mal wieder 
aufrufen im Single Conversion Mode. Am besten in Kombination (oder jetzt 
anstatt?) mit den Tasten in einem Timerinterrupt.
Neue Werte für den ADC wirst du seltener benötigen, ein Zähler im 
Timerinterrupt hilft das gröbere Raster für den ADC-Aufruf zu markieren.

von Dietrich L. (dietrichl)


Lesenswert?

thomas schrieb:
> Für den "endlichen Automaten" könnte ich gut noch einen Tip oder ein
> Beispiel gebrauchen...

https://www.mikrocontroller.net/articles/Statemachine

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> Stefan ⛄ F. schrieb:
>> Was das return(0) angeht:
>> Hinter einer Endlosschleife ist es sinnlos. Diese Zeile wird nie
>> erreicht. Manche Quelttext-Checker meckern das sogar an (unreachable
>> statement).
>
> aber meist ist main auch als int definiert und andere
> "Quelttext-Checker" oder Quältext-Checker? meckern dann das es kein
> return gibt.

Wobei return bei main optional ist, zumindest wenn ich C11 (hosted) 
richtig interpretiere:
1
5.1.2.2.3 Program termination
2
3
1 [...] reaching the } that terminates the main function
4
  returns a value of 0. [...]

und für C++
1
3.6.1 Main function [basic.start.main]
2
3
5 [...] If control reaches the end of main without encountering
4
  a return statement, the effect is that of executing return 0;

Wenn also irgendein Checker meckert, ist das nicht gerechtfertigt.  Und 
GCC zum Beispiel meckert main ohne finales return ebenfalls nicht an, 
auch dann nicht, wenn es erreichbar ist.

von Joachim B. (jar)


Lesenswert?

Johann L. schrieb:
> GCC zum Beispiel meckert main ohne finales return ebenfalls nicht an

es gibt ja nicht nur GCC, mein Text war eben beispielhaft für alles was 
mir schon begegnet ist!
Es gibt auch noch Compileroptionen und wehe man aktiviert mal alle 
Warnungen, soviel Fehler kann man kaum machen was da alles bemängelt 
wird.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ändert doch nix dran, dass ein Programm mit return 0 am Ende von main 
semantisch das gleiche ist wie ein Programm ohne return am Ende von 
main.

Wenn ein Feld-Wald-und-Wiesen-Programmierer das nicht weiß ist es ok, 
aber wenn ein Tool-Hersteller das nicht weiß, dann spricht das nicht für 
diesen Hersteller.

von Joachim B. (jar)


Lesenswert?

da hast du Recht!
Nur diese Diskusion habe ich meist aufgegeben, führt zu nichts, man muss 
es hinnehmen und so machen wie der Compiler es will, sinnvoll oder nicht 
ist nicht gefragt!

von Stefan F. (Gast)


Lesenswert?

Das "return 0" optional ist, war laut Spezifikation schon immer so. Ich 
wiederhole nochmal mein Zitat:

"The body of the main function does not need to contain the return
statement: if control reaches the end of main without encountering a
return statement, the effect is that of executing return 0;"

https://en.cppreference.com/w/cpp/language/main_function

Dort gibt es keinen Hinweis, dass das erst ab einer bestimmten Version 
gilt.

Auch in C ist und war es gemäß der Webseite schon immer optional:

"If the main function executes a return that specifies no value or, 
which is the same, reaches the terminating } without executing a return, 
the termination status returned to the host environment is undefined. 
(until C99)

If the returned type is compatible with int and control reaches the 
terminating }, the value returned to the environment is the same as if 
executing return 0; (since C99)"

https://en.cppreference.com/w/c/language/main_function

von thomas (Gast)


Lesenswert?

@Hilde,
danke, ich guck mal was ich da so hinkriege...

@Dietrich,
faszinierend der Link mit der Statemachine, übersteigt aber im Moment 
meine programmiertechnischen Fähigkeiten.

@Stefan,
soll ich das "return 0" jetzt besser nicht verwenden?

von Einer K. (Gast)


Lesenswert?

thomas schrieb:
> @Stefan,
> soll ich das "return 0" jetzt besser nicht verwenden?
Völlig egal.

von HildeK (Gast)


Lesenswert?

thomas schrieb:
> @Hilde,
Wenn du kich meinst, dann HildeK!  :-)

> soll ich das "return 0" jetzt besser nicht verwenden?
Ein 'return' in main() bei μCs ist nutzlos, schadet aber auch nicht. Es 
gib ja keinen aufrufenden Prozess, an den etwas zurückgegeben werden 
kann.
C wird aber auch in Umgebungen mit Betriebssystemen verwendet und da ist 
es durchaus sinnvoll auf diesem Weg eine Erfolgs- oder 
Misserfolgsmeldung auszugeben.

von Stefan F. (Gast)


Lesenswert?

thomas schrieb:
> soll ich das "return 0" jetzt besser nicht verwenden?

Ist praktisch egal. Hauptsache es ist compilierbar.

von Peter D. (peda)


Lesenswert?

thomas schrieb:
> soll ich das "return 0" jetzt besser nicht verwenden?

Du hast ja im Main immer eine Endlosschleife, d.h. das Main wird nie 
verlassen. Also ist alles, was hinter der Schleife steht, toter Code und 
wird auch nicht implementiert. Der Compiler ist ja nicht doof.
Du kannst also alles dahinter schreiben, was Du lustig bist.
Persönlich gefällt es mir besser, wenn kein toter Code hingeschrieben 
wird, d.h. hinter der schließenden Klammer der Endlosschleife folgt nur 
noch die schließende Klammer des Main.

Du darfst natürlich auch auf MCs Programme schreiben, die das Main 
verlassen, aber sowas ist recht sinnfrei. Falls es wirklich nichts mehr 
zu tun gibt, bis zum nächsten Reset, dann geht man doch besser in Sleep 
und spart Strom.

Prinzipiell kann ein Main auch sich selber rekursiv aufrufen, aber sowas 
macht man nur im Obfuscated C Code Contest.

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> Prinzipiell kann ein Main auch sich selber rekursiv aufrufen, aber sowas
> macht man nur im Obfuscated C Code Contest.

Darüber habe ich noch nie nachgedacht, aber: Was passiert, wenn ich am 
Ende von main() main() wieder aufrufe? Habe ich dann einen sauberen 
Neustart (da End-Rekursiv) oder wächst mein Stack dann immer tiefer?

(Lassen wir mal den Heap außen vor. Den nutzen ja anständige Menschen 
auf dem AVR eh nicht.)

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> Habe ich dann einen sauberen Neustart (da End-Rekursiv)

Nein.

> oder wächst mein Stack dann immer tiefer?

Ja.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Prinzipiell kann ein Main auch sich selber rekursiv aufrufen,

Nicht in C++
1
3.6.1 Main function [basic.start.main]
2
3
3 The function main shall not be used (3.2) within a program. [...]

Und was C angeht, hat avr-gcc eine Optimierung, die Aufrufe von main im 
Endeffekt UB machen, es sei denn man verwendet -mno-main-is-OS_task, 
siehe

http://gcc.gnu.org/gcc-8/changes.html#avr

Logischerweise darf main dann auch weder Attribut OS_task noch OS_main 
tragen.

> Du darfst natürlich auch auf MCs Programme schreiben, die das Main
> verlassen, aber sowas ist recht sinnfrei.

Es gibt mindestens eine Anwendung, wo das sehr sinnvoll ist, nämlich bei 
Ausführung der GCC Testsuite — wobei das streng genommen nicht "auf MC" 
ist:

Es ist wesentlich einfacher und konsistenter, das Verlassen von main 
standardkonform zu behandeln, als händisch Testfälle auszuschließen, die

* atexit testen / verwenden

* Statische Destruktoren testen / verwenden (C++)

* __attribute__((_destructor_)) testen / verwenden (GCC Erweiterung)

* Code in Section .fini9 ... .fini0 haben (avr-spezifisch)

Wobei der Simulator (avrtest) hierzu noch etwas Extra-Code braucht:

https://sourceforge.net/p/winavr/code/272/tree/trunk/avrtest/dejagnuboards/exit.c#l100

Das ist auch der Grund, warum in der avr-libc am Ende des Startup-Codes 
in .init9 steht
1
    [r]call main
2
    [r]jmp exit
und eben nicht
1
    [r]jmp main
obwohl das 2 Bytes RAM und 6–8 Bytes Flash kostet.

http://svn.savannah.nongnu.org/viewvc/avr-libc/trunk/avr-libc/crt1/gcrt1.S?revision=2519&view=markup#l297

: Bearbeitet durch User
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.