Forum: Mikrocontroller und Digitale Elektronik #define Ich bekomme ein Makro nicht hin.


von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

ich glaube ich bin zu doof - oder es geht einfach nicht - !!! (aber eher 
glaube ich, ich bin zu doof und sehe vor lauter Bäumen den Wald nicht).

Problem:

Ich habe mir eine eigene sehr minimalistische printf Funktion 
geschrieben damit ich den printf-Komfort auch mit einem ATtiny2313 
"geniese" (siehe Code).

Funktioniert alles tadellos wie ich mir das wünsche ... mit einer 
Ausnahme.
Da der Tiny nur extrem spärliche 128 Byte RAM hat, muß ein String für 
printf zwingend im Codespeicher abgelegt sein und dann (das ist das 
üble) mittels "pgm_read_byte" dort wieder hervor geholt werden.

Der für mich größte Schönheitsfehler besteht nun darin, dass ich meine 
printf Funktion nun folgendermaßen aufrufen muß:
1
tiny_printf(PSTR("Zahlensystem        %dd  = %xh\n\r"),84, 84);

Das gefällt mir so gar nicht.
Ich hätte gerne ein Makro, welches mir den Aufruf umdefiniert, damit ich 
bspw. folgendes schreiben kann:
1
my_printf("Zahlensystem        %dd  = %xh\n\r",84, 84);

Also irgendwas im Stile von:
1
#define my_printf( bla bla     tiny_printf(PSTR( bla bla

... eben ohne das lästige PSTR( ... und das schlimme: die schließende 
Klammer nach dem String.

Bin ich zu dämlich oder geht das wirklich nicht ?

von Dr. Sommer (Gast)


Lesenswert?

1
#define my_printf(str,...) (tiny_printf(PSTR(str) , ## __VA_ARGS__))

Der Trick mit dem ", ##" funktioniert nur im GCC, bewirkt aber dass der 
Aufruf auch mit 0 Argumenten funktioniert, siehe:

https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

von Ralph S. (jjflash)


Lesenswert?

... das werde ich jetzt sofort ausprobieren... vielen Dank für's erste

von Dr. Sommer (Gast)


Lesenswert?

PS:
1
void tiny_printf(const uint8_t *s,...)
2
{
3
  int       total, arg1;
4
  uint8_t   token, *arg2;
5
  char      ch;
6
  va_list   ap;
Die 90er sind vorbei, man darf Variablen heutzutage auch woanders als am 
Funktionsanfang deklarieren. Am sinnvollsten ist es, die Variable genau 
dort zu deklarieren, wo sie auch das erste Mal benutzt wird, z.B.:
1
uint8_t token= pgm_read_byte(++s);
2
switch(token) ...
So ist genau klar, in welchen Bereich die Variable überhaupt benutzt 
wird (nämlich innerhalb des if-Blocks). Man kann sie auch nicht 
versehentlich auslesen, während sie noch überhaupt keinen Wert hat.

Dein Algorithmus ist ineffizient, hier:
1
if(pgm_read_byte(s)=='%')
und hier:
1
uart_putchar(pgm_read_byte(s));
und hier:
1
ch= pgm_read_byte(s);
liest  du exakt das selbe Zeichen immer wieder ein indem du 
pgm_read_byte mit dem selben Parameter aufrufst. Nimm doch die Variable 
"ch", um das Zeichen zwischenzuspeichern... Außerdem musst du im letzten 
Stück das "s++" und das uart_putchar(...) tauschen!

von Ralph S. (jjflash)


Lesenswert?

Waaaaaaaahnsinn, das funktioniert !!!

Vielen vielen Dank

PS: ... ich wußte schon immer, dass ich zu dämlich bin ! :-)

von Ralph S. (jjflash)


Lesenswert?

Dr. Sommer schrieb:
> Dein Algorithmus ist ineffizient, hier:if(pgm_read_byte(s)=='%')

ich werde es überarbeiten (und natürlich hast du Recht), ich war erst 
einmal froh, dass das überhaupt lief.

Vor allem schau ich mir an, wo ich Codegröße einsparen kann. Aber 
nochmals vielen vielen Dank.

von Eric B. (beric)


Lesenswert?

Spasshalber mal ein putint() ohne mult und div:
1
void putint(int i)
2
{
3
    static int zz[] = { 10000, 1000, 100, 10 };
4
    bool_t not_first = FALSE;
5
    
6
    if (!i)
7
    {
8
        uart_putchar('0');
9
    } else {
10
        if(i < 0)
11
        {
12
            uart_putchar('-');
13
            i = -i;
14
        }
15
        
16
        int z, b;
17
        for(int zi = 0; zi < 4; zi++}
18
        {
19
            z = 0;
20
            b = 0;
21
            
22
            while(z + zz[zi] <= i)
23
            {
24
                b++;
25
                z += zz[zi];
26
            }
27
            
28
            if(b || not_first)
29
            {
30
                uart_putchar('0' + b);
31
                not_first = TRUE;
32
            }
33
            
34
            i -= z;
35
        }
36
        uart_putchar('0' + i);
37
    }
38
}

: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

... werde ich jetzt mal "einbauen", auch wenn ich sowieso an der putint 
dran war (Codegröße und "Kommafunktion" für Pseudokommazahlen)...

Ich muß lachen, ich hätte nicht geglaubt, dass der Thread hier wächst.

von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Eric B. schrieb:
> Spasshalber mal ein putint() ohne mult und div:

... das hat 114 Byte Ersparnis gebracht, Spasshalber der gesamte Code im 
Anhang

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.