Forum: Mikrocontroller und Digitale Elektronik 7-Segment-Ansteuerung


von Gerhard H. (Firma: Rentner) (spectro)


Lesenswert?

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 
3
  ATMega48
4
 */
5
6
7
#define F_CPU 8000000UL
8
9
#include <avr/io.h>
10
#include <util/delay.h>
11
12
uint16_t display_value;
13
uint8_t  einer, rest, zehner, hunderter;
14
const uint8_t segmenttable[11];
15
16
17
#define T1 0xFE  // Basis Transistor 1 (PNP) Einerstelle
18
#define T2 0xFD  // Basis Transistor 2  Zehnerstelle
19
#define T3 0xFB  // Basis Transistor 3 Hunderterstelle
20
21
void wert_zerlegen (int display_value)
22
{
23
  einer = display_value % 10;
24
  rest =  display_value / 10;
25
  zehner =  rest % 10;
26
  hunderter = rest / 10;
27
}
28
29
void main (void)
30
{
31
  
32
  DDRD  = 0xFF; // PORTD auf Ausgang setzen
33
  DDRB  = 0xFF;
34
  PORTD = 0xFF; //Ausgabeport für 7-Segment-Ziffern
35
  PORTB = 0xFF; // Ansteuerung von T1 bis T3
36
  
37
  const uint8_t segmenttabel[11] =
38
  
39
   {0x03, 0xF3, 0x25, 0x0D, 0x99, 0x49, 0x41, 0x1F, 0x01, 0x19, 0xFE } ; // Ziffern von 0 bis 9 und DP
40
  
41
  display_value = 219;  // Beispielzahl für die Ausgabe auf den 3 Anzeigen
42
  
43
  
44
  while(1)
45
  
46
  {
47
    
48
    wert_zerlegen (display_value);
49
    
50
    PORTB = T1;
51
    PORTD = segmenttable [einer];
52
    _delay_ms(7);
53
    
54
    PORTB = T2;
55
    PORTD = segmenttable [zehner];
56
    _delay_ms(7);
57
    
58
    PORTB = T3;
59
    PORTD = segmenttable [hunderter];
60
    _delay_ms(7);
61
    
62
  }
63
  
64
}

von Olaf (Gast)


Lesenswert?

> 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

von Wilhelm M. (wimalopaan)


Lesenswert?

Der Rückgabetyp von main() muss int sein.

Das lokale Array segmenttable verdeckt das globale, was damit unbenutzt 
ist.

von Andras H. (kyrk)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Andras H. schrieb:
> Zeile 37 geht nach oben wo Zeile 14 war. Dann ist es
> global und wird im ROM gespeichert.

Beim AVR-GCC nicht. Da braucht es einige Klimmzüge, Variablen im Flash 
zu halten und auch zum Lesen sind spezielle Funktionen nötig.

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

von Gerhard H. (Firma: Rentner) (spectro)


Lesenswert?

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

von Ingo Less (Gast)


Lesenswert?

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 ;)

von Gerhard H. (Firma: Rentner) (spectro)


Lesenswert?

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

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von OldMan (Gast)


Lesenswert?

Zeige bitte den aktuellen Code.

von Gerhard H. (Firma: Rentner) (spectro)


Lesenswert?

Sorry, ich hatte vorhin beim Schusseln einen Flüchtigkeitsfehler 
eingebaut.
so sieht es derzeit aus:
1
/*  7-SEGMENT-ANZEIGE  Multiplexbetrieb  mit drei 7-Segment-Anzeigen, CA,
2
    Ansteuerung an PORTB0, PORTB1 und PORTB2 mit PNP Transistoren 
3
  ATMega48
4
 */
5
6
7
#define F_CPU 8000000UL
8
9
#include <avr/io.h>
10
#include <util/delay.h>
11
12
uint16_t display_value;
13
uint8_t  einer, rest, zehner, hunderter;
14
15
16
17
18
#define T1 0xFE  // Basis Transistor 1 (PNP) Einerstelle
19
#define T2 0xFD  // Basis Transistor 2  Zehnerstelle
20
#define T3 0xFB  // Basis Transistor 3 Hunderterstelle
21
22
23
24
void wert_zerlegen (int display_value)
25
{
26
  einer = display_value % 10;
27
  rest =  display_value / 10;
28
  zehner =  rest % 10;
29
  hunderter = rest / 10;
30
}
31
32
void main (void)
33
{
34
  
35
  DDRD  = 0xFF; // PORTD auf Ausgang setzen
36
  DDRB  = 0xFF;
37
  PORTD = 0xFF; //Ausgabeport für 7-Segment-Ziffern
38
  PORTB = 0xFF; // Ansteuerung von T1 bis T3
39
  
40
 const uint8_t segmenttable[11] = 
41
 { 0x03, 0xF3, 0x25, 0x0D, 0x99, 0x49, 0x41, 0x1F, 0x01, 0x19, 0xFE } ;
42
  
43
  display_value = 345;
44
  
45
    
46
47
    while(1)
48
  
49
  {
50
    
51
    wert_zerlegen (display_value);
52
    
53
    PORTB = T1;
54
    PORTD = segmenttable[einer];
55
    _delay_ms(7);
56
    
57
    PORTB = T2;
58
    PORTD = segmenttable[zehner];
59
    _delay_ms(7);
60
    
61
    PORTB = T3;
62
    PORTD = segmenttable[hunderter];
63
    _delay_ms(7);
64
    return(0);
65
    
66
  }
67
  
68
}

von Wilhelm M. (wimalopaan)


Lesenswert?

Das mit int main(void) hast Du verstanden?

Soll Dein Programm eine Endlosschleife machen oder nicht?

von Martin S. (mmaddin)


Lesenswert?

Hallo Gerhard,

nimm mal das return (0) aus der while Schleife.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Martin S. (mmaddin)


Lesenswert?

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;

: Bearbeitet durch User
von Gerhard H. (Firma: Rentner) (spectro)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

"Failure is not an option." :-)

Das solltest du schon hinbekommen, ist keine Raketenwissenschaft.

von Martin S. (mmaddin)


Lesenswert?

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...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Martin S. (mmaddin)


Lesenswert?

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...

:-)

von HildeK (Gast)


Lesenswert?

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.

von Gerhard O. (gerhard_)


Angehängte Dateien:

Lesenswert?

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

von Martin S. (mmaddin)


Lesenswert?

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 :-)

von Teo D. (teoderix)


Lesenswert?

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

von Martin S. (mmaddin)


Lesenswert?

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"

von Gerhard H. (Firma: Rentner) (spectro)


Angehängte Dateien:

Lesenswert?

Vielen Dank. Ich muss noch alles durchackern.

Mit dem Eigenbau-Board murkse ich übrigens herum.

von Wilhelm M. (wimalopaan)


Lesenswert?

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
int main(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.

von Martin S. (mmaddin)


Lesenswert?

Gerhard H. schrieb:
> Vielen Dank. Ich muss noch alles durchackern.


Fang mal damit an:

Beitrag "Re: 7-Segment-Ansteuerung"

von Wilhelm M. (wimalopaan)


Lesenswert?

Martin S. schrieb:
> Gerhard H. schrieb:
>> Vielen Dank. Ich muss noch alles durchackern.
>
>
> Fang mal damit an:
>
> Beitrag "Re: 7-Segment-Ansteuerung"

Ich denke eher, er sollte erstmal ein C++-Buch (weil Arduino-Framework) 
zur Hand nehmen (auch als Autodidakt) ;-)

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Lesenswert?

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

von HildeK (Gast)


Angehängte Dateien:

Lesenswert?

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 ... 😉

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

: Bearbeitet durch User
von Gerhard O. (gerhard_)


Lesenswert?

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?

von Gerhard O. (gerhard_)


Lesenswert?

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

von Wilhelm M. (wimalopaan)


Lesenswert?

Gerhard O. schrieb:
> Auf welche genaue avr-gcc V12/13 bezogst Du Dich?

12.2 bzw. 13.0 (trunk)

Beitrag #7335726 wurde vom Autor gelöscht.
von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Siehe Anhang. Bissel aufgeräumt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
> Siehe Anhang. Bissel aufgeräumt.

Was soll denn daran aufgeräumt sein?
1
text    data     bss     dec     hex filename
2
422      12       5     439     1b7 test7seg.elf
3
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.

von Falk B. (falk)


Lesenswert?

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?

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
> Wilhelm M. schrieb:
>>> Der Quelltext und die Stuktur.
>>
>> Warum globale Variablen?
>
> Warum nicht?

Struktur???
Optimizer???

von Teo D. (teoderix)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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. ;-)

von Martin S. (mmaddin)


Lesenswert?

Teo D. schrieb:
> Hmmm... was'n hier los?

...schnall ich auch absolut nicht...???

M.

von Wilhelm M. (wimalopaan)


Lesenswert?

Martin S. schrieb:
> Teo D. schrieb:
>> Hmmm... was'n hier los?
>
> ...schnall ich auch absolut nicht...???

Das ist wohl das geringste Problem hier.

von Falk B. (falk)


Lesenswert?

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.

von Gerhard O. (gerhard_)


Lesenswert?

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

von Teo D. (teoderix)


Lesenswert?

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?!

von HildeK (Gast)


Lesenswert?

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...

von Falk B. (falk)


Lesenswert?

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!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Zumal es ja nur
1
int main(void)
2
{
3
...
4
}

braucht, nicht einmal ein return muss sein.

von Gerhard O. (gerhard_)


Lesenswert?

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-software
https://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

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Jens (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

: Bearbeitet durch User
Beitrag #7336828 wurde von einem Moderator gelöscht.
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Axel R. (axlr)


Lesenswert?

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.

von Jens (Gast)


Lesenswert?

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

von Axel R. (axlr)


Lesenswert?

(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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

Axel R. schrieb:
> War das mit dem "Ghosting" eigentlich geklärt?

In meiner Version schon.

Beitrag "Re: 7-Segment-Ansteuerung"

von HildeK (Gast)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Axel R. (axlr)


Lesenswert?

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

von Al. K. (alterknacker)


Lesenswert?

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

von Gerhard O. (gerhard_)


Lesenswert?

> 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

von Gerhard O. (gerhard_)


Lesenswert?

> Gerhard H. vs.  Gerhard O.

Hier geht es aber neuerdings streng zu:-)

von rbx (Gast)


Lesenswert?

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.

von Gerhard O. (gerhard_)


Lesenswert?

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:-)

von Gerhard O. (gerhard_)


Lesenswert?

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

von Martin S. (mmaddin)


Lesenswert?

Gerhard O. schrieb:
> Welcher Thread ist das, rbx?
>
> Gruß,
> Gerhard

https://www.mikrocontroller.net/topic/550298#new

von Teo D. (teoderix)


Lesenswert?


von Gerhard O. (gerhard_)


Lesenswert?

Teo D. schrieb:
> Gerhard O. schrieb:
>> Welcher Thread ist das
>
> Beitrag "Empfehlenswerte Literatur zum Erlernen von C"

Dankeschön!

Gruß,
Gerhard

von Gerhard O. (gerhard_)


Lesenswert?

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.

: Bearbeitet durch User
von Roland F. (rhf)


Lesenswert?

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

Beitrag #7337856 wurde von einem Moderator gelöscht.
Beitrag #7337900 wurde von einem Moderator gelöscht.
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.