Forum: Mikrocontroller und Digitale Elektronik AVR, Datentypumwandlung in C


von Burns B. (fox1707)


Lesenswert?

Versuche, die char (8 bit) Werte vom ATMEGA per USARTz zu senden. Excel 
soll die Werte einlesen.
Im Excel benötige ich die Werte und nicht die Zeichen. Besteht die 
Möglichkeit, dass Excel die Umwandlung vornimmt. Das hätte auch den 
Vorteil, dass nur ein Zeichen pro Wert übertragen wird.
Oder gibt es da einen C-Befehl der char-Werte in ASCI-Zeichen umwandelt? 
Danach müsste man die Zeichenkette (3 Zeichen) für einen Wert per USART 
senden.
Thanks im Voraus!

von Michael J. (jogibaer)


Lesenswert?

Hallo,

schau Dir mal >itoa< an.

Jogibär

von Burns B. (fox1707)


Lesenswert?

Hallo Jogibär!

Danke für deinen Tipp, aber leider funktioniert es nicht.
Sende ich den Integer-Wert 123 zum HyperTerminal, so bekomme ich dort 
123115!
Zum senden verwende ich "usart_puts".

Ich vermute, weil >itoa< nur für 16Bit Integer geeignet ist. Oder mache 
ich was falsch? Muss (kann) ich den INTEGER in eine CHAR-Wert umwandeln.
Bitte um Hilfe.

von Jens K. (f1d1)


Lesenswert?

Hi,

itoa wandelt dir deinen integer Wert in ein Array um. Oder Quasi in eine 
Char Variable, die müsstest du dann senden können.

Mache das mit meinem LCD Display am AVR auch.

In C sieht das dann so aus:
1
char umwandlung()
2
3
{
4
  int i = 100;      
5
  char lcd_wert [5];
6
  char lcdstring;
7
      
8
     i = lese();      //Analogwert aus lese UP aufrufen
9
    
10
    itoa (i,lcd_wert,10);  //Umwandeln in Dezimalstring
11
    
12
    lcdstring = lcd_wert;
13
14
      
15
    return lcdstring;  //Rückgabe int als string
16
17
18
19
}

MfG

von Harald F. (haraldf)


Lesenswert?

So ist das aber nichts.

1. Die auto-variable "lcd_wert" auf dem stack ist nach dem return nicht 
mehr gültig.

2. Der return eines solchen strings sollte auch mit "char *" deklariert 
sein.

3. Die Zuweisung "lcdstring = lcd_wert;" sollte eigentlich auch ein paar 
Warnings geben. Darüberhinaus ist sie unnötig.

Gruß

von Jens K. (f1d1)


Lesenswert?

Hi,
nunja, der Code läuft so.

1. Das war mir bewusst, wird sonst auch nirgendwo verwendet.

2. Bitte beschreib mir mal genauer, was du da meinst.

3. Warnungen gab es keine. Das sie nicht notwendig war, ist mir im 
nachhinein auch bewusst.

Ist eins meiner ersten Programme.

MfG

von Harald F. (haraldf)


Lesenswert?

Jens K. wrote:
> Hi,
> nunja, der Code läuft so.

Mag sein, aber nicht sicher.  Punkt 1. ist eine Zeitbombe, wenn dir da 
ein Interrupt bis zur Verwendung der Variable im Aufrufer dazwischen 
funkt wird Schrott ausgegeben.

>
> 1. Das war mir bewusst, wird sonst auch nirgendwo verwendet.

Dann ist es ja gut;-)

>
> 2. Bitte beschreib mir mal genauer, was du da meinst.

Nun, willst doch einen String in Form eines char-Arrays zurückgeben, 
oder? So wie du es deklarierst ist es aber nur ein einzelnes Zeichen.

>
> 3. Warnungen gab es keine.

Also hier (avr-gcc3.4.6) kommt:

"warning: assignment makes integer from pointer without a cast"


>
> War eins meiner ersten Programme.

Kein Problem.

Gruß

von Jens K. (f1d1)


Lesenswert?

Hi Harald,

Zum ersten Punkt, wie müsste ich mit der Variablen umgehen, dass sie 
nicht verloren geht? Müsste ich ne globale Variable verwenden, die ich 
im Unterprogramm verwende?

3. Habe es nochmal durchkompiliert und dabei habe ich auch deine besagte 
Warnung bekommen. Wie müsste ich den Return-Wert abändern, dass er mir 
dort diese Fehlermeldung nichtmehr ausgibt? Müsste ich an dieser Stelle 
auch eine globale Variable verwenden? Oder im Allgemeinen, wenn ich aus 
einem Unterprogramm einen Wert zurückgebe in ein anderes oder auch in 
Main, muss es sich beim zurückgeben in Main immer um eine globale 
Variable handeln und muss ich die Variable im Falle eines Aufrufs aus 
einem anderen Unterprogramm auch in dem aufrufenden Unterprogramm 
deklarieren, oder einfach in diesem Fall auch eine globale Variable 
verwenden?
Sollte ich in solch kleinen Programmen vll komplett auf lokale Variablen 
verzichten?

MfG

von Daniel F. (df311)


Lesenswert?

i.a. kann man in c mit chars genauso rechnen wie mit integer. je nach 
compiler ist manchmal sogar ein char nur ein int mit 8 bit. deshalb gibt 
es auch keinen unterschied in der übertragung ob nun 0x20, ' ' oder 32 
gesendet wird - nur die darstellung ändert sich.

daher ist es dem controller auch egal ob nun chars oder bytes gesendet 
werden. dadurch liegt das problem mit der darstellung als zahl oder als 
buchstabe auch an excel.

von Harald F. (haraldf)


Lesenswert?

Jens K. wrote:
> Hi Harald,
>
> Zum ersten Punkt, wie müsste ich mit der Variablen umgehen, dass sie
> nicht verloren geht?

Bei Programmierung im PC-Bereich würde ich mir Speicher über "malloc" 
(o. "new") holen und ihn beim Aufrufer wieder freigeben.

Bei Programmierung im uC-Bereich lege ich im Aufrufer den Speicher an, 
und übergebe ihn. Der kann dann auch lokal sein.

> 3. Habe es nochmal durchkompiliert und dabei habe ich auch deine besagte
> Warnung bekommen.

wusst' ich es doch;-)

> Wie müsste ich den Return-Wert abändern, dass er mir
> dort diese Fehlermeldung nichtmehr ausgibt?

Wenn du ein  char-Array zurückgeben willst, dann mit:
1
char *funktion()
2
{
3
   char *lcdstring;
4
..
5
..
6
..
7
   return lcdstring;  //Rückgabe als string
8
}

> Müsste ich an dieser Stelle
> auch eine globale Variable Verwenden? Oder im Allgemeinen, wenn ich aus
> einem Unterprogramm einen Wert zurückgebe in ein anderes oder auch in
> Main, muss es sich beim zurückgeben in Main immer um eine globale
> Variable handeln

nein. Es kommt darauf an ob du den Wert selbst zurück gibst, oder (wie 
hier) eine Referenz.

> Sollte ich in solch kleinen Programmen vll komplett auf lokale Variablen
> verzichten?

Würde ich nicht, lokale Variablen sparen statischen Speicher und sorgen 
auch für Kapselung.

Gruß

von Jens K. (f1d1)


Lesenswert?

Ok, vielen Dank schonmal bis hierhin.
Das mit dem Übergeben, wie meinst du das genau? Ich nehme mir einen 
Wert, übergebe ihn an mein Unterprogramm, verändere ihn dann dort und 
gebe den selben Wert wieder zurück? Oder Deklarierst du einen 
Übergabewert hin und einen Zurückwert im aufrufenden Programm?
Wenn ich mir das so durchlese klingt die zweite Möglichkeit etwas zu 
überdimensioniert, da ich den alten Wert danach ja eigentlich nichtmehr 
benötige. Oder liege ich da falsch?

Ok nun zu dem Codeschnipsel. Habe ihn nun mal so verändert:
1
char *umwandlung()
2
3
{
4
  int i = 100;      
5
  char *lcd_wert [5];
6
  
7
    
8
     i = lese();      //Analogwert aus lese UP aufrufen
9
    
10
    itoa (i,lcd_wert,10);  //Umwandeln in Dezimalstring
11
    
12
    
13
14
      
15
    return lcd_wert;  //rückgabe int als string

Bekomme dabei nun folgende Fehlermeldungen:

../int_to_string.c:14: warning: implicit declaration of function 'lese'

Diese Problem habe ich leider noch nicht so ganz duchschaut. Ich Rufe ja 
meine Funktion lese auf, in welcher ich den Analogwert einlese. Müsste 
ich mir im aufrufenden UP für diesen Wert noch eine Variable anlegen? 
Diese Fehlermeldung war aber schon vor der Änderung da. Aber da wir ja 
gerade dabei sind :=)

../int_to_string.c:16: warning: passing argument 2 of 'itoa' from 
incompatible pointer type

Diese Fehlermeldung ist neu, kann aber mit dieser leider garnichts 
anfangen.

../int_to_string.c:21: warning: return from incompatible pointer type

Auch diese ist neu, wird aber meiner Ansicht nach was mit der vorigen 
Fehlermeldung zu tun haben.

../int_to_string.c:21: warning: function returns address of local 
variable

Das ist ja das Problem, wo auch die erste Warnung drauf abzielt. Da 
werde ich nochmal genauer schauen müssen.

Hier nochmal das ganze Unterprogramm. fällt dir damit sicher leichter, 
als es dir nur vorzustellen.
1
#include <avr/stdlib.h>  // für Befehl itoa einbinden
2
#include <avr/io.h>
3
4
5
char *umwandlung()
6
7
{
8
  int i = 100;      
9
  char *lcd_wert [5];
10
  
11
    
12
     i = lese();      //Analogwert aus lese UP aufrufen
13
    
14
    itoa (i,lcd_wert,10);  //Umwandeln in Dezimalstring
15
    
16
    
17
18
      
19
    return lcd_wert;  //rückgabe int als string
20
21
22
23
}

MfG

von B e r n d W. (smiley46)


Lesenswert?

Ungefähr so?
- Das Array sollte von der aufrufenden Funktion definiert werden.
- Excel benötigt ein Trennzeichen: \t oder ; -> Tab, \r -> Return
1
#include <stdio.h>
2
#include <string.h>
3
#include <stdlib.h>  // für Befehl itoa einbinden
4
#include <avr\io.h>
5
6
unsigned char lese();
7
void usart_puts(char *ptr);
8
9
void 
10
umwandlung(unsigned char i, char *ptr)
11
{
12
   // Umwandeln in Dezimalstring
13
   itoa (i, ptr, 10);
14
   // Spalten bilden für Excel
15
   strcat(ptr, "\r");
16
}
17
18
int 
19
main()
20
{
21
char lcd_wert[5];
22
unsigned char i;      
23
24
   while(1) {
25
      // Analogwert lesen
26
//      i = lese();
27
      i = 123; // vorerst
28
      umwandlung(i, lcd_wert);
29
      usart_puts(lcd_wert);
30
   }
31
   return 0;
32
}

von Jens K. (f1d1)


Lesenswert?

Hi,
habe den code nun mal abgeändert in folgenden:
1
#include <avr/io.h>
2
#include <avr/lcd_routines.h>
3
#include <util/delay.h>
4
5
6
 
7
8
9
10
int main(void)
11
12
13
14
{
15
  char lcd_wert[5];
16
  unsigned char i;
17
  
18
  
19
  lcd_init();            //initialisieren LCD
20
 
21
    
22
23
 
24
    while(1)
25
  
26
  {
27
  
28
  lcd_init();
29
  i = lese();
30
  i = 123;
31
  umwandlung(i, lcd_wert);
32
  
33
  lcd_string(lcd_wert);    //Ausgabe des Umgewandelten Analogwertes auf LCD
34
  
35
36
 }
37
    return 0;
38
  }

Bekomme aber leider immernoch folgende Warnmeldungen:
../main_ausgabe.c:30: warning: implicit declaration of function 'lese'

und

../main_ausgabe.c:32: warning: implicit declaration of function 
'umwandlung'

Kannst du mir dazu noch etwas sagen?

MfG

von Johannes M. (johnny-m)


Lesenswert?

Die Fehlermeldungen bedeuten, dass die besagten Funktionen dem Compiler 
zum Zeitpunkt ihres Aufrufs nicht bekannt sind, weshalb der Compiler 
denkt, Du willst sie an der Stelle deklarieren. Eine Funktion muss vor 
ihrem ersten Aufruf mindestens deklariert werden.

Du solltest nebenbei noch eine Fehlermeldung der Art "Achtung! Zu viele 
Leerzeilen im Quelltext" bekommen, und da der Compiler das nicht macht, 
bekommst Du sie jetzt von mir...

von B e r n d W. (smiley46)


Lesenswert?

Die Funktionen lese() und umwandlung() benötigen eine 
Prototyp-Deklaration. Diese solltest du jeweils in einem Header-File mit 
dem gleichen Namen der C-Datei, in welcher sich die Original-Funktion 
befindet, jedoch mit der Endung .h unterbringen. Dieser Headerfile wird 
dann dort, wo er benötigt wird, included.

Zum Ausprobieren reichts erst mal, das oberhalb von main() einzufügen. 
Die Deklaration sollte aber identisch zur Originalfunktion sein. Da du 
diese Funktionen hier noch nicht reingestellt hattest, kann ich nur 
raten:

unsigned char lese();
void usart_puts(char *ptr);

Gruss, Bernd

von Jens K. (f1d1)


Lesenswert?

:)
Ok, werde meinen zukünftigen Code etwas kompakter schreiben.

Nunja, hab ein wenig rumprobiert und bin wohl auf den Grund gestoßen, 
warum er sie nicht finden kann. Aus Übersichtsgründen habe ich die 
einzelnen Funktionen in seperate *.c Daeien gepackt, die ich dann links 
neben im Projektbaum ( verwende AVR Studio mit GCC Plugin ) schön 
einzeln öffnen kann.
Wenn ich nun diese einzelnen Funktionen nehme und schreibe sie in die 
Datei wo sich auch mein main befindet, sind diese Fehlermeldungen weg. 
So scheint es zumindest erstmal.
Gibt es eine Möglichkeit dem Compiler zu sagen, dass er aus mehr als nur 
einer Datei besteht?

MfG

von Jens K. (f1d1)


Lesenswert?

Hallo Bernd,
das heisst nun, dass ich die einzelnen C Dateien dann in h Dateien 
umbenennen muss und sie dann oben include?
Das wäre ja sehr umständlich.
Dann noch eine Frage. Ich verwende ja nun die Standart Header Dateien. 
Links im Projektbaum ( AVR Studio 4 mit GCC Plugin ) gibt es ja so eine 
schöne Aufteilung. Kann ich die Headerdateien, die dort liegen nicht 
auch irgendwie einfach einbinden?
Würde in meinen Augen den Sinn machen, dass ich dann das Projekt schön 
zusammen in einem Verzeichnis hätte.

MfG

von B e r n d W. (smiley46)


Lesenswert?

Nein, es gibt eine Originaldate mit den kompletten Funktionen und eine 
Headerdatei mit den Prototypen, jedoch ohne Funktionsinhalt.

In die Datei "funktionen.h" kommt folgendes
1
void umwandlung(unsigned char i, char *ptr);

und in die Datei "funktionen.c" das
1
void umwandlung(unsigned char i, char *ptr)
2
{
3
   // Umwandeln in Dezimalstring
4
   itoa (i, ptr, 10);
5
   // Spalten bilden für Excel
6
   strcat(ptr, "\r");
7
}

von Jens K. (f1d1)


Lesenswert?

Und in die Headerdatei kommen dann alle Funktionen, die ich verwende?
Dann übernimmt der die Funktionen aus dem Projektbaum? Also die *.c 
Dateien?

von B e r n d W. (smiley46)


Lesenswert?

Standard Headerfiles werden üblicherweise so eingebunden:
#include <stdio.h>
dabei fügt der Compiler seinen default-include-Pfad ein.

und deine header so:
#include "funktionen.h"
Diese Datei wird aus deinem Verzeichnis eingefügt.

Bernd

von B e r n d W. (smiley46)


Lesenswert?

Alle Funktionsprototypen, welche irgendwann mal an anderer Stelle 
benötigt werden könnten, in die Header-Datei. Genauso die globalen 
Variablen und #defines.

von Jens K. (f1d1)


Lesenswert?

Nun habe ich ein anderes Problem. Habe in die Headerdatei die Funktionen 
eingetragen.
1
#include <avr/io.h>
2
#include <avr/lcd_routines.h>
3
#include <util/delay.h>
4
#include <avr/stdlib.h>
5
#include "funktionen.h"
6
 
7
int main(void)
8
{
9
  char lcd_wert[5];
10
  unsigned char i;
11
  
12
  
13
  lcd_init();            //initialisieren LCD
14
 
15
    while(1)
16
  {
17
  lcd_init();
18
  i = lese();
19
  i = 123;
20
  umwandlung(i, lcd_wert);
21
  
22
  lcd_string(lcd_wert);  //übergabe Wert an LCD   
23
   }
24
    return 0;
25
}

Nun kommen folgende Fehlermeldungen:

../main_ausgabe.c:7: error: expected '=', ',', ';', 'asm' or 
'__attribute__' before 'int'

und

../main_ausgabe.c:25: error: expected '{' at end of input

Beim Draufklicken springt der Zeiger in die Zeile meiner Main Anweisung
bei der zweiten Springt er auf die geschweifte Klammer am Ende?

Wenn ich die funktion.h wieder rausnehme, funktioniert alles wie vorher.

MfG

von B e r n d W. (smiley46)


Lesenswert?

Möglicherweise befindet sich der Fehler (fehlender Strichpunkt o.Ä.) in 
deiner "funktionen.h".

von Jens K. (f1d1)


Lesenswert?

tztztz
Unglaublich hohe Trefferquote deinerseits.

Dank dir

von Jens K. (f1d1)


Lesenswert?

Aber nun noch eine Frage. Wieso schreibe ich die Prototypen meiner 
Funktionen sowie die globalen Variablen nocheinmal in eine extra 
Headerdatei?
Die stehen ja eigentlich schon alle im Code. Oder liegt es an den vielen 
Codedateien, die ich habe?

von Rolf Magnus (Gast)


Lesenswert?

> Oder liegt es an den vielen Codedateien, die ich habe?

Ja, genau. Wenn der Compiler aufgerufen wird, wird das für genau eine 
.c-Datei gemacht. Er sieht nur diese, und sonst nichts. Damit er weiß, 
wie der Aufruf einer Funktion aussehen muß und welche Funktionen 
überhaupt existieren, benötigt er in dieser Datei deshalb den Prototyp. 
Damit man nun nicht in jeder einzelnen .c-Datei sämtliche Prototypen 
hinschreiben muß, werden die in Headern zusammengefaßt, die dann per 
#include vom Präprozessor in die .c-Datei eingebunden werden, bevor der 
eigentliche Compiler sie dann sieht.

von Jens K. (f1d1)


Lesenswert?

Ahh ok.
Muss ich diese Headerdatei dann in alle C Dateien einbinden oder nur in 
die, wo sich meine main Funktion drin befindet?

von B e r n d W. (smiley46)


Lesenswert?

Die Header-Datei muss überall dort eingebunden werden, wo du eine der 
Funktionen verwenden willst.

Selbst hier ist ein Prototyp notwendig, da funktion_b beim Aufruf noch 
nicht bekannt ist:
1
void funktion_b();
2
3
void funktion_a()
4
{
5
  funktion_b();
6
}
7
8
void funktion_b()
9
{
10
  ...
11
}

von Jens K. (f1d1)


Lesenswert?

Ahh jetzt kommts. Aber die Deklaration der Funktion sucht sich der 
Compiler dann selbst in dem Wust von Dateien?

von B e r n d W. (smiley46)


Lesenswert?

Der Compiler legt eine Tabelle mit Funktionen, Variablen, Konstanten 
usw. an. Beim Aufruf einer Funktion schaut der Compiler nach, ob und wie 
diese deklariert ist. Bei Unklarheiten gibts eine Warnung oder Error.

Der Linker weist später jeder Funktion eine Adresse zu. Damit ist erst 
dem Linker bekannt, wohin ein Aufruf/Sprung geht.

Bernd

von Jens K. (f1d1)


Lesenswert?

Vielen Dank für die netten Erklärungen.
Diese grundlegenden Möglichkeiten mit der Headerdatei und das Einbinden 
von Headerfiles, die neben im Projektverzeichnis sind, findet man leider 
( oder ich habe sie noch nicht gefunden ) in keinem c Tutorial.
Mfg

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.