mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Array Probleme


Autor: jonas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
ich brauche dringend eure Hilfe.
Ich habe ein C-Programm, welches mir Zeichenweise die empangenen Zeichen 
(RS232) in einen Array schriebt.

Jetzt möchte ich den Array komplett an eine andere Varible übergeben. 
Leider funktioniert var1 += array[i]; in einer schleife nicht, da so 
meine Werte addiert werden und nicht nebeneinander gespeichert werden.

Übersicht:
array[1] = 1
array[2] = 2
array[3] = 3

Struktur:
[var1 = array[1]array[2]array[3]]

Ausgabe:
var1 soll dann "123" sein.

Absicht:
Später sollen die empfangenen Zeichen komplett an eine Funktion übergben 
werden.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also Du empfängst Zahlenwerte und keine ASCII-Zeichen? Sind die Zahlen 
immer dreistellig? Welchen Wertebereich können die überhaupt haben? Wo 
hast Du array[0]?

Autor: bluebrother (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du kannst keine Werte so konkatenieren. Du willst ein neues Array haben 
und die Werte mit strncpy kopieren.
Alternativ kannst du auch einfach die Werte ab array[1] per Pointer 
übergeben. Musst dann natürlich darauf achten dass der aufgerufenen 
Funktion auch bekannt ist wie lang das neue Array ist und es 
funktioniert dann auch nur wenn die Werte (also Indizes) fortlaufend 
sind.

Und nachdem du hier mit array[1] beginnst: dir ist klar dass Indizes in 
C bei 0 anfangen, oder?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was du da schreibst ist reichlich verworren.

Aber schau dir mal zum Thema 'Wir funktionieren Strings in C'
mal folgendes an:

http://www.mikrocontroller.net//articles/FAQ#Wie_f...

Das sollte einiges klären.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ansonsten: Wenn aus "{1, 2, 3}" die Zahl 123 werden soll, dann musst Du 
einfach die jeweilige Ziffer mit dem Wert der entsprechenden 
Dezimalstelle multiplizieren, also z.B.
var1 = array[3];
var1 += array[2] * 10;
var1 += array[1] * 100;
Mit den obigen Werten steht dann die Zahl 123 in var1. Das ganze lässt 
sich natürlich viel eleganter in einer Schleife lösen
uint8_t i, mul;
var1 = 0;
for(i = 3, mul = 100; i; i--)
{
    var1 += array[i] * mul;
    mul /= 10;
}
(ohne Gewähr)

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so jetzt bin ich registriert^^

Also ich empfange auch ASCII Zeichen, und das ist mein größtes Problem.

Ich werde mir jetzt mal den Link angucken und schreiben was bei 
rumgekommen ist.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei ASCII-Zeichen musst Du halt vor der Addition und Multiplikation noch 
die '0' abziehen, um die betreffende Ziffer zu bekommen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jonas G. wrote:
> Ich werde mir jetzt mal den Link angucken und schreiben was bei
> rumgekommen ist.

Das Hauptproblem in deiner Fragestellung ist, dass nicht klar
ist worauf deine Frage abzielt. Es gibt da mehrere Interpretations-
möglichkeiten. Insbesondere ist nicht ganz klar, was dein
das Ergebnis sein soll.
Falls du noch Fragen hast, denke also daran die Fragestellung
zu präzisieren. Insbesondere hilft es meist, wenn du angibst
welche Datentypen involviert sind. Daraus kann man dann meist
dein eigentliches Problem erraten.

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okay,

ich habe jetzt mal gelesen und ausprobiert. Leider ohne wirklichen 
erfolg.
Ich möchte wissen, wie ich die Zeichen, die ich per UART bekomme und in 
"unsigned char c" speichere in den array "char temp_str[40]" speichern, 
sodass im arry später alle empangenen zeichen (Zahlen und Buchstaben) 
enthalten sind.

Leider gibt es Probleme, wenn ich c also UDR in den Array specihern 
möchte.
Meldung:
code.c:227: warning: passing argument 2 of 'strcat' makes pointer from 
integer without a cast
Das ist mein Code:
SIGNAL(SIG_UART_RECV)
{
  char temp_str[40];
        unsigned char c;
  c = UDR;
  strcat(temp_str,c);
  
  for(int i=0; i<40; i++){      //40 nur zum Test um den gesammten array auszulesen.
  uart_send_c(temp_str[i]);
  }
  
}

Wenn ich statt "c" einen String wie "TEST" einfüge, bekomme ich zwar 
keinen Fehler aber falsche Zeichen im Hyperterminal.

Jonas

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
c ist eine Variable. strcat erwartet als Argument aber einen Zeiger auf 
einen String (also wenn überhaupt, dann "&c" anstatt "c", aber da c kein 
String ist, geht der Rest dann wegen des fehlenden Nullterminators in 
die Hose). Aber das, was Du da vorhast, kann aus mehreren anderen 
Gründen nicht funktionieren. strcat ist an der Stelle völig unsinnig. Du 
brauchst im Prinzip nur ein array (das aber entweder global deklariert 
oder zumindest static sein muss!) und einen Zählindex, der ebenfalls 
global oder zumindest static sein muss. Jedes Mal, wenn ein Zeichen 
ankommt, wird dieses in array[i] geschrieben und i anschließend um 1 
erhöht. Die Ausgabe gehört dann ins Hauptprogramm (und dazu müssen array 
und Zählindex global und volatile sein).

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das was du schriebts stimmt zwar und so hat es mit der ausgabe auch 
funktioniert. Doch ich brauche unbedingt alle empangenen Zeichen in 
einer Variable oder muss die zusammen an eine Funktion übergben.

Hier die Funktion:
void stepper(int drive, int steps, int dir, int mode){..}

So möchte ich dann übergeben:
stepper(1, [Alle Zeichen bzw. kompl. Array], 1, 0);

Hoffe ihr verliehrt nicht die gedult mit mir^^

Jonas

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BTW: Du solltest möglichst anstelle des veralteten SIGNAL-Makros das 
aktuelle ISR verwenden. SIGNAL wird zwar von der aktuellen 
AVR-libc-Version noch unterstützt, ich denke jedoch, dass es irgendwann 
in nicht allzu ferner Zukunft "abgekündigt" wird. Gewöhne Dir am besten 
gleich die aktuelle Schreibweise an, sonst musst Du demnächst alle alten 
Programme ändern.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jonas G. wrote:
> Okay,
>
> ich habe jetzt mal gelesen und ausprobiert. Leider ohne wirklichen
> erfolg.
> Ich möchte wissen, wie ich die Zeichen, die ich per UART bekomme und in
> "unsigned char c" speichere in den array "char temp_str[40]" speichern,
> sodass im arry später alle empangenen zeichen (Zahlen und Buchstaben)
> enthalten sind.

Ganz einfach: Indem du sie ins Array zuweist:

  temp_str[naechstes_Zeichen] = UDR;

und natürlich danach naechstes_Zeichen um 1 erhöhen, sodass
das nächste Zeichen dann im Array an die nächste Position
kommt.

  naechstes_Zeichen++;

Also:
char temp_str[40];
int  nachstes_Zeichen;

SIGNAL(SIG_UART_RECV)
{
  temp_str[naechsts_Zeichen] = UDR;
  naechstes_Zeichen++;
}

Ein String wird in C in einem Array gespeichert. Die einzelnen
Elemente des Arrays sind die Zeichen die den String aufbauen.
Du kannst daher auf jedes einzelne Zeichen mit ganz normaler
Array Sytax zugreifen.
Erst dann wenn du das Array als Ganzes als String auffassen
möchtest, kommen die str... Funktionen ins Spiel.

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
johnny.m wrote:
> BTW: Du solltest möglichst anstelle des veralteten SIGNAL-Makros das
> aktuelle ISR verwenden.

Werde ich spätestens ändern, wenn die übergabe an die stepper funktion 
läuft. Eigendlcih mache ich das auch mit ISR. Keine Ahnung, warum ich es 
diesmal nciht gemacht haben xD

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hoffe ihr verliehrt nicht die gedult mit mir^^
Die Geduld vielleicht nicht, aber langsam die Übersicht, was Du 
eigentlich genau willst. Das, was Du oben geschrieben hast mit der 
UART-ISR, hat mit dem ursprünglichen Problem doch erstmal gar nichts 
mehr zu tun. Wie man ASCII-Zahlzeichen, die in der richtigen Reihenfolge 
ankommen, in einer Variablen aufaddiert, habe ich ganz oben schon 
beschrieben (zumindest prinzipiell). Dass Deine ISR so nicht 
funktionieren wird (unabhängig vom ersten Thema) steht auch fest. 
Deshalb jetzt die Aufforderung an Dich: Beschreibe einmal ausführlich, 
was Du genau willst, was Du bereits gemacht hast usw. Und versuche 
dabei, die oben u.a. von mir gestellten Fragen, die Du z.T. noch nicht 
wirklich beantwortet hast (z.B. "Wie sehen die Daten, die Du empfängst 
und an die Funktion weitergeben willst, überhaupt genau aus") zu 
beantworten.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jonas G. wrote:
> Das was du schriebts stimmt zwar und so hat es mit der ausgabe auch
> funktioniert. Doch ich brauche unbedingt alle empangenen Zeichen in
> einer Variable

Nochmal. Das geht nicht.
Alle empfangenen Zeichen zusammengenommen bilden einen String.
Es gibt aber keinen Datentyp für Strings! Es gibt nur ein Array

> Hier die Funktion:
>
> void stepper(int drive, int steps, int dir, int mode){..}
> 

Das ist aber was ganz anderes. Diese Funktion möchte
Zahlenwerte und keine Strings.

Du musst dich also damit beschäftigen, wie du aus einem
String "123" den Zahlenwert 123 bekommst.

>
> stepper(1, [Alle Zeichen bzw. kompl. Array], 1, 0);
> 

Hier:
             ********************************

hier musst du aus dem String "123" den Zahlenwert 123 machen.

Wenn der String korrekt aufgebaut ist (das abschliessende '\0'
nicht vergessen!) dann geht das so

  int Zahl = atoi( temp_str );

atoi macht aus einem entsprechend geformten String den
entsprechenden Zahlenwert. Da steckt nichts
geheimnusvolles dahinter. Angenommen du mueestes das
machen und ich geb die die Zeichen einzeln. Fangen wir
an.
Zunächst mal ist deine Zahl eine 0
Dann geb ich dir eine '5' (Also den ASCII Code für 5)
Du ziehst davon den Code für '0' ab, nimmst die bisherige
Zahl mal 10 und addierst die 5

   Zahl = 10 * Zahl + ( '5' - '0' )

Da Zahl vorher 0 war, kriegt Zahl als neuen Wert 5

Jetzt geb ich dir '8'. Davon die '0' abgezogen gibt 8, also
den Zahlenwert, der dem Zeichen '8' entspricht.
Und wieder nimmst du die bisherige Zahl mal 10
(also 5 * 10 -> 50 ) und addierst diese 8. Macht 58

Das nächste Zeichen das ich dir gebe ist eine '3'

   '3' - '0'     ->  3
   58 * 10   -> 580  und dazu noch die 3 addiert -> 583

Dann geb ich dir '7'

   '7' - '0'     -> 7
   583 * 10 -> 5830 + 7 -> 5837

Jetzt solltest du das Prinzip schon gesehen haben. In C Code
gegossen ist das dann:
  int ToNumber( char* String )
  {
    int i = 0;
    int Zahl = 0;

    while( String[i] != '\0' ) {
      Zahl = 10 * Zahl + ( String[i] - '0' );
      i++;
    }

    return Zahl;
  }

Zusammengefasst: Von der UART kriegst du einen String.
In diesem String steckt die Zeichenmässige Repräsentierung
einer Zahl. Die kann man wieder als Zahl zurückgewinnen und
dann natürlich in die stepper-Funktion weitergeben

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So dann starte ich mal:
Ich möchte eine Reihe von Zahlen und Buchstaben an den µC schicken und 
verarbeiten. Später soll mit diesem Daten die Funktion für die 
Schrittmoren "gefüttert" werden.
Dazu muss immer die ISR immer die empfangnen Zeichen speichern, was jezt 
auch funktioniert (hatte vorher irgendwie ein Brtee vorm Kopf). Code 
s.u.
Ich übergbe dann nach jedem Befehl ein Zeichen, was das Ende angibt. 
Dann muss der µC die Empfangenen Zeichen an die Funktion übergben hier 
ein Bsp.:
Gesendete Zeichen PC -> µC:
A;1;300;1;0;
Spätere Verarbeitung:
A=Stepper-Funktion
1=Motor 1
300 = 300 Schritte
1 = Linkslauf
0 = Vollschritt

So sieht mein Ziel aus. Doch das Eigendliche und oben besprochene 
Problem ist das, dass ich nicht weiß, wie ich die Zeichenkette aus 
mehreren Array-Einträgen übergbe. z.B.: die 300 wären ja 3 Einträge 
3-0-0 und wie übergbe ich die zusammen an die Funktion.

Hoffe es verwirrt nicht nochmehr...

Jonas

P.S.: Wie ich die Daten "auseinanderreiße" weiß ich und die 
Stepperfunktion ist auch fertig.

Hier die Codes:
//////////////////////UART-ISR zum Empfangen
SIGNAL(SIG_UART_RECV)
{
  temp_str[NextChar] = UDR;
  NextChar++;
  
  for(int i=0; i<40; i++){
  uart_send_c(temp_str[i]);
  }
  
}
//////////////////////Deklaration der Stepperfunktion
void stepper(int drive, int steps, int dir, int mode)...

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@   Karl heinz Buchegger:
Ich glaube in deinem Post ist die Antwort für mein Problem.
Ich teste jezt mal und dann melde ich meinen erfolg.

Jonas

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> A;1;300;1;0;
> Spätere Verarbeitung:
> A=Stepper-Funktion
> 1=Motor 1
> 300 = 300 Schritte
> 1 = Linkslauf
> 0 = Vollschritt
>
> So sieht mein Ziel aus. Doch das Eigendliche und oben besprochene
> Problem ist das, dass ich nicht weiß, wie ich die Zeichenkette aus
> mehreren Array-Einträgen übergbe. z.B.: die 300 wären ja 3 Einträge
> 3-0-0 und wie übergbe ich die zusammen an die Funktion.
>
> Hoffe es verwirrt nicht nochmehr...

Ganz im Gegenteil: Jetzt ist alles klar.
Du entdeckst gerade das ein String etwas anderes als eine Zahl ist,
selbst wenn in dem String "123" drinnensteht.
Lösung: schon gepostet: Du musst die Zahl aus dem String wieder
zurückgewinnen.

Autor: Monica L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <stdlib.h>
int main(void)
{
  char string[]={"A;1;300;1;0;"};
  int zahl;

  zahl = atoi(string+4);




return 0;
}

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ERFOLG:
SIGNAL(SIG_UART_RECV)
{
  temp_str[NextChar] = UDR;
  
  for(int i=0; i<40; i++){
  uart_send_c(temp_str[i]);
  }
  if (temp_str[NextChar] == 0x0D) {
  int zahl = atoi(temp_str);
  stepper(1,zahl,1,0);}
  NextChar++;
}

Wenn ich zB 400 sende und dann Enter drücke dreht sich der Motor 1 um 
genau 400 Schritte. (ist nen Motor mit 400 Stepps daher leicht zu 
erkennen)

Danke an alle und Sorry wenn ich euch verwirtt habe^^

Jonas

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
NextChar wieder auf 0 zurücksetzen, sonst überlaufst du
das Array irgendwann.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jonas G.

Ich glaube du hasst da noch ein Verständnissproblem was Interrupts 
angeht. Im Interrupt wird beim UART immer nur ein Zeichen gelesen und 
gespeichert, die Verarbeitung erfolgt zu 99% ausserhalb des Interrupts.

SIGNAL(SIG_UART_RECV)
{
  int8_t tmp;

  tmp= UDR;
  temp_str[NextChar] = tmp;
  NextChar++;
  if (NextChar>=MaxChar) NextChar=0;  // Sicherung gegen Overflow
  if (tmp=10) RX_complete=1;      // 10 ist der ASCII für RETURN
}

//////////////////////Deklaration der Stepperfunktion
void stepper(int drive, int steps, int dir, int mode)...

#define MaxChar 20

char temp_str[MaxChar];
uint8_t RX_complete=0;
int NextChar=0;

Im Main musst du dann prüfen ob RX_complete =1 ist, dann kannst du auf 
temp_str zugreifen und die Daten verarbeiten.

MfG
Falk

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk wrote:
> @Jonas G.
>
> Ich glaube du hasst da noch ein Verständnissproblem was Interrupts
> angeht. Im Interrupt wird beim UART immer nur ein Zeichen gelesen und
> gespeichert, die Verarbeitung erfolgt zu 99% ausserhalb des Interrupts.

Ne, den Code den ich da gepostet habe, der war nur zum Testen. Ich werde 
dass dans im Main-PRG machen.

Mir ging es dort nur um den Erfolg und den Test^^

Jonas

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jonas G.

>Ne, den Code den ich da gepostet habe, der war nur zum Testen. Ich werde
>dass dans im Main-PRG machen.

Auch zum Testen war der vollkommen unbrauchbar.

MFG
Falk

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
naja unbauchbar ist falsch, da es ja funktonier hat.
Jetzt wird rx_flag immer überprüft...
So muss ich natürlich jede Eingabe mit [Enter] abschließen.
SIGNAL(SIG_UART_RECV)
{
  temp_str[NextChar] = UDR;
  if (temp_str[NextChar] == 0x0D) {
  rx_flag=1;}
  else {
  NextChar++;
             }
}

  

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Überlaufsicherung von NextChar fehlt noch.

MFG
Falk

Autor: Jonas G. (jonny)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt, die kann ich auch ins ISR schreiben.
hatte sie im Main PRG

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jonas G.

>stimmt, die kann ich auch ins ISR schreiben.
>hatte sie im Main PRG

Die solltest du in ISR schreiben. Ist kompakter und sicherer.

MfG
Falk

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.