www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR, Datentypumwandlung in C


Autor: Burns B. (fox1707)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Michael J. (jogibaer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

schau Dir mal >itoa< an.

Jogibär

Autor: Burns B. (fox1707)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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:
char umwandlung()

{
  int i = 100;      
  char lcd_wert [5];
  char lcdstring;
      
     i = lese();      //Analogwert aus lese UP aufrufen
    
    itoa (i,lcd_wert,10);  //Umwandeln in Dezimalstring
    
    lcdstring = lcd_wert;

      
    return lcdstring;  //Rückgabe int als string



}

MfG

Autor: Harald F. (haraldf)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Harald F. (haraldf)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Daniel F. (df311)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Harald F. (haraldf)
Datum:

Bewertung
0 lesenswert
nicht 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:
char *funktion()
{
   char *lcdstring;
..
..
..
   return lcdstring;  //Rückgabe als string
}

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

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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:
char *umwandlung()

{
  int i = 100;      
  char *lcd_wert [5];
  
    
     i = lese();      //Analogwert aus lese UP aufrufen
    
    itoa (i,lcd_wert,10);  //Umwandeln in Dezimalstring
    
    

      
    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.

#include <avr/stdlib.h>  // für Befehl itoa einbinden
#include <avr/io.h>


char *umwandlung()

{
  int i = 100;      
  char *lcd_wert [5];
  
    
     i = lese();      //Analogwert aus lese UP aufrufen
    
    itoa (i,lcd_wert,10);  //Umwandeln in Dezimalstring
    
    

      
    return lcd_wert;  //rückgabe int als string



}


MfG

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ungefähr so?
- Das Array sollte von der aufrufenden Funktion definiert werden.
- Excel benötigt ein Trennzeichen: \t oder ; -> Tab, \r -> Return
#include <stdio.h>
#include <string.h>
#include <stdlib.h>  // für Befehl itoa einbinden
#include <avr\io.h>

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

void 
umwandlung(unsigned char i, char *ptr)
{
   // Umwandeln in Dezimalstring
   itoa (i, ptr, 10);
   // Spalten bilden für Excel
   strcat(ptr, "\r");
}

int 
main()
{
char lcd_wert[5];
unsigned char i;      

   while(1) {
      // Analogwert lesen
//      i = lese();
      i = 123; // vorerst
      umwandlung(i, lcd_wert);
      usart_puts(lcd_wert);
   }
   return 0;
}

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
habe den code nun mal abgeändert in folgenden:
#include <avr/io.h>
#include <avr/lcd_routines.h>
#include <util/delay.h>


 



int main(void)



{
  char lcd_wert[5];
  unsigned char i;
  
  
  lcd_init();            //initialisieren LCD
 
    

 
    while(1)
  
  {
  
  lcd_init();
  i = lese();
  i = 123;
  umwandlung(i, lcd_wert);
  
  lcd_string(lcd_wert);    //Ausgabe des Umgewandelten Analogwertes auf LCD
  

 }
    return 0;
  }

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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht 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
void umwandlung(unsigned char i, char *ptr);

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

Autor: Jens K. (f1d1)
Datum:

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

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: B e r n d W. (smiley46)
Datum:

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

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun habe ich ein anderes Problem. Habe in die Headerdatei die Funktionen 
eingetragen.
#include <avr/io.h>
#include <avr/lcd_routines.h>
#include <util/delay.h>
#include <avr/stdlib.h>
#include "funktionen.h"
 
int main(void)
{
  char lcd_wert[5];
  unsigned char i;
  
  
  lcd_init();            //initialisieren LCD
 
    while(1)
  {
  lcd_init();
  i = lese();
  i = 123;
  umwandlung(i, lcd_wert);
  
  lcd_string(lcd_wert);  //übergabe Wert an LCD   
   }
    return 0;
}

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

Autor: B e r n d W. (smiley46)
Datum:

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

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tztztz
Unglaublich hohe Trefferquote deinerseits.

Dank dir

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jens K. (f1d1)
Datum:

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

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht 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:
void funktion_b();

void funktion_a()
{
  funktion_b();
}

void funktion_b()
{
  ...
}

Autor: Jens K. (f1d1)
Datum:

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

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jens K. (f1d1)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.