Forum: Mikrocontroller und Digitale Elektronik char Array erhält zufällige Werte


von Christian O. (chris_o)


Lesenswert?

Hallo Leute,
ich bräuchte eure Hilfe!
Ich verwende MPLAB X IDE zum programmieren, da ich einen PIC 
Mikrocontroller verwende.
Ich hab mich jetzt schon länger eingearbeitet und möchte Daten von einem 
Mikrocontroller zum PC per Bluetooth schicken. Das ganze funktioniert 
soweit auch.
Mein Problem:
Ich möchte mein Programm jetzt in mehrere Source-files unterteilen. Dazu 
habe ich die einzelnen Source files und dazugehörige header-files 
angelegt.
Mein Programm arbeitet diese files auch wunderbar nacheinander ab. 
Leider hänge ich dabei noch etwas, wenn es darum geht ein char-Array zu 
übergeben.
In meiner Main baue ich mir ein char Array, dass 8 Zeichen lang ist => 
funktioniert wunderbar!
Anschließend rufe ich meine Funktion auf und möchte mein gebautes Array 
dort haben!
Ich habe mir gedacht, ich mache das folgendermaßen:
in meiner Main (die durch eine Schleife immer wieder neu abgearbeitet 
wird) rufe ich folgende Funktion auf und baue mir daraus mein Array:
1
int Bluetooth_send()
2
{
3
  static int laufvar = 0;
4
  static int sendezahl = 0;
5
  int Laenge = 8;
6
  char senden[8];
7
  static int sperren = 1;
8
 
9
  if (sperren == 1)        
10
  {
11
  //Byte-Array zum senden bauen
12
  senden[sendezahl] = 0x02;  //STX senden
13
  sendezahl++;
14
  if((data0 == 0x03) || (data0 == 0x16))  //Wenn ETX oder DLE in Nutzdaten vorkommt
15
  {
16
  senden [sendezahl] = 0x16;  //DLE einfügen
17
  sendezahl++;
18
  senden [sendezahl] = data0;
19
  sendezahl++;
20
  }
21
  else
22
  {
23
  senden[sendezahl] = data0;
24
  sendezahl++;
25
  }
26
 
27
  if((data1 == 0x03) || (data1 == 0x16))
28
  {
29
  senden [sendezahl] = 0x16;
30
  sendezahl++;
31
  senden [sendezahl] = data1;
32
  sendezahl++;
33
  }
34
  else
35
  {
36
  senden[sendezahl] = data1;
37
  sendezahl++;
38
  }
39
 
40
  if((data2 == 0x03) || (data2 == 0x16))
41
  {
42
  senden [sendezahl] = 0x16;
43
  sendezahl++;
44
  senden [sendezahl] = data2;
45
  sendezahl++;
46
  }
47
  else
48
  {
49
  senden[sendezahl] = data2;
50
  sendezahl++;
51
  }
52
 
53
  if((data3 == 0x03) || (data3 == 0x16))
54
  {
55
  senden [sendezahl] = 0x16;
56
  sendezahl++;
57
  senden [sendezahl] = data3;
58
  sendezahl++;
59
  }
60
  else
61
  {
62
  senden[sendezahl] = data3;
63
  sendezahl++;
64
  }
65
 
66
  if((din == 0x03) || (din == 0x16))
67
  {
68
  senden [sendezahl] = 0x16;
69
  sendezahl++;
70
  senden [sendezahl] = din;
71
  sendezahl++;
72
  }
73
  else
74
  {
75
  senden[sendezahl] = din;
76
  sendezahl++;
77
  }
78
 
79
 
80
  if ((laufvar == 0x03) || (laufvar == 0x16))
81
  {
82
  senden[sendezahl] = 0x16;
83
  sendezahl++;
84
  senden[sendezahl] = laufvar;  
85
  laufvar++;
86
  sendezahl++;
87
  }
88
  else
89
  {
90
  if (laufvar <=255)  //Laufvariable um Datenempfang beim Empfänger prüfen zu können
91
  {
92
  senden[sendezahl] = laufvar;  //Zählt von 0-255 und beginnt wieder bei 0
93
  laufvar++;
94
  sendezahl++;
95
  }
96
  else
97
  {
98
  senden[sendezahl] = 0;
99
  laufvar=1;
100
  sendezahl++;
101
  }  
102
  }
103
 
104
  senden[sendezahl] = 0x03;
105
  sendezahl = 0;
106
  }
107
  sperren = Bluetooth_Send(Laenge, senden);    // Hier wird Bluetooth_Send aufgerufen
108
 
109
  return 0;
110
}
Ich weiß, dass das ganze durch die DLE maskierung auch länger als 8 
werden kann (muss ich später noch ändern), aber das stört vorläufig 
nicht.

Mein Header sieht wie folgt aus:
1
#ifndef BLUETOOTH_H
2
#define   BLUETOOTH_H
3
 
4
int Bluetooth_Send(int Lang, char senden[]);
5
 
6
#endif   /* BLUETOOTH_H */

Und hier noch das Source-file:
1
#define FOSC (80000000ULL)
2
#define FCY (FOSC/2)
3
 
4
#include "C:\Program Files (x86)\Microchip\xc16\v1.25\include\lega-c\stdio.h"
5
#include "C:\Program Files (x86)\Microchip\xc16\v1.25\include\lega-c\stdlib.h"
6
#include "C:\Program Files (x86)\Microchip\xc16\v1.25\support\dsPIC33F\h\p33FJ16GS404.h"
7
#include "C:\Program Files (x86)\Microchip\xc16\v1.25\support\generic\h\xc.h"
8
#include "C:\Program Files (x86)\Microchip\xc16\v1.25\support\generic\h\libpic30.h"
9
#include "C:\Program Files (x86)\Microchip\xc16\v1.25\include\lega-c\time.h"
10
 
11
 
12
int Bluetooth_Send(int Lang,char senden[])
13
{
14
  static int i = 0;
15
  static int finish = 0;
16
 
17
  //Send data
18
  if (i <= Lang)
19
  {
20
  __delay_us(80);  //Verzögerung um Bluetoothmodul nicht zu überfordern (80µs)
21
  if(!IFS0bits.U1TXIF)  //Wenn Interrupt Flag nicht gesetzt
22
  {
23
  U1TXREG=senden[i];
24
  i++;
25
  }
26
  else
27
  {
28
  IFS0bits.U1TXIF = 0;  //Rücksetzen der Interruptflag
29
  }
30
  }
31
  if (i==Lang)
32
  {
33
  finish = 1;                    //erst wenn finish = 1, wird ein neues Array gebaut
34
  i=0;          
35
  }
36
  else
37
  {
38
  finish = 0;  
39
  }
40
 
41
  return (finish);
42
}

Mein Array sende ich über ein BLuetoothmodul, und empfange die Daten mit 
einem Terminalprogramm (Funktioniert wunderbar)
Die Daten sollen die Struktur wie folgt haben:
STX, 0x00, 0x00, 0x00, 0x00, 0x00, "Laufvariable von 0-255", ETX 
...ständig wiederholen (die Nullen werden später mit Sensordaten 
befüllt)

Mein Problem ist jetzt, dass ich am Terminalprogramm folgendes empfange:
{FF}{00}{00}{00}{88}{09}{00}{00}{FF}{00}{00}{00}{88}{09}{00}{00}...
und das ganze ständig!

Hab folgendes festgestellt:
nach dem ersten Durchlauf hab ich richtigerweise noch das STX im Array 
stehen. Im zweiten Durchlauf ist das bauen eines neuen Arrays 
gesperrt(da noch nicht alles gesendet ist). So bald ich nun wieder meine 
Funktion fürs Senden aufrufe, werden beliebige Werte in mein Array 
geschrieben. => Eben diese, die dann auch gesendet werden. Warum?
Bitte um Hilfe!

Gruß Chris

von Klaus (Gast)


Lesenswert?

Das hat zwar mit deinem Problem nichts zu tun, deine #includes sehen mit 
den vollen Namen merkwürdig aus:
1
#define FCY 16000000UL
2
#include <xc.h>
3
#include <stdint.h>
4
#include <stdio.h>
5
.
6
.

so sieht das bei mir aus. Und p33FJ16GS404.h gehört da garnicht hin, das 
erledigt xc.h automatisch. Ich schreib auch die Config-Bits mit in den 
Source, dann kann man nichts falsch einstellen und weiß auch in paar 
Monaten noch, wie sie sein sollen.
1
#pragma config BWRP = OFF               // Boot Segment Write Protect (Disabled)
2
#pragma config BSS = OFF                // Boot segment Protect (No boot program flash segment)
3
.
4
.

MfG Klaus

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Christian O. schrieb:
> char senden[8];

Das ist eine sogenannte Auto-Variable. Die liegt auf dem Stack und das 
Array enthält erstmal nicht zwingend 0-Werte.

Ich verstehe Deine Logik nicht, aber ist immer gewährleistet, dass 
niemals mehr als 8 Daten da hinein gelangen? Wenn mehrere Bedingungen 
wahr sind, können die Variable sendezahl größer als 8 werden.

Beim Funktionsaufruf

        Bluetooth_Send(Laenge, senden);

gibst Du auch gar nicht "sendezahl" herunter. Sie erhält also keine 
Information, wieviele Zeichen Du mittlerweile in "senden" gesammelt hast 
und wieviele Du senden willst.

Willst Du das wirklich so? Und wenn sendezahl am Ende nur 6 ist, 
schickst Du dann noch 2 zufällige Werte aus dem Array hinterher?

von Mike B. (mike_b97) Benutzerseite


Lesenswert?

gibts in C/C++ nich auch sowas wie eine Case..of.. - Anweisung?
Dann kann man den ganzen if then-Block kürzen, blickt ja keiner durch da

von B. S. (bestucki)


Lesenswert?

Hui, das sieht ja wirr aus. Ich fang einfach mal irgendwo an.

Du hast zwei Funktionen, die fast identisch heissen, das ist eher 
verwirrend (Bluetooth_send vs. Bluetooth_Send). Funktionen sollten das 
tun, was ihr Name verspricht, das ist bei mindestens einer der beiden 
nicht der Fall.

1
static int sendezahl = 0;
Das static kannst du dir sparen, du setzt die Variable am Ende der 
Funktion so oder so wieder auf Null.

1
char senden[8];
Der Inhalt des Arrays ist ersmal undefiniert. Es steht halt das drin, 
was gerade zufälligerweise dort im RAM steht. Benutze den Datentypen 
char nur, wenn du die Variable für Zeichen nutzen willst. Merke dir:
char != signed char
char != unsigned char

1
  senden[sendezahl] = 0x02;  //STX senden
2
  sendezahl++;
3
  if((data0 == 0x03) || (data0 == 0x16))  //Wenn ETX oder DLE in Nutzdaten vorkommt
Magic Numbers stiften eher Verwirrung. De Werte kannst du mit einem 
Makro oder einer const-Variable definieren. Benutzte aussagekräftige 
Namen.

1
  if (laufvar <=255)  //Laufvariable um Datenempfang beim Empfänger prüfen zu können
2
  {
3
  senden[sendezahl] = laufvar;  //Zählt von 0-255 und beginnt wieder bei 0
4
  laufvar++;
5
  sendezahl++;
6
  }
7
  else
8
  {
9
  senden[sendezahl] = 0;
10
  laufvar=1;
11
  sendezahl++;
12
  }
13
  }
Der Kommentar ist falsch. laufvar zählt von 1-256, wobei 256 abgefangen 
und die Null manuell zugewiesen wird. So wäre es übersichtlicher 
(funktioniert nur, wenn ein unsigned char 8 Bit hat):
1
static unsigned char laufvar = 0;
2
...
3
laufvar++; /* nutzt den Ueberlauf */
4
senden[sendezahl] = laufvar;
5
sendezahl++;


Versuche die Funktion Bluetooth_send besser zu strukturieren. Irgendwie 
werden Werte abhängig von globalen Variablen in ein Array geschrieben. 
Keiner weiss, wie viele Werte tatsätzlich geschrieben werden. Als 
Maximum habe ich 14 gezählt, dein Array hat aber die Länge 8.


Grundsätzlich habe ich deine Funktion so verstanden:
- Erzeuge ein Array aus den Werten data0, data1, data2, data3, din und 
laufvar.
- Der erste Wert im Array ist STX.
- Für alle Werte:
  - Ist der Wert gleich ETX oder DLF, schreibe DLF und anschliessend den 
Wert, ansonsten nur den Wert.
- Der letzte Wert im Array ist ETX.

Versuche identische Funktionalität in universelle Funktionen zu 
verpacken, z.B. das Schreiben der einzelnen Werte in das Array.



Was mir noch gerade aufgefallen ist:
Bluetooth_Send verarscht den Aufrufer so richtig. Es sendet nur das 
nächste Byte, nicht das gesamte Array. Das Array wird jedoch nach jedem 
Durchlauf neu berechnet, somit können wiederum andere Werte an gleicher 
Position stehen. Auch der Übergabeparameter Laenge ist immer 8, obwohl 
eine variable Anzahl an Werten ins Array geschrieben werden.


Bringe Struktur in dein Programm, so wird das nichts.


Nachtrag:
Normalerweise macht man das so:
Irgendwo werden die Daten erzeugt, die versendet werden müssen. Dann 
packt man diese in das geignete Prorotoll und schiebt diese in einen 
Sendebuffer (FIFO). Eine andere unabhängige Instanz prüft zyklisch, ob 
Daten im Buffer vorhanden sind und ob das Sendemodul verfügbar ist. 
Trifft beides zu, veranlasst die Instanz, dass das Sendemodul die Daten 
versendet.

: Bearbeitet durch User
von Christian O. (chris_o)


Lesenswert?

Erstmal danke für eure Antworten!

Frank M. schrieb
>Ich verstehe Deine Logik nicht, aber ist immer gewährleistet, dass
>niemals mehr als 8 Daten da hinein gelangen? Wenn mehrere Bedingungen
>wahr sind, können die Variable sendezahl größer als 8 werden.

Ja es kann größer werden, dass weiß ich auch... für das Problem wollte 
ich mir eine Lösung überlegen, so bald meine Daten richtig übergeben 
werden bzw. gesendet werden => Das spielt im Moment erst mal keine Rolle 
für mein Problem

>gibst Du auch gar nicht "sendezahl" herunter. Sie erhält also keine
>Information, wieviele Zeichen Du mittlerweile in "senden" gesammelt hast
>und wieviele Du senden willst.

Ich wollte das erst mal statisch mit 8 Zeichen machen um zu überprüfen 
ob das Senden überhaupt funktioniert! Um die ganze Problematik wollte 
ich mich später kümmern!

be stucki schrieb:
>Hui, das sieht ja wirr aus. Ich fang einfach mal irgendwo an.

Ich weiß schäm! Ich werde versuchen das Programm etwas besser zu 
strukturieren und meine Namen der Funktionen anzupassen!

>Das static kannst du dir sparen, du setzt die Variable am Ende der
>Funktion so oder so wieder auf Null.

Verstanden!

>Der Inhalt des Arrays ist ersmal undefiniert. Es steht halt das drin,
>was gerade zufälligerweise dort im RAM steht. Benutze den Datentypen
>char nur, wenn du die Variable für Zeichen nutzen willst.

Das da erst mal undefiniert Dinge aus dem RAM stehen ist mir bewust. Was 
würdest du für einen Datentyp benutzen? STX DEL und ETX sind ja ASCII 
zeichen... und die hex-Werte zwischendrin kann man ja auch als Zeichen 
verstehen... ist also doch kein Problem oder?!

>Der Kommentar ist falsch. laufvar zählt von 1-256, wobei 256 abgefangen
>und die Null manuell zugewiesen wird. So wäre es übersichtlicher

Für mich war in dem Kommentar eher die Überlegung was ich am Ende raus 
bekomme... da wird der Wert von 0 auf 255 erhöht und wieder bei 0 
angefangen....gelöst ist das eben mit dem Zähler von 1-256... mal sehen 
ob ich das vllt noch anders mache! Werd mir deinen Vorschlag durch den 
Kopf gehen lassen.

>Versuche die Funktion Bluetooth_send besser zu strukturieren. Irgendwie
>werden Werte abhängig von globalen Variablen in ein Array geschrieben.
>Keiner weiss, wie viele Werte tatsätzlich geschrieben werden. Als
>Maximum habe ich 14 gezählt, dein Array hat aber die Länge 8.

Jop stimmt! Das Problem werd ich lösen, wenn meine Übergabe prinzipiell 
erst mal funktioniert! (Ob ich da eventuell ein paar Werte verliere, 
interessiert mich vorerst nicht...  ;-) )


>Grundsätzlich habe ich deine Funktion so verstanden:
>- Erzeuge ein Array aus den Werten data0, data1, data2, data3, din und
>laufvar.
>- Der erste Wert im Array ist STX.
>- Für alle Werte:
>  - Ist der Wert gleich ETX oder DLF, schreibe DLF und anschliessend den
>Wert, ansonsten nur den Wert.
>- Der letzte Wert im Array ist ETX.

Genau so soll es sein!

>Was mir noch gerade aufgefallen ist:
>Bluetooth_Send verarscht den Aufrufer so richtig. Es sendet nur das
>nächste Byte, nicht das gesamte Array. Das Array wird jedoch nach jedem
>Durchlauf neu berechnet, somit können wiederum andere Werte an gleicher
>Position stehen. Auch der Übergabeparameter Laenge ist immer 8, obwohl
>eine variable Anzahl an Werten ins Array geschrieben werden.

Ja er sendet nur das nächste Byte (ich wollte hier eine Schleife im 
Source-file vermeiden). Die Schleife habe ich in der Main, die immer 
wieder meine Sendefunktion aufruft! Das Array wird nicht nach jedem 
Aufruf neu berechnet, da ich erst wenn ich 8 Bytes gesendet habe, eine 
Freigabe zum neu berechnen erteile:
Vor dem Bauen des Arrays steht folgende Anweisung:
1
if (sperren == 1)

sperren schalte ich mit hilfe der Sendefunktion auf 0:
1
  if (i==Lang)
2
  {
3
  finish = 1;                    //erst wenn finish = 1, wird ein neues Array gebaut
4
  i=0;          
5
  }
6
  else
7
  {
8
  finish = 0;  
9
  }
10
 
11
  return (finish);

Mein Problem ist jetzt, dass beim zweiten Durchlauf (wo dann das Bauen 
des Arrays gespert ist) einfach beliebige Werte in das Array geschrieben 
werden, die dann gesendet werden....Ich verstehe nicht warum! Wenn ein 
Array einmal befüllt ist, behält er doch normalerweise die Werte oder 
nicht?

Könnte es sein, dass wegen meiner deklaration im Header das Array jedes 
mal beliebig befüllt wird bzw. einer anderen Adresse zugewiesen wird 
wenn ich die Funktion neu aufrufe?

>Normalerweise macht man das so:
>Irgendwo werden die Daten erzeugt, die versendet werden müssen. Dann
>packt man diese in das geignete Prorotoll und schiebt diese in einen
>Sendebuffer (FIFO). Eine andere unabhängige Instanz prüft zyklisch, ob
>Daten im Buffer vorhanden sind und ob das Sendemodul verfügbar ist.
>Trifft beides zu, veranlasst die Instanz, dass das Sendemodul die Daten
>versendet.

Daten erzeugen wird in einer separaten Funktion gemacht, die meine 
Eingänge auslesen. Diese werden dann in data0 etc. gespeichert. Aus 
diesen wird dann mein Array gebaut.

Das ganze möchte ich dann via UART an mein BLuetoothmodul schicken. 
Hierzu wird mein Byte durch das U1TXREG in den FIFO-Sendebuffer 
geschoben. (dieser ist maximal 4Byte lang, weshalb ich einfach jedes 
Byte extra rein packe.)
1
if(!IFS0bits.U1TXIF)  //Wenn Interrupt Flag nicht gesetzt
Durch diese Abfrage prüfe ich, ob das Sendemodul bereit ist, Daten zu 
senden. Die Interrupt Flag muss ich dann manuell wieder rücksetzen um 
senden zu können.

Das ist doch also in etwa das, was du gemeint hast oder?

Aber wie gesagt, mein Problem ist ja aktuell ein anderes!


"Mein Problem ist jetzt, dass beim zweiten Durchlauf (wo dann das Bauen 
des Arrays gespert ist) einfach beliebige Werte in das Array geschrieben 
werden, die dann gesendet werden....Ich verstehe nicht warum! Wenn ein 
Array einmal befüllt ist, behält er doch normalerweise die Werte oder 
nicht?

Könnte es sein, dass wegen meiner deklaration im Header das Array jedes 
mal beliebig befüllt wird bzw. einer anderen Adresse zugewiesen wird 
wenn ich die Funktion neu aufrufe?"

von B. S. (bestucki)


Lesenswert?

Christian O. schrieb:
> Mein Problem ist jetzt, dass beim zweiten Durchlauf (wo dann das Bauen
> des Arrays gespert ist) einfach beliebige Werte in das Array geschrieben
> werden, die dann gesendet werden....Ich verstehe nicht warum! Wenn ein
> Array einmal befüllt ist, behält er doch normalerweise die Werte oder
> nicht?

Dann musst du das Array als static definieren, so wie du es bei anderen 
Variablen tust. Ansonsten wird das Array bei jedem Funktionsaufruf mit 
"zufälligen" Werten gefüllt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Christian O. schrieb:
> Könnte es sein, dass wegen meiner deklaration im Header das Array jedes
> mal beliebig befüllt wird bzw. einer anderen Adresse zugewiesen wird
> wenn ich die Funktion neu aufrufe?"

Ja, natürlich.

Entweder Du machst das Array static statt wie jetzt implizit auto, oder 
Du initialisierst es zunächst mit 8 Nullen.

von B. S. (bestucki)


Lesenswert?

Christian O. schrieb:
> Was
> würdest du für einen Datentyp benutzen? STX DEL und ETX sind ja ASCII
> zeichen... und die hex-Werte zwischendrin kann man ja auch als Zeichen
> verstehen... ist also doch kein Problem oder?!

Wenns ASCII-Zeichen sind, ist char ok. Sonderzeichen würde ich jedoch 
zur besseren Lesbarkeit des Codes als Makro hinschreiben:
1
#define ASCII_STX 0x02
2
// usw...

Christian O. schrieb:
> Jop stimmt! Das Problem werd ich lösen, wenn meine Übergabe prinzipiell
> erst mal funktioniert! (Ob ich da eventuell ein paar Werte verliere,
> interessiert mich vorerst nicht...  ;-) )

Das macht man schon grundsätzlich so, wie du das gemacht hast: Übergabe 
eines Zeigers + Länge. Andererseits ist dein Array mit ETX terminiert 
(wie ein String mit '\0'), dann kannst du dir die Längenangabe sparen. 
Kann jedoch auch Verwirrung stiften, da ein char-Array normalerweise für 
Strings verwendet wird. Also evt. doch noch die '\0' am Schluss 
spenieren. Eigentlich ist es ja auch nichts anderes als ein String.

: Bearbeitet durch User
von Christian O. (chris_o)


Lesenswert?

Ok, Danke für die hinweise...

Werd das morgen gleich mal ausprobieren...

von Christian O. (chris_o)


Lesenswert?

Hi,

static hat geklappt! Danke

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.