Forum: Compiler & IDEs Struct; Was ist eleganter?


von Max (Gast)


Lesenswert?

Hallo ich brauche mal eurer Hilfe, weil ich den Eindruck habe das was 
ich da mache nicht so ganz elegant ist! ;-)

meine Struktur
1
typedef struct
2
{
3
  uint8_t color;
4
  uint8_t won;
5
}pProfil;

später im Code
1
void PlayTheGame()
2
{
3
//...
4
static pProfil spieler1 = {0,0};
5
static pProfil spieler2 = {0,0};
6
7
static pProfil *sp1 = &spieler1;
8
static pProfil *sp2 = &spieler2;
9
//...
10
}

Wie kann man das kürzer machen? Möglichst in zwei Zeilen... Das 
Einzigste was mir einfallen würde, wäre mit malloc zu arbeiten. Wobei 
man ja hier eigentlich eine dynamische Speicherverwaltung eigentlich 
nicht braucht?! Zu mal man ja dann trotzdem noch Zuweisung der Werte 
machen muss.
Ich muss alle vier als static deklarieren ne? Sprich das so richtig?!

Und so kommen wir zu meinem zweiten Knackpunkt. Später wenn das Spiel 
dann vorbei ist möchte ich die Werte von sp1 und sp2 zurücksetzten.

So habe ich es jetzt gemacht. Was wie ich finde auch nicht so prall 
ist...
1
void resetplayer(pProfil *sp1, pProfil *sp2)
2
{
3
 
4
 sp1->color = 0;
5
 sp1->won = 0;
6
 sp2->color = 0;
7
 sp2->won = 0;
8
}

Mit folgendem würde ich mich ja schon zu frieden geben. Allerdings 
reserviere ich ja wieder für die "profil" Speicherplatz?!
1
void resetplayer(pProfil *sp1, pProfil *sp2)
2
{
3
 pProfil profil = {0,0};
4
 *sp1 = profil;
5
 *sp2 = profil;
6
}

LG Max

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Deine Lösung ist im Grund doch OK.

Man kann die beiden static Structs noch aus der Funktion rausziehen und 
zu globalen Structs machen. Bei µC ist das angenehmer, weil der RAM 
Bedarf von Variablen DATA (=> globale Structs) und BSS zur Compilezeit 
ausgerechnet werden kann. Zur Laufzeit erlebt man dann selterner 
unliebsame Überraschungen mit überlaufendem Stack/Heap (lokale Variablen 
in Funktionen, malloc/free).

Um das Optimieren beim Initialisieren beim neuen Spiel würde ich mich 
nicht kümmern. Das ist eine einmalige Peanuts-Aktion. Die macht man 
irgendwie (z.b. wie dein 1. Beispiel, bei globalen Struchts ohne 
Funktionsargumente) und gut ist's. Da lohnen sich andere Optimierungen 
bestimmt mehr ;-)

von Rolf Magnus (Gast)


Lesenswert?

> Wie kann man das kürzer machen? Möglichst in zwei Zeilen...

Hmm...
1
static pProfil spieler1 = {0,0}, spieler2 = {0,0};
2
static pProfil *sp1 = &spieler1, *sp2 = &spieler2;

Ist halt nicht so lesbar. Was erhoffst du dir eigentlich durch eine 
Reduktion auf zwei Zeilen?

> Ich muss alle vier als static deklarieren ne? Sprich das so richtig?!

Das kommt darauf an, wozu du sie brauchst.

> So habe ich es jetzt gemacht. Was wie ich finde auch nicht so prall
> ist...

Wieso? Was gefällt dir daran nicht?

> Mit folgendem würde ich mich ja schon zu frieden geben. Allerdings
> reserviere ich ja wieder für die "profil" Speicherplatz?!

Temporär, möglicherweise, ja.

von Sven P. (Gast)


Lesenswert?

Mir erschließt sich ehrlich gesagt der Sinn der globalen Zeiger nicht so 
ganz.

von Max (Gast)


Lesenswert?

Ah dann bin ich ja beruhigt! Hätte ja sein können, dass man es kürzer 
machen kann... :-)

Jetzt habe ich allerdings ein Speed Problem. Und zwar will ich mit 
folgender Funktion Registieren, welche Taste gedrückt worden ist. 
Allerdings mit dieser Funktion geht das nicht wirklich gut. Muss 
meinstens mehr mals drücken, bis ein Druck registriert worden ist.

Die Funktion
1
int8_t getAnyKeyPush(void)
2
{
3
  int8_t ret;
4
  //Zeile 1
5
  if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_1))
6
  {
7
    ret = FELD1;
8
  }
9
  else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_2))
10
  {
11
    ret = FELD2;
12
  }
13
  else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_3))
14
  {
15
    ret = FELD3;
16
  }
17
  //Zeile 2
18
  else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_1))
19
  {
20
    ret = FELD4;
21
  }
22
  else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_2))
23
  {
24
    ret = FELD5;
25
  }
26
  else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_3))
27
  {
28
    ret = FELD6;
29
  }
30
  //Zeile 3
31
  else if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_1))
32
  {
33
    ret = FELD7;
34
  }
35
  else if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_2))
36
  {
37
    ret = FELD8;
38
  }
39
  else if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_3))
40
  {
41
    ret = FELD9;
42
  }
43
  // Wenn keine Taste gedrückt worden ist
44
  else
45
  {
46
    ret = -1;
47
  }
48
  
49
  return ret;
50
}

Die Defines
1
//Die Feldtasten
2
#define TASTEN_Z12_DDR  DDRB
3
#define TASTEN_Z12_PORT PORTB
4
#define TASTEN_Z12 PINB
5
//Zeile 1
6
#define TASTE_Z1_1 PB0
7
#define TASTE_Z1_2 PB1
8
#define TASTE_Z1_3 PB2
9
//Zeile 2
10
#define TASTE_Z2_1 PB3
11
#define TASTE_Z2_2 PB4
12
#define TASTE_Z2_3 PB5
13
//Zeile 3
14
#define TASTEN_Z3_DDR  DDRC
15
#define TASTEN_Z3_PORT PORTC
16
#define TASTEN_Z3 PINC
17
18
#define TASTE_Z3_1 PC0
19
#define TASTE_Z3_2 PC1
20
#define TASTE_Z3_3 PC2

Und noch die delay Funktion
1
uint8_t delay_buttonpush(volatile uint8_t *port, uint8_t pin)
2
{
3
  if ( ! (*port & (1 << pin)) )
4
    { 
5
        _delay_ms(50); 
6
        if ( *port & (1 << pin) )
7
        {
8
            _delay_ms(50); 
9
            return 1;
10
        }
11
    }
12
    return 0;
13
}

LG Max

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich würde unbedingt die Entprellung per Software mittels /debounce 
time/ Methode und dem 2*50ms Warten ersetzen. Z.b. durch die bewährten 
Routinen aus der Artikelsammlung mit dem Einlesen der Tasten im 
Timer-Interrupt.

Ich würde bei 8 Tasten alle auf einen Port legen und den komplett nur 
einmal einlesen. Das Rauspfriemeln der gedrückten Taste zum Auswerten 
dann mit Bitmasken. Damit spart man die vielen Aufrufe von 
delay_buttonpush() in getAnyKeyPush()

Du hast allerdings 9 Tasten - scheint eine 3x3 Tastaturmatrix zu sein. 
Da gibt es in der Artikelsammlung auch Routinen dafür. Alternativ die am 
wenigsten benutzte Taste auf einen extra Pin legen und 8+1 abfragen.

von Max (Gast)


Lesenswert?

So ich hab es jetzt wie folgt geändert. Ist jetzt so einigermaßen wie 
ich es haben will. Stören sich eigentlich ein Timer Interrupt und die 
_delay_ms()? Weil ich noch eine Multiplexer LED Schaltung hinzufügen 
will wie über Timer Interrupt laufen wird. Und ich will halt nicht das 
die sich gegenseitig erheblich in Quäre kommen...

1
uint8_t delay_buttonpush(volatile uint8_t *port, uint8_t pin)
2
{
3
  if ( ! (*port & (1 << pin)) )
4
    { 
5
        _delay_ms(50); 
6
    _delay_ms(50); 
7
        if ( *port & (1 << pin) )
8
        {
9
            _delay_ms(50); 
10
      _delay_ms(50); 
11
            return 1;
12
        }
13
    }
14
    return 0;
15
}
1
int8_t getAnyKeyPush(void)
2
{
3
  int8_t ret = -1;
4
  /*Zeile 1 u. Zeile 2 registrieren*/
5
  if((TASTEN_Z12&0x3F)<0x3F)
6
  {
7
    if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_1))
8
    {
9
      ret = FELD1;
10
    }
11
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_2))
12
    {
13
      ret = FELD2;
14
    }
15
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_3))
16
    {
17
      ret = FELD3;
18
    }
19
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_1))
20
    {
21
      ret = FELD4;
22
    }
23
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_2))
24
    {
25
      ret = FELD5;
26
    }
27
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_3))
28
    {
29
      ret = FELD6;
30
    }
31
  }
32
  else if((TASTEN_Z3&0x7)<0x7)
33
  {
34
    if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_1))
35
    {
36
      ret = FELD7;
37
    }
38
    else if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_2))
39
    {
40
      ret = FELD8;
41
    }
42
    else if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_3))
43
    {
44
      ret = FELD9;
45
    }
46
  }
47
  else
48
  {
49
    ret = -1;
50
  }
51
  
52
  return ret;
53
}

Warum geht die modifizierte getAnyKeyPush() gefühlstechnisch besser? 
Denn das Ausmaskieren macht doch die delay_buttonpush auch schon?! 
Sprich die geht doch erst gar nicht zum _delay_ms(), wenn keine Taste 
gedrückt ist?!

von Max (Gast)


Lesenswert?

So ich hab es jetzt doch noch was konsequenter gemacht! ;-)
1
int8_t getAnyKeyPush(void)
2
{
3
  int8_t ret = -1;
4
  if((TASTEN_Z12&0x7)<0x7) //Zeile 1
5
  {
6
    if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_1))
7
    {
8
      ret = FELD1;
9
    }
10
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_2))
11
    {
12
      ret = FELD2;
13
    }
14
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z1_3))
15
    {
16
      ret = FELD3;
17
    }
18
  }
19
  else if((TASTEN_Z12&0x38)<0x38) //Zeile 2
20
  {
21
    if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_1))
22
    {
23
      ret = FELD4;
24
    }
25
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_2))
26
    {
27
      ret = FELD5;
28
    }
29
    else if(delay_buttonpush(&TASTEN_Z12, TASTE_Z2_3))
30
    {
31
      ret = FELD6;
32
    }
33
  }
34
  else if((TASTEN_Z3&0x7)<0x7)
35
  {
36
    if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_1))
37
    {
38
      ret = FELD7;
39
    }
40
    else if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_2))
41
    {
42
      ret = FELD8;
43
    }
44
    else if(delay_buttonpush(&TASTEN_Z3, TASTE_Z3_3))
45
    {
46
      ret = FELD9;
47
    }
48
  }
49
  else
50
  {
51
    ret = -1;
52
  }
53
  
54
  return ret;
55
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Max wrote:

> Stören sich eigentlich ein Timer Interrupt und die
> _delay_ms()?

Sicher doch. Die _delay_ms() wird von den Timer-Interupts unterbrochen 
und braucht länger als von dir angegeben, d.h. sie wird unpräziser.

> Weil ich noch eine Multiplexer LED Schaltung hinzufügen
> will wie über Timer Interrupt laufen wird. Und ich will halt nicht das
> die sich gegenseitig erheblich in Quäre kommen...

Dann lass die das Softwaredebounce weg und polle die Tasten im sowieso 
vorhandenen Timer-Interrupt. Eleganter kannst du das nicht lösen.

> Warum geht die modifizierte getAnyKeyPush() gefühlstechnisch besser?
> Denn das Ausmaskieren macht doch die delay_buttonpush auch schon?!
> Sprich die geht doch erst gar nicht zum _delay_ms(), wenn keine Taste
> gedrückt ist?!

Durch die beiden neuen Zusatzabfragen gehst du nur in die zeitmäßig 
teure delay_buttonpush(), wenn eine Taste gedrückt ist. Vorher gingst du 
immer rein. Der Zeitverbrauch ist die Aufrufzeit der delay_buttonpush().

(Edit: Teil gelöscht. Analyse deiner Tastenabfrage ist mir im Moment zu 
zeitaufwändig)

50 ms ist schon rel. viel Entprellzeit. Zur Info: In BASCOM AVR sind 
beim Befehl DEBOUNCE 25 ms default (einstellbar mit CONFIG DEBOUNCE).

von Max (Gast)


Lesenswert?

Ach so also 2 mal 25ms statt 2 mal 50 ?

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.