Forum: Mikrocontroller und Digitale Elektronik Array Probleme


von jonas (Gast)


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.

von johnny.m (Gast)


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]?

von bluebrother (Gast)


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?

von Karl H. (kbuchegg)


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_funktioniert_String-Verarbeitung_in_C.3F

Das sollte einiges klären.

von johnny.m (Gast)


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.
1
var1 = array[3];
2
var1 += array[2] * 10;
3
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
1
uint8_t i, mul;
2
var1 = 0;
3
for(i = 3, mul = 100; i; i--)
4
{
5
    var1 += array[i] * mul;
6
    mul /= 10;
7
}
(ohne Gewähr)

von Jonas G. (jonny)


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.

von johnny.m (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


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.

von Jonas G. (jonny)


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:
1
SIGNAL(SIG_UART_RECV)
2
{
3
  char temp_str[40];
4
        unsigned char c;
5
  c = UDR;
6
  strcat(temp_str,c);
7
  
8
  for(int i=0; i<40; i++){      //40 nur zum Test um den gesammten array auszulesen.
9
  uart_send_c(temp_str[i]);
10
  }
11
  
12
}

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

Jonas

von johnny.m (Gast)


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).

von Jonas G. (jonny)


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:
1
void stepper(int drive, int steps, int dir, int mode){..}

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

Hoffe ihr verliehrt nicht die gedult mit mir^^

Jonas

von johnny.m (Gast)


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.

von Karl H. (kbuchegg)


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:
1
char temp_str[40];
2
int  nachstes_Zeichen;
3
4
SIGNAL(SIG_UART_RECV)
5
{
6
  temp_str[naechsts_Zeichen] = UDR;
7
  naechstes_Zeichen++;
8
}

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.

von Jonas G. (jonny)


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

von johnny.m (Gast)


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.

von Karl H. (kbuchegg)


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:
>
1
> void stepper(int drive, int steps, int dir, int mode){..}
2
>

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.

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

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:
1
  int ToNumber( char* String )
2
  {
3
    int i = 0;
4
    int Zahl = 0;
5
6
    while( String[i] != '\0' ) {
7
      Zahl = 10 * Zahl + ( String[i] - '0' );
8
      i++;
9
    }
10
11
    return Zahl;
12
  }

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

von Jonas G. (jonny)


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:
1
//////////////////////UART-ISR zum Empfangen
2
SIGNAL(SIG_UART_RECV)
3
{
4
  temp_str[NextChar] = UDR;
5
  NextChar++;
6
  
7
  for(int i=0; i<40; i++){
8
  uart_send_c(temp_str[i]);
9
  }
10
  
11
}
12
//////////////////////Deklaration der Stepperfunktion
13
void stepper(int drive, int steps, int dir, int mode)...

von Jonas G. (jonny)


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

von Karl H. (kbuchegg)


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.

von Monica L. (Gast)


Lesenswert?

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

  zahl = atoi(string+4);




return 0;
}

von Jonas G. (jonny)


Lesenswert?

ERFOLG:
1
SIGNAL(SIG_UART_RECV)
2
{
3
  temp_str[NextChar] = UDR;
4
  
5
  for(int i=0; i<40; i++){
6
  uart_send_c(temp_str[i]);
7
  }
8
  if (temp_str[NextChar] == 0x0D) {
9
  int zahl = atoi(temp_str);
10
  stepper(1,zahl,1,0);}
11
  NextChar++;
12
}

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

von Karl H. (kbuchegg)


Lesenswert?

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

von Falk (Gast)


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

von Jonas G. (jonny)


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

von Falk (Gast)


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

von Jonas G. (jonny)


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.
1
SIGNAL(SIG_UART_RECV)
2
{
3
  temp_str[NextChar] = UDR;
4
  if (temp_str[NextChar] == 0x0D) {
5
  rx_flag=1;}
6
  else {
7
  NextChar++;
8
             }
9
}

  

von Falk (Gast)


Lesenswert?

Die Überlaufsicherung von NextChar fehlt noch.

MFG
Falk

von Jonas G. (jonny)


Lesenswert?

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

von Falk (Gast)


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

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.