Ich hätte als 74-jähriger autodidaktischer C-Lehrling eine grosse Bitte!
Wäre jemand von euch Profis so nett, mir einen Ratschlag zu folgendem
Programm zu geben, bei dem 3 Stk. 7-Segment-Anzeigen im Multiplexbetrieb
über PORTB angesteuert werden sollen. Verwendet wird ein ATMega48.
Die Ausgabezahl ist vorgegeben fürs Erste.
Ich erhalte folgende Warnmeldungen:
return type of main is not 'int'
(verstehe ich zwar auf Grund der Berechnungen,aber wie korrigieren?)
und
unused variable 'segmenttable'
1
/* 7-SEGMENT-ANZEIGE Multiplexbetrieb mit drei 7-Segment-Anzeigen, CA,
2
Ansteuerung an PORTB0, PORTB1 und PORTB2 mit PNP Transistoren
> return type of main is not 'int'> (verstehe ich zwar auf Grund der Berechnungen,aber wie korrigieren?)
Dein Compiler ist etwas hyperaktiv. :)
> void main (void)
Du sagst hier das dein main keinen Wert zurueckliefert. Das machst ja
auch nicht und das macht embedded auch nicht viel sinn. In PC-Umgebungen
liefern Programm aber ueblicherweise einen Rueckgabewert wenn sie sich
beenden.
Also ignorieren, abschalten oder auf int wechseln.
> unused variable 'segmenttable'
Du definierst hier:
const uint8_t segmenttabel[11] =
Eine Variable und verwendest aber: segmenttable
Das mag ja fuer menschliche Gehirne aehnlich aussehen unterscheidet sich
aber doch.
Olaf
Gerhard H. schrieb:> return type of main is not 'int'> (verstehe ich zwar auf Grund der Berechnungen,aber wie korrigieren?)
versuche mal den main als
int main (void)
{
...
return 0;
}
zu definieren. Klar auf dem Kontroller macht so etwas keinen Sinn, weil
die Rückgabewert nie ausgewertet wird. Aber manche Compilers bestehen
darauf.
> const uint8_t segmenttable[11];
Zeile 14: Variable wird definiert aber nirgendwo verwendet.
Zeile 37: Variable const uint8_t segmenttabel[11] = wird definiert und
verwendete.
segmenttabel ist nicht gleich
segmenttable
Zeile 14 löschen. Zeile 37 geht nach oben wo Zeile 14 war. Dann ist es
global und wird im ROM gespeichert.
Danke euch schön. Werde weiter testen.
Ich habe wirklich herumgegoogelt wie der Böse, konnte aber zu keinem
positiven Resultat gelangen.
Wenn ich am Kopf die Deklaration von 'segmenttable' weglasse, komme ich
zu einer Fehlermeldung, aber ich werde schauen, dass ich mit eurer
freundlichen Hilfe weiterkomme.
Gruss,
Gerhard
Gerhard H. schrieb:> Wenn ich am Kopf die Deklaration von 'segmenttable' weglasse, komme ich> zu einer Fehlermeldung, aber ich werde schauen, dass ich mit eurer> freundlichen Hilfe weiterkomme.
Du hast einen Schreibfehler- schau mal:
Andras H. schrieb:> segmenttabel ist nicht gleich> segmenttable
-table
-tabel
Du hast die Variable zweimal erzeugt, versehendlich, mit ähnlichem Namen
und verwendest die Falsche. Nenne deine Variable mal in Segemts um,
evtl. siehst du es dann ;)
Danke für die Hinweise.
Die falsche Schreibweise ist mir in der Tat nicht aufgefallen, Schande.
Passiert mir sonst so gut wie nie.
Leider hatte ich bisher trotzdem keinen Erfolg.
return(0); ergibt die Meldung:
'return' with a value, in function returning void
Ferner erhalte ich folgende Warn- und Fehlermeldungen:
near initialization for 'segmenttable'
excess elements in scalar initializer
subscripted value is neither array nor pointer nor vector
variable 'segmenttable' set but not used
Für mich eine harte Nuss
Gerhard H. schrieb:> Danke für die Hinweise.> Die falsche Schreibweise ist mir in der Tat nicht aufgefallen, Schande.> Passiert mir sonst so gut wie nie.> Leider hatte ich bisher trotzdem keinen Erfolg.>> return(0); ergibt die Meldung:> 'return' with a value, in function returning void
Leider hast Du die obigen Hinweise nicht beachtet.
>> Ferner erhalte ich folgende Warn- und Fehlermeldungen:>> near initialization for 'segmenttable'> excess elements in scalar initializer> subscripted value is neither array nor pointer nor vector> variable 'segmenttable' set but not used
Zeige den veränderten Quelltext.
Weitere Hinweise:
Du definierst eine Tabelle mit 11 Elementen für die Segmente, obwohl du
nur 10 Ziffern hast.
Deine Segmentanordnung darin ist mir nicht wirklich transparent.
Jedesmal erst über PORTB den neuen Digit-Treiber zu aktivieren, während
der alte Segmentstatus noch aktiv ist, bringt "Ghosting". Besser am Ende
der Zeitscheibe für eine Stelle erstmal alle Stellen ausschalten (das
wäre bei dir PORTB=0xff;), dann die neue Segmentbelegung aktivieren,
dann erst den Digit-Treiber dafür einschalten.
Schau dir mal an was ein Rückgabeparameter einer Funktion ist und wie
das funktioniert.
void Funktion (void)
^
|
wofür das void links steht...
PORTB = T3; //hiermit überschreibst du alle 8 Bits des Ports, obwohl du
nur eines ändern möchtest
PORTB = PORTB & 0xF7;
wäre deine Wahl, das kann man auch kürzer schreiben:
PORTB &= 0xF7;
ist das selbe, nur die kurzschreibweise in C. Dann aber bedenken dass du
den vorher auf 0 gesetzten Pin wieder auf 1 setzen musst...
PORTB |= 0x08; //
So könntest du das machen:
#define T1_aktivieren PORTB&=0xFE
#define T1_deaktivieren PORTB|=0x01
#define T2_aktivieren PORTB&=0xFD
#define T2_deaktivieren PORTB|=0x02
#define T3_aktivieren PORTB&=0xFB
#define T3_deaktivieren PORTB|=0x04
Im code dann:
PORTD = segmenttable[einer];
T1_aktivieren;
delay_ms(7);
T1_deaktivieren;
Vielen Dank einstweilen!! Ich check das nochmals genau durch.
(return (0); war am falschen Platz, grober Fehler)
Ich erlaube mir, mich später mal wieder zu melden, um über Erfolg oder
Misserfolg Bescheid zu geben.
Gruss
Gerhard
Gerhard H. schrieb:> war am falschen Platz, grober Fehler
Kein Thema, das kann schnell passieren. Jedoch musst du, wenn du in
einer Funktion (in diesem Fall main) etwas zurückgeben willst (return 0)
auch den Rückgabetyp entsprechend anpassen, in dem Fall den Rückgabetyp
von Main, wurde oben schon erwähnt.
Das anhand des Main() zu erklären ist echt ein blödes Beispiel für den
Einstieg in die Gestaltung von Funktionen in C.
Beispiel:
uint8_ t Addiere (uint8_t a, uint8_t b)
{
uint8_t ergebnis=0;
ergebnis=a+b;
return ergebnis;
}
du kannst dann zb im main code schreiben:
void main (void)
{
uint8_t variable=0;
...
variable=Addiere(7,8);
...
}
Die Funktion Addiere() gibt einen Wert zurück...
Main wird auch als Funktion "gesehen" und gibt u.u etwas ans System
zurück... Das ist aber für deine uc Anwendung völlig
irrelevant...deswegen ein schlechtes Beispiel...
Martin S. schrieb:> #define T1_aktivieren PORTB&=0xFE> #define T1_deaktivieren PORTB|=0x01
Oder noch besser:
1
#define T1_aktivieren() PORTB &= ~(1 << 0)
2
#define T1_deaktivieren() PORTB |= (1 << 0)
3
4
…
5
// Aufruf mit Klammern
6
T1_aktivieren();
7
_delay_ms(7);
8
T1_deaktivieren();
Makros, die direkt irgendein Ereignis bewirken (hier: eine Ausgabe auf
Port B) schreibt man besser in der funktions-ähnlichen Schreibweise,
also mit Klammern. Dann steht da auch im Code selbst das Klammernpaar,
und man weiß beim Draufgucken sofort: "Da passiert direkt was."
An die Mimik mit "&= ~(1 << bitnummer)" und "|= (1 << bitnummer)" zum
Löschen und Setzen von Bits sollte man sich gewöhnen, das ist völliger
Standard in diesem Umfeld.
Jörg W. schrieb:> Oder noch besser:
Ich wollte es nicht gleich überladen, in meinem Beispiel findet der TO
ggf. seine alten Werte noch mal wieder...
:-)
Gerhard H. schrieb:> Für mich eine harte Nuss
Falls du eine bereits fertige Lösung benötigst, melde dich nochmal. Ich
möchte dir jedoch nicht den Ehrgeiz und das Erfolgserlebnis für eine
eigene Lösung wegnehmen, sonst hätte ich es direkt angehängt.😀
Ich habe für ein dreistelliges LED-Display ein kleines Progrämmchen
einem MEGA8 in Verwendung - genau deine Anforderung. Müsste sogar auf
dem MEGA48 direkt laufen (ungeprüft), es wird nichts besonderes
verwendet.
Eigenschaften:
- mit Jumper ist eine invertierte Darstellung wählbar (STK500)
- mit Jumper für die Auswahl der Darstellung in DEZ oder HEX bzw. BCD
- Unterdrückung führender Nullen bei DEZ
- für Common-Anode Display, Spaltentreiber mit PNP-Transistoren
- Segmente werden direkt über den PortC angesteuert
- 8 Bit Input auf PortB
- Spaltenansteuerung und Lesen der Jumper über PortD
(Portbelegung ist etwas anders als bei dir.)
Ich verwende es u.a. für die leichtere Interpretierbarkeit anstelle der
acht LEDs am STK500 und bei anderen Debugaufgaben.
Moin,
im Arduino IDE 1.8.19 für einen 328er passiert das Gleiche. Siehe
Anhang. mit einem "int main(void)" kompiliert es dann vollkommen
fehlerfrei.
Gerhard
Rückgabewert
In deinem Programm hat die Funktion zerlege_wert() eigentlich auch drei
Rückgabewerte (einer, zehner und hunderter)
In C kann eine Funktion aber nur einen Rückgabewert haben. In deiner
Lösung "schummelst" du mit den drei globalen Variablen, das sollte man
wenn möglich immer vermeiden.
Es gibt viele Möglichkeiten, eine wäre die Funktion in drei Funktionen
zu zerlegen:
uint8_t gibEiner (uint8_t);
uint8_t gibZehner (uint8_t);
uint8_t gibHunderter (uint8_t);
In deinem Main könntest du sie dann so nutzen:
void main (void)
{
uint8_t einer=0;
...
einer = gibEiner(display_value);
...
PORTD = segmenttable[einer];
...
}
oder sogar direkt ohne den Umweg über die Variable "einer":
void main (void)
{
...
PORTD = segmenttable[gibEiner(display_value)];
...
}
Das geht beides in C, du kannst das theoretisch alles in eine Zeile
schreiben, jedoch ist es irgendwann nicht mehr lesbar :-)
HildeK schrieb:> Ich habe für ein dreistelliges LED-Display ein kleines Progrämmchen> einem MEGA8 in Verwendung> ...> Eigenschaften:> - mit Jumper
Wenn Du dir das Patentieren lässt... ;D
Gerhard O. schrieb:> mit einem "int main(void)" kompiliert es dann vollkommen> fehlerfrei.
Für dich wäre es zuerst wichtig zu verstehen was der Rückgabewert einer
Funktion überhaupt ist.
In deinem Programm fehlt nun der Rückgabewert, also das return()
Schau dir mal mein Beispiel dazu an:
Beitrag "Re: 7-Segment-Ansteuerung"
Martin S. schrieb:> In deinem Main könntest du sie dann so nutzen:> void main (void)
Vielleicht solltest Du hier mal auch wirklich ein
1
intmain(void)
hinschreiben. Weil nur dies (und andere Signaturen) standardisiert sind.
Zwar ist eine Implementierung frei weitere Startpunkte eines Programm
festzulegen, der gcc macht das aber erstmal nicht und deswegen gibt es
die Warnung.
Martin S. schrieb:> Gerhard O. schrieb:>> mit einem "int main(void)" kompiliert es dann vollkommen>> fehlerfrei.>> Für dich wäre es zuerst wichtig zu verstehen was der Rückgabewert einer> Funktion überhaupt ist.
Bei uC main() und gcc wäre Deine Erklärung tatsächlich hilfreich für
mich, warum gcc auf eine Rückgabe Erklärung besteht.
main.cpp:30:16: error: '::main' must return 'int'
void main (void)
Das Ende von main() wird in der Regel bei uC nie erreicht. Andere uC
Compiler die ich verwende, haben damit auch kein Problem (PIC, STM32).
Wenn gcc darauf besteht, dann mache ich es eben, damit das Meckern
aufhört. Ich sehe da keinerlei Gefahren. Aber die Leute vom gcc werden
schon ihre guten Gründe haben...
>> In deinem Programm fehlt nun der Rückgabewert, also das return()>> Schau dir mal mein Beispiel dazu an:>> Beitrag "Re: 7-Segment-Ansteuerung"
Der gcc 5.4.0 braucht übrigens nur 498 bytes
Der gcc 7.3.0 braucht 586 bytes für das selbe Programm
Gerhard H. schrieb:> Mit dem Eigenbau-Board murkse ich übrigens herum.
Meins sieht so aus 😀
Teo D. schrieb:> Wenn Du dir das Patentieren lässt... ;D
Lass ich ... 😉
Gerhard O. schrieb:> Der gcc 5.4.0 braucht übrigens nur 498 bytes> Der gcc 7.3.0 braucht 586 bytes für das selbe Programm
Mit gcc-12 (oder 13) und etwas Kosmetik in C++ (was Du ja oben verwendet
hast: Arduino) sind es dann nur noch 232 Bytes.
Wilhelm M. schrieb:> Gerhard O. schrieb:>> Der gcc 5.4.0 braucht übrigens nur 498 bytes>> Der gcc 7.3.0 braucht 586 bytes für das selbe Programm>> Mit gcc-12 (oder 13) und etwas Kosmetik in C++ (was Du ja oben verwendet> hast: Arduino) sind es dann nur noch 232 Bytes.
Danke. Komisch, meine installierte IDE V1.8.19 benutzt noch avr-gcc
V7.3.0
Ist mir gar nicht aufgefallen, dass die ziemlich alt ist.
Auf welche genaue avr-gcc V12/13 bezogst Du Dich?
Gerhard O. schrieb:>> Mit gcc-12 (oder 13) und etwas Kosmetik in C++ (was Du ja oben verwendet>> hast: Arduino) sind es dann nur noch 232 Bytes.
Mit etwas "Spielen" sind es jetzt mit V7.3.0 nur noch 302 Bytes
Wilhelm M. schrieb:>> Siehe Anhang. Bissel aufgeräumt.>> Was soll denn daran aufgeräumt sein?
Der Quelltext und die Stuktur.
> text data bss dec hex filename> 422 12 5 439 1b7 test7seg.elf> 204 0 0 204 cc bm65.elf>> Ergibt auch 422 Bytes,> bei mir (in C++ wie oben von Gerhard O. eingeführt) sind es 204 Bytes.
Ja und? War das das Ziel der Übung? Spielt das für den Lerneffekt eine
Rolle?
Falk B. schrieb:> Wilhelm M. schrieb:>>> Siehe Anhang. Bissel aufgeräumt.>>>> Was soll denn daran aufgeräumt sein?>> Der Quelltext und die Stuktur.
Warum globale Variablen?
Warum Konversionen signed/unsigend?
>>> text data bss dec hex filename>> 422 12 5 439 1b7 test7seg.elf>> 204 0 0 204 cc bm65.elf>>>> Ergibt auch 422 Bytes,>> bei mir (in C++ wie oben von Gerhard O. eingeführt) sind es 204 Bytes.>> Ja und? War das das Ziel der Übung?
Programme, die der Compiler schlecht optimieren kann, sind meistens auch
schlecht geschrieben.
Wilhelm M. schrieb:>> Der Quelltext und die Stuktur.>> Warum globale Variablen?
Warum nicht? Denkst du, deine Version spart RAM, nur weil der Compiler
keinen statischen RAM-Bedarf anzeigt?
> Warum Konversionen signed/unsigend?
Hab ich übersehen, ist nebensächlich.
Wilhelm M. schrieb:>> Ja und? War das das Ziel der Übung?>> Programme, die der Compiler schlecht optimieren kann, sind meistens auch> schlecht geschrieben.
Du bist ein Pedant. Mein herzliches Beileid.
Teo D. schrieb:> Delays über Delays im Code und keiner verliert ein Wort darüber!
Ich glaube, bei einer LED-Siebensegment-Anzeige brauchst du nicht drüber
zu diskutieren, ob der Controller jetzt noch 5 mA sparen kann, indem er
während der Wartezeit schläft. ;-)
Teo D. schrieb:> Hmmm... was'n hier los?> Delays über Delays im Code und keiner verliert ein Wort darüber!
Warum auch? Das ist ein EINFACHES Lernprogramm eines C-Anfängers im
reifen Alter von 74. Er hat noch Zeit, sich mit Interrupts und Timern zu
befassen.
Teo D. schrieb:> Hmmm... was'n hier los?> Delays über Delays im Code und keiner verliert ein Wort darüber!> Das ist doch sonst, der Trigger schlecht hin!?-O
Moin,
Ich finde es in diesen Fall folgerichtig, weil es von Gerhard nur ein
einfachstes Testprogramm sein soll, um die HW zu testen. Finde ich
absolut nichts falsch daran.
In einer realen Anwendung mache ich es sonst immer als Timer-ISR im
Hintergrund ohne irgendwelche Delays. Da braucht main() dann nur eine
leere „Erhaltungsschleife“ enthalten und man kann im restlichen Code
machen was man will, ohne den Display Scan zu stören.
Abgesehen davon sind viele von uns im Forum, einschließlich yours truly,
nur "Hobby Programmierer". Nur industriell/professionelle Maßstäbe
anlegen zu wollen, ist unangebracht. Viele Wege führen nach Rom; mehr
oder weniger holprig.
Noch etwas, auch wenn es bei gcc üblich ist hartnäckig auf einen
Rückgabewert der main() zu bestehen, gibt es viele embedded Werkzeuge,
denen das gleich ist und beides akzeptieren. Gcc ist nicht das Maß aller
Dinge. Etwas Recherche ergab, dass man es zwar machen soll, einfach,
weil es technisch gesehen, korrekter sein soll. Ich bin kein
professioneller Programmierer, der die ganzen gcc Unterlagen studiert
hat. Wenn es für mich so, wie erwartet, in traditioneller Weise
funktioniert, reicht es mir aus. Ich habe jahrelang mit nicht-gcc
Werkzeugen gearbeitet, wo noch andere Maßstäbe geherrscht haben und bin
diese Ära gewöhnt. Auch gcc wurde vielfach revidiert. Mit jeder neuen
Generation gibt es subtile Veränderungen, die oft alten Code brechen.
Was ich damit sagen will ist, dass man nicht immer vom hohen Pferd
herunter „schimpfen“ soll. Mir ist für alte Projekte auch langfristig
Rückwerts-Kompatibilität wichtiger, als den neuesten
Mode-Sprachenststandard zu folgen. Vieles, was vor 30 Jahren in C
durchging, wird heute nicht mehr gern gesehen bzw. erlaubt. Es gibt noch
viele Anwendungen, wo man in freiem Stil Probleme lösen kann und
funktionierende Anwendungen auf den Tisch stellen kann.
OK, jetzt dürft ihr meine gebührenden Minuspunkte auf mich
ausschütten:-)
Gerhard
Gerhard O. schrieb:> Teo D. schrieb:>> Hmmm... was'n hier los?>> Delays über Delays im Code und keiner verliert ein Wort darüber!>> Das ist doch sonst, der Trigger schlecht hin!?-O>> Moin,>> Ich finde es in diesen Fall folgerichtig, weil es von Gerhard nur ein> einfachstes Testprogramm sein soll, um die HW zu testen. Finde ich> absolut nichts falsch daran.
Eben, was hat hier, dieser RAM geifernder Optimierungs-Hickack, zu
suchen?!
Gerhard O. schrieb:> OK, jetzt dürft ihr meine gebührenden Minuspunkte auf mich> ausschütten:-)
Nein, überhaupt nicht. Ich stimme dir in (fast) allem zu!
Ob ein 'delay' böse ist oder nicht, kommt ganz auf den Anwendungsfall
an. Entweder es stört oder eben nicht. Soweit kenne ich meine Programme
schon, dass ich das entscheiden kann. Das Ergebnis zählt!
Zum anderen Punk: Der Compiler besteht nicht auf 'int main ()', er warnt
nur.
Das kann man bereinigen, aber auch einfach die Warnung lesen und
abnicken. Es passiert nichts...
HildeK schrieb:> Das kann man bereinigen, aber auch einfach die Warnung lesen und> abnicken. Es passiert nichts...
Man kann aber auch einfach den Scheiß so hinschreiben daß der Compiler
Ruhe gibt! Einen Compilerdurchlauf ohne Warnungen sollte man anstreben,
erst recht, wenn es SOOO einfach machbar ist!
HildeK schrieb:> Gerhard O. schrieb:>> OK, jetzt dürft ihr meine gebührenden Minuspunkte auf mich>> ausschütten:-)>> Nein, überhaupt nicht. Ich stimme dir in (fast) allem zu!> Ob ein 'delay' böse ist oder nicht, kommt ganz auf den Anwendungsfall> an. Entweder es stört oder eben nicht. Soweit kenne ich meine Programme> schon, dass ich das entscheiden kann. Das Ergebnis zählt!>> Zum anderen Punk: Der Compiler besteht nicht auf 'int main ()', er warnt> nur.> Das kann man bereinigen, aber auch einfach die Warnung lesen und> abnicken. Es passiert nichts...
Moin,
Im Arduino IDE weigert er sich und beendet den Build process. Ob man das
mit Einstellungen vermeiden könnte, ist ohne Recherche nicht zu
beantworten. Andrerseits ist es ja in Ordnung, die main(), so wie der
Compiler es wünscht, zu formulieren.
Mir war das nur ungewohnt, weil andere, ältere Compiler für PIC, CORTEX,
IAR, Keil, T.I. mit denen ich vertraut bin, nicht darauf bestanden haben
und es mir im embedded Bereich in über 25 Jahren auch niemals begegnete.
Abgesehen davon wurde das in ihren Beispielen in den Handbüchern auch
mit void deklariert. Ist eben eine gcc Sache. Ich war aber ein bisschen
verärgert, weil man mich hier deswegen etwas angemacht hatte. Gcc ist
für mich noch neu. Da ich gcc nur im Arduino Bereich verwende, sehe ich
auch seine main() Funktion fast nie.
Ich habe natürlich die Angelegenheit danach etwas recherchiert und der
Konzensus der Experten ist, main() immer als int zu deklarieren, weil es
angeblich so professioneller ist, auch wenn es oberflächlich gesehen,
sinnfrei scheint. Die meisten Compiler entscheiden ohnehin selber was
unter der Haube gemacht werden muß.
Intuitiv ist es etwas wunderlich in embeddete Anwendungen die main()
Funktion mit einem int zu deklarieren. Aber es ist für mich in Ordnung
wenn das Werkzeug darauf besteht - eben halt wieder etwas dazu gelernt.
Es besteht kein Grund für eine Bockigkeit:-)
Aber wie hätte ich es auch wissen können? Das passierte mir erstmalig
gestern. Und ich verdiene mir mit Programmieren nicht meine Brötchen und
ich mache das nur als Hobby. Im embedded Bereich macht es auch noch viel
Freude mit uC etwas auf die Beine zu stellen. Ich bin da etwas mehr HW
orientiert.
Gruß,
Gerhard
Einige Hersteller Beispiele mit "void main()"
Microchip C:
http://www.ccsinfo.com/content.php?page=compexamples#seconds
Keil 8051:
https://www.tutorialspoint.com/programming-8051-using-keil-softwarehttps://people.eecs.berkeley.edu/~boser/courses/40/labs/docs/IAR%20tutorial.pdf
Codevision C
https://inst.eecs.berkeley.edu/~ee128/fa04/labs/CodeVisionCompiler.pdf
Codecomposer Studio msp430:
https://github.com/ticepd/msp430-examples/blob/master/10-timerBlink/main.c
Gerhard O. schrieb:> Ist eben eine gcc Sache.
Nö, ist eine Sache des C-Standards.
Zwar gestattet der C-Standard auch, dass andere
implementierungsabhängige Formen von main() akzeptiert sein können
(deshalb kann dir Microchip eben die Sache mit "void" nahelegen). Auch
der GCC besteht nur mit dem (voreingestellten) -fhosted darauf, denn er
existiert für so viele verschiedene Plattformen, dass er schlicht keine
Ahnung hat, dass deine Umgebung tatsächlich in einer Endllosschleife
enden wird. Nimmt man -ffreestanding, dann ist ihm der Prototyp von
main() egal, allerdings nimmt er dann wirklich gar keine Optimierungen
mehr vor, die er für ein "hosted environment" vornehmen darf. Dann wird
eben auch für
1
i=strlen("foo");
wirklich die Funktion strlen() aufgerufen, statt da gleich eine 3
einzusetzen.
Insofern sind heutige Embedded-Umgebungen eben gar nicht so sehr
"freestanding", wie man das auf den ersten Blick erwarten würde. Die
mitgelieferten Bibliotheken und restliche Teile der Umgebung orientieren
sich, soweit irgend möglich, am C-Standard und verhalten sich dann auch
genau so, sodass der Unterschied zu einem hosted environment minimiert
wird.
Gerhard H. vs. Gerhard O.
Gerhard O. hat andere Themen die er hier diskutiert und damit alle
verwirrt vielleicht sogar inkl. Gerhard H. der ja noch alles durch
akkert.
Gerhard O. könnte ja auch einen Thread auf machen und dort seine Bytes
zu zählen, auch um den blutigen Anfänger hier nicht noch mehr zu
verwirren, aber vielleicht ist ihm das zu Bytelastig :-)
Wie dem auch sei, schön verwirrend hier...
JJ
Jörg W. schrieb:> Ich glaube, bei einer LED-Siebensegment-Anzeige brauchst du nicht drüber> zu diskutieren, ob der Controller jetzt noch 5 mA sparen kann, indem er> während der Wartezeit schläft. ;-)
Das ist nicht der Punkt.
Niemand will eine Konstante anzeigen, sondern einen Wert, z.B. von einem
DS18B20 Temperatursensor. Und dann geht mit dem Delay das große Flackern
los. Delay ist also immer eine Sackgasse.
Statt erstmal Babysprache zu lernen, es gleich richtig zu machen
(Timerinterrupt) spart jede Menge Zeit.
Peter D. schrieb:> Statt erstmal Babysprache zu lernen, es gleich richtig zu machen> (Timerinterrupt) spart jede Menge Zeit.
Solange er sich noch damit rumschlägt, die Grundlagen der Sprache zu
erlernen, brauchst du noch nicht mit Interrupts daher kommen.
War das mit dem "Ghosting" eigentlich geklärt?
Ich finde so die logischen Abläufe zu klären in jenem Falle wichtiger,
als sich über delays etc. aufzuregen.
Axel R. schrieb:> War das mit dem "Ghosting" eigentlich geklärt?
Für Gerhard H. wäre es erst mal wichtig zu wissen wie man einen Pin von
dem Controller richtig bedient, bevor man über "Ghosting" spricht...
JJ
(LED-Matrix 16x10)ich hatte einen 1 aus 10 Decoder für die Zeilen und
hab dann immer die aktuelle zeile leuchten lassen und dann die "Zeile11"
adressiert, die es nicht gab, die neuen Zeileninformationen (2x8bit)
geladen und DANACH erst die anzuzeigende Zeile adressiert. Hier sind es
eben die Dezimalstellen.
Jörg W. schrieb:> Peter D. schrieb:>> Statt erstmal Babysprache zu lernen, es gleich richtig zu machen>> (Timerinterrupt) spart jede Menge Zeit.>> Solange er sich noch damit rumschlägt, die Grundlagen der Sprache zu> erlernen, brauchst du noch nicht mit Interrupts daher kommen.
Das mit dem Delay ist doch gut für den Anfang. Danach kann er vllt einen
Zustandsautomat bauen für die Anzeigephasen des Displays. Dann braucht
er nur noch einmal Delay, und dann ... kann er einen Timer nehmen.
Jörg W. schrieb:> Zumal es ja nur> int main(void)> {> ...> }>> braucht, nicht einmal ein return muss sein.
Ich widerspreche der Aussage ja nicht, dass man es so machen soll. Alle
meine Programme haben 'int main(void)'!
Wichtig ist aber auch, dass man weiß, was für eine Auswirkung eine
solche Warnung hat. Das wusste Gerhard H. wohl noch nicht.
Anderes Beispiel:
während der Programmentwicklungsphase kann es durchaus vorkommen, dass
man eine Variable definiert hat aber (zunächst) noch nicht verwendet.
Gefahrlos, denn wenn der Grund ein Tippfehler war, dann taucht ein Error
auf bei der versuchten Verwendung der falsch geschriebenen Variable.
Andererseits ist ein Lesen einer definierten Variablen ohne vorherige
Wertzuweisung auch 'nur' eine Warnung, das aber meist funktionale
Auswirkungen haben wird.
HildeK schrieb:> Jörg W. schrieb:>> Zumal es ja nur>> int main(void)>> {>> ...>> }>>>> braucht, nicht einmal ein return muss sein.>> Ich widerspreche der Aussage ja nicht, dass man es so machen soll. Alle> meine Programme haben 'int main(void)'!>> Wichtig ist aber auch, dass man weiß, was für eine Auswirkung eine> solche Warnung hat. Das wusste Gerhard H. wohl noch nicht.
Als Programmiranfänger in C oder C++ sollte man keine Warnung zulassen,
am besten mit -Werror arbeiten. Denn der Anfänger kann meistens nicht
entscheiden, ob das wichtig ist, zu IB oder UB führt.
>> Anderes Beispiel:> während der Programmentwicklungsphase kann es durchaus vorkommen, dass> man eine Variable definiert hat aber (zunächst) noch nicht verwendet.> Gefahrlos, denn wenn der Grund ein Tippfehler war, dann taucht ein Error> auf bei der versuchten Verwendung der falsch geschriebenen Variable.> Andererseits ist ein Lesen einer definierten Variablen ohne vorherige> Wertzuweisung auch 'nur' eine Warnung, das aber meist funktionale> Auswirkungen haben wird.
Nicht nur das: es ist UB!
Daher hatte ich ja auch schon gesagt, das Objekte primitiver DT immer
expilizit initialisiert werden müssen.
Wilhelm M. schrieb:> Das mit dem Delay ist doch gut für den Anfang.
Ich hab früher viel mit TTL-ICs gebastelt. Da der 7-Segment Decoder P147
in der DDR schweineteuer war, hab ich die Anzeigen gemultiplext.
Dann später auf dem 8051 habe ich dafür automatisch den Timerinterrupt
benutzt.
Auf die Idee mit dem Delay bin ich gar nicht erst gekommen. Es schien
mir von Anfang an viel zu riskant, das nebenwirkungslos mit den Aufgaben
in der Mainloop verwursten zu können. Auch hatte ich Angst, daß bei
Fehlern in der Mainloop die Anzeigen durchbrennen könnten.
Peter D. schrieb:> Auch hatte ich Angst, daß bei> Fehlern in der Mainloop die Anzeigen durchbrennen könnten.
das geht zB. bei ner VQC10 sehr schnell, dass die da ne komplette Zeile
wegbrennt, wenn in der Software was schief läuft, beim entwickeln oder
beim "Messen".
Aber: nimmt ja eh niemand mehr
Peter D. schrieb:> Auch hatte ich Angst, daß bei> Fehlern in der Mainloop die Anzeigen durchbrennen könnten.
Bei der Entwicklung und Test wird eben wegen diesen Möglichkeiten mit
wesentlich geringer Leuchtkraft gearbeitet.
MfG
alterknacker
> Nö, ist eine Sache des C-Standards.
Hallo Joerg,
Danke für ausführliche Hintergrundinfo dazu.
Für mich ist dieses Thema nun ohnehin abgehakt, weil ich jetzt weiß,
warum der Arduino Build Script so eingestellt ist und richte mich eben
danach, wenn ich mit gcc in der Weise arbeite.
Was übrigens die VQC10 Ansteuerung betrifft, habe ich das Problem der
Überlastung damals in HW gelöst:
Beitrag "Re: Zeigt her eure Kunstwerke (2020)"
Gruß,
Gerhard
Ich hätte ja noch was in dem C-Buch Thread geschrieben, der aber auf
wundersame Weise mal wieder für Gäste gesperrt ist.
Es ist hilfreich, ein gutes Nachschlagewerk zum Thema Digitaltechnik
parat zu haben.
Digitaltechnik von Beuth ist ziemlich gut, aber es gibt auch noch
andere.
Axel R. schrieb:> Peter D. schrieb:>> Auch hatte ich Angst, daß bei>> Fehlern in der Mainloop die Anzeigen durchbrennen könnten.>> das geht zB. bei ner VQC10 sehr schnell, dass die da ne komplette Zeile> wegbrennt, wenn in der Software was schief läuft, beim entwickeln oder> beim "Messen".> Aber: nimmt ja eh niemand mehr
Ich schon:-)
rbx schrieb:> Ich hätte ja noch was in dem C-Buch Thread geschrieben, der aber> auf> wundersame Weise mal wieder für Gäste gesperrt ist.>> Es ist hilfreich, ein gutes Nachschlagewerk zum Thema Digitaltechnik> parat zu haben.> Digitaltechnik von Beuth ist ziemlich gut, aber es gibt auch noch> andere.
Welcher Thread ist das, rbx?
Gruß,
Gerhard
Gerhard O. schrieb:> Teo D. schrieb:>> Gerhard O. schrieb:>>> Welcher Thread ist das>>>> Beitrag "Empfehlenswerte Literatur zum Erlernen von C">> Dankeschön!>> Gruß,> Gerhard
In diesen Thread scheint ein (grantiger und kleinlicher) Minusmann
herumzugeistern. Man darf sich nicht einmal mehr bedanken, ohne
angefahren zu werden.
Hallo,
Gerhard O. schrieb:> In diesen Thread scheint ein (grantiger und kleinlicher) Minusmann> herumzugeistern. Man darf sich nicht einmal mehr bedanken, ohne> angefahren zu werden.
Einfach ignorieren.
rhf