Forum: Mikrocontroller und Digitale Elektronik String umwandlung und auffüllen


von René K. (tesla24)


Lesenswert?

Hallo liebe Gemeinde:

Ich habe mehrere int Variablen, diese wandel ich jeweils mit itoa() in 
strings um. Dann möchte ich die einzelnen strings in einen großen String 
verketten und diesen großen sende ich dann mit UART raus.

Manche Variablen können mal einen Wert von 5 bis 255 haben, nun muss 
aber der String immer die gleiche Länge haben um ihn am Empfänger 
auswärten zu können!

Bsp.:
1
int a=5;
2
char a_str[];
3
4
itoa(a,a_str,10);

Ergebnis: '5'
Ich hätte gerne: '005'

Vielen Dank im voraus !

von J. F. (Firma: Père Lachaise) (rect)


Lesenswert?

Sowas?

    int a = 3;
    char buffer[4];
    snprintf(buffer, 4, "%03d", a);

von Nop (Gast)


Lesenswert?

zum Beispiel so, ohne printf:
1
void to_string(char *str, uint8_t val)
2
{
3
  str[0] = val / 100;
4
  val %= 100;
5
  str[1] = val / 10;
6
  val %= 10;
7
  str[3] = val;
8
  str[4] = 0;
9
}

Bedingung: Der Buffer, den man als str da reingibt, muß wenigstens 4 
Zeichen fassen können:
1
char my_str[4];
2
uint8_t my_val;
3
4
my_val = 42;
5
to_string[my_str, my_val);

Ergebnis: "042" in my_str, und nullterminiert.

von Nop (Gast)


Lesenswert?

argh..
1
void to_string(char *str, uint8_t val)
2
{
3
  str[0] = val / 100 + '0';
4
  val %= 100;
5
  str[1] = val / 10 + '0';
6
  val %= 10;
7
  str[3] = val + '0';
8
  str[4] = 0;
9
}

von Harlekin (Gast)


Lesenswert?

René K. schrieb:
> Manche Variablen können mal einen Wert von 5 bis 255 haben, nun muss
> aber der String immer die gleiche Länge haben um ihn am Empfänger
> auswärten zu können!

Alternative wäre, ein Trennzeichen zwischen die Variablen setzen. 
Stichwort csv

von René K. (tesla24)


Lesenswert?

Hallo wieder....

Ja stimmt dass mit dem Trennzeichen klingt auch gut!

Ich habe nun folgendes Problem:
Die Zusammensetzung und Umwandlung der verschiedenen Variablen in einen 
String funktioniert auch das mit den "Nullen" auffüllen. Ich habe mit 
einem anderen Compiler ein c-Programm geschrieben und mit printf zur 
Kontrolle ausgegeben.

Wenn ich einen char teststring[]="Hallo Welt" über die UART ausgebe wird 
es mir auch in HTerm angezeigt, also funktioniert die "uart_puts()"

Die Übertragung des von mir generierten String klappt aber leider nicht 
und ich komme nicht drauf. Mittlerweile habe ich auch schon alles ins 
main geschrieben.
1
#include <util/setbaud.h>
2
3
//Standardbibliotheken
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <string.h>
7
#include <avr/interrupt.h>
8
9
10
11
//Eigene Bibliotheken
12
#include "defines.h"
13
#include "init.h"
14
#include "globals.h"
15
#include "pwm.h"
16
17
char test_string[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
18
19
int main(void)
20
{
21
//Globale setzen nach Neustart
22
bga_go=1;
23
bga_power_bit=255;
24
led_go=1;
25
frost=1;
26
bga_stufen=7;
27
bga_max_power_bit=255;
28
bga_timer=123;
29
pwm_rot=1023;
30
pwm_gruen=1023;
31
pwm_blau=1023;
32
  
33
  
34
portinit();
35
timer0_init();
36
serial_init();
37
  
38
39
40
sei();
41
  
42
  
43
 while (1) 
44
{
45
//Umwandlung und Speichern der Globalen in die Strings
46
snprintf(bga_go_str,1,"%01d",bga_go);
47
snprintf(bga_power_bit_str,3,"%03d",bga_power_bit);
48
snprintf(frost_str,1,"%01d",frost);
49
snprintf(bga_stufen_str,1,"%01d",bga_stufen);
50
snprintf(bga_max_power_bit_str,"%03d",bga_max_power_bit);
51
snprintf(bga_timer_str,3,"%03d",bga_timer);
52
snprintf(led_go_str,1,"%01d",led_go);
53
snprintf(pwm_rot_str,4,"%04d",pwm_rot);
54
snprintf(pwm_gruen_str,4,"%04d",pwm_gruen);
55
snprintf(pwm_blau_str,4,"%04d",pwm_blau);
56
57
//strings verketten zu einem String 21 Einzelzeichen 
58
send_to_PI[0]=  bga_go_str[0];      
59
send_to_PI[1]=  bga_power_bit_str[0];      
60
send_to_PI[2]=  bga_power_bit_str[1];      
61
send_to_PI[3]=  bga_power_bit_str[2];      
62
send_to_PI[4]=  frost_str [0];
63
send_to_PI[5]=  bga_timer_str[0];
64
send_to_PI[6]=  bga_timer_str[1];
65
send_to_PI[7]=  bga_timer_str[2];
66
send_to_PI[8]=  led_go_str[0];
67
send_to_PI[9]=  pwm_rot_str[0];
68
send_to_PI[10]= pwm_rot_str[1];
69
send_to_PI[11]= pwm_rot_str[2];
70
send_to_PI[12]= pwm_rot_str[3];
71
send_to_PI[13]= pwm_gruen_str[0];
72
send_to_PI[14]= pwm_gruen_str[1];
73
send_to_PI[15]= pwm_gruen_str[2];
74
send_to_PI[16]= pwm_gruen_str[3];
75
send_to_PI[17]= pwm_blau_str[0];
76
send_to_PI[18]= pwm_blau_str[1];
77
send_to_PI[19]= pwm_blau_str[2];
78
send_to_PI[20]= pwm_blau_str[3];
79
send_to_PI[21]= bga_max_power_bit_str[0];
80
send_to_PI[22]= bga_max_power_bit_str[1];
81
send_to_PI[23]= bga_max_power_bit_str[2];
82
83
}
84
  
85
}
86
87
88
89
ISR(TIMER0_OVF_vect) 
90
{
91
  cli();
92
    
93
  //uart_puts(send_to_PI); //Das noch nicht !
94
  uart_puts(test_string); //Das Funktioniert perfekt !
95
  sei();
96
97
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Warum erst in verschiedene Strings per snprintf und dann diese wieder 
zusammenkopieren? Warum nicht direkt raussenden?
1
char buf[16];
2
3
snprintf(buf,1,"%01d",bga_go);
4
uart_puts(buf);
5
snprintf(buf,3,"%03d",bga_power_bit);
6
uart_puts(buf);
7
....

> send_to_PI[23]= bga_max_power_bit_str[2];

Hier fehlt die Terminierung:

send_to_PI[24] = '\0';

> ISR(TIMER0_OVF_vect)
> {
>   cli();
>
>   //uart_puts(send_to_PI); //Das noch nicht !
>   uart_puts(test_string); //Das Funktioniert perfekt !
>   sei();
>
> }

Das ist böse: Einen ganzen String in einer ISR rauskloppen macht man 
nicht. Das dauert viel zu lang.

Man setzt in der ISR ein Flag. In der Hauptschleife wertet man dann 
dieses Flag aus und sendet dann den String.

von René K. (tesla24)


Lesenswert?

Vielen Dank,

ich wollte das in eins rausschicken damit ich den String am Empfänger 
wieder in die Variablen aufdröseln und abspeichern kann.

Mit der ISR hatte ich auch schon bedenken, auch weil ich dort eine 
Schleife drin habe, was ja auch gefährlich ist.

Ich weiß irgendwie selber nicht warum mir das so Schwierigkeiten 
macht....klar ist schon etwas her das Ganze.

von Johnny B. (johnnyb)


Lesenswert?

René K. schrieb:
> Vielen Dank,
>
> ich wollte das in eins rausschicken damit ich den String am Empfänger
> wieder in die Variablen aufdröseln und abspeichern kann.
>
> Mit der ISR hatte ich auch schon bedenken, auch weil ich dort eine
> Schleife drin habe, was ja auch gefährlich ist.
>
> Ich weiß irgendwie selber nicht warum mir das so Schwierigkeiten
> macht....klar ist schon etwas her das Ganze.

Wenn Dein Empfänger auf einem grösseren Betriebssystem basiert ist aber 
auch nicht garantiert, dass Du den kompletten String als einen einzigen 
"Block" erhälst. Da musst Du eh damit umgehen können, dass der String 
unterteilt sein könnte, also alles was empfangen wird zusammensetzen, 
bis das Endzeichen (\0) empfangen wird.

von Walter K. (Gast)


Lesenswert?

Nur mal so interessehalber...

dieses Array send_to_PI[...]
ist was?  Klar, wenn es ein char-array sein soll fehlt die 
Null-Terminierung
- aber wo sehe ich was das ist, wie gross es deklariert wurde?

ist das auch in globals.h ?

von René K. (tesla24)


Lesenswert?

Das send_to_PI[] ist in den globals.h deklariert und ist ja der String 
den ich in eins übertragen möchte.

also mit dev-c Compiler funktioniert snprintf() aber in AVR nicht!

ich habe das mal mit atoi() gemacht und es klappt. Den funktionierenden 
Code poste ich gleich. Zuvor habe ich noch eine Frage:

nach jedem uart_puts() setzt er am Ende "\0" warum? liegt das irgendwie 
am Zeiger ?

Wie bekomme ich das hin das dort ein "\n" anstatt dem "\0" angehängt 
wird?

[c}
void uart_puts (const char *s)
{
   do
   {
     uart_putc (*s);
   }
   while (*s++);
   uart_putc('\n');
}
[/c]

von Nop (Gast)


Lesenswert?

René K. schrieb:

> nach jedem uart_puts() setzt er am Ende "\0" warum?

Weil Du eine do-while-Schleife anstatt einer while-do-Schleife 
verwendest.

von René K. (tesla24)


Lesenswert?

1
int main(void)
2
{
3
  //Globale setzen nach Neustart
4
  bga_go=1;
5
  bga_power_bit=128;
6
  bga_max_power_bit=255;
7
  bga_stufen=7;
8
  bga_timer=45;
9
  frost=0;
10
  led_go=1;
11
  pwm_rot=1023;
12
  pwm_gruen=1023;
13
  pwm_blau=1023;
14
  
15
  portinit();
16
  timer0_init();
17
  serial_init();
18
  
19
20
21
  sei();
22
  
23
    /* Replace with your application code */
24
    while (1) 
25
    {
26
    
27
    if(flag_uart_tx)
28
    {
29
      char buffer[7];
30
      
31
      uart_puts("A");
32
      
33
      //Umwandlung und Speichern der Globalen in die Strings
34
      itoa(bga_go,buffer,10);
35
      uart_puts(buffer);
36
      
37
      itoa(bga_power_bit,buffer,10);
38
      uart_puts(buffer);
39
      
40
      itoa(bga_max_power_bit,buffer,10);
41
      uart_puts(buffer);
42
      
43
      itoa(bga_stufen,buffer,10);
44
      uart_puts(buffer);
45
      
46
      itoa(bga_timer,buffer,10);
47
      uart_puts(buffer);
48
      
49
      itoa(frost,buffer,10);
50
      uart_puts(buffer);
51
      
52
      itoa(led_go,buffer,10);
53
      uart_puts(buffer);
54
            
55
      itoa(pwm_rot,buffer,10);
56
      uart_puts(buffer);
57
      
58
      itoa(pwm_gruen,buffer,10);
59
      uart_puts(buffer);
60
      
61
      itoa(pwm_blau,buffer,10);
62
      uart_puts(buffer);
63
      
64
      uart_puts("E");
65
      
66
      flag_uart_tx=0;    
67
    }
68
69
70
    }
71
  
72
}
73
74
75
76
ISR(TIMER0_OVF_vect) 
77
{
78
  cli();
79
    flag_uart_tx=1;
80
81
  sei();
82
83
}

von René K. (tesla24)


Lesenswert?

Nop schrieb:
> René K. schrieb:
>
>> nach jedem uart_puts() setzt er am Ende "\0" warum?
>
> Weil Du eine do-while-Schleife anstatt einer while-do-Schleife
> verwendest.

Stimmt...
so geht es:
1
void uart_puts (const char *s)
2
{
3
   while (*s)
4
   {
5
     uart_putc (*s);
6
     *s++;
7
   }
8
   uart_putc('\n');
9
10
}

von Nop (Gast)


Lesenswert?

René K. schrieb:

> so geht es:void uart_puts (const char *s)
> {
>    while (*s)
>    {
>      uart_putc (*s);
>      *s++;
>    }
>    uart_putc('\n');
>
> }

Etwas aufgeräumter wäre:
1
{
2
   while (*s)
3
   {
4
     uart_putc (*s);
5
     s++;
6
   }
7
   uart_putc('\n');
8
9
}

Und falls uart_putc nicht irgendein verstecktes Macro ist, sondern eine 
Funktion:
1
{
2
   while (*s)
3
   {
4
     uart_putc (*s++);
5
   }
6
   uart_putc('\n');
7
8
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

René K. schrieb:
> uart_putc('\n');

Das würde ich gar nicht in uart_puts() schreiben, dann wird das ja nach 
jeder Zahl gesandt. Da Du die zu sendenden Werte bereits auf feste 
Längen ausrichtest, brauchst Du einen solchen Trenner nicht.

Wenn doch, eignet sich '\n' eher nicht als Feldttrenner, da würde ich 
eher ein Leerzeichen ' ' oder ein Tab '\t' bevorzugen.

'\n' wird üblicherweise als Satztrenner benutzt, also am Ende Deines 
Datensatzes, also da, wo Du ein 'E' für Ende-des-Datensatzes sendest.

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.