Forum: Mikrocontroller und Digitale Elektronik globale variable sauber anlegen


von little_H (Gast)


Lesenswert?

Moin

ich habe da ihrgendwas noch nicht so richtig verstanden.
Vieleicht könnt ihr mir ja sagen wo ich da falsch denke.

ich möchte eine globale variable anlegen und zwar uint8 RX_BLE[16]

ich habe 3 .c files

main.c mit:

int main()
{


    // lade Globale variablen vor
  RX_BLE[1]=0x00;
  RX_BLE[2]=0x00;
  RX_BLE[3]=0x00;
  RX_BLE[4]=0x00;
  RX_BLE[5]=0x00;
  RX_BLE[6]=0x00;
  RX_BLE[7]=0x00;
  RX_BLE[8]=0x00;
  RX_BLE[9]=0x00;
  RX_BLE[10]=0x00;
  RX_BLE[11]=0x00;
  RX_BLE[12]=0x00;
  RX_BLE[13]=0x00;
  RX_BLE[14]=0x00;
  RX_BLE[15]=0x00;
  RX_BLE[16]=0x00;


       ........
       for(;;)
    {  .........
    }
}


BLE.c

void HandleBLE_RXTraffic(void * eventparam)
{
   while(n!=0)
  {
   RX_BLE[i]=RxBLEparm->handleValPair.value.val[i];
   n--;
   i++;

   if(RX_BLE[3]==1)
   {
    TEST_OUT_1_Write(!TEST_OUT_1_Read());
   }
  }

Uart.c

hier sollen später die RX_BLE Daten wenn eine anfrage auf die daten 
kommt in den uart übergeben werden.


deswegen wollte ich die daten global machen


habe sie also auserhalb des mains so definiert:
uint8 RX_BLE[17];


und dann in den Header BLE.h geschrieben

extern uint8 RX_BLE[17];


der kompiler meckert auch nicht aber ich bekomme nicht die richtigen 
daten (Byte3 müsste 1 sein).

wenn ich aber es lokal mache bekomme ich das richtige ergebniss die 
daten kommen aloso richtig an.

also so geht

BLE.c

void HandleBLE_RXTraffic(void * eventparam)
{
  uint8 RX_BLE[17];
  while(n!=0)
  {
   RX_BLE[i]=RxBLEparm->handleValPair.value.val[i];
   n--;
   i++;

   if(RX_BLE[3]==1)
   {
    TEST_OUT_1_Write(!TEST_OUT_1_Read());
   }
 }


was mache ich falsch.
Habe bis jetzt leider nur asm gemacht und da ist ja alles was ich 
definiere global also sorry wenn ihr sagt es ist quatsch die varialbe 
global anzulegen.
ach ja RX_BLE wird momentan nur in BLE.c aufgerufen eswegen verstehe ich 
auch nicht warum er anscheinend auf 2 speicherpätze zugreift.


Heidi

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

little_H schrieb:

>           // lade Globale variablen vor
>   RX_BLE[1]=0x00;

Überflüssiger Quatsch.

Globale Variablen sind mit 0 initialisiert.


> der kompiler meckert auch nicht aber ich bekomme nicht die richtigen
> daten (Byte3 müsste 1 sein).

Vermutlich hast du an irgendeiner Stelle ein "volatile" vergessen,
um dem Compiler mitzuteilen, dass der entsprechende Wert sich von
außerhalb seines Sichtbarkeitsbereichs (bspw. aus einem Interrupt)
ändern kann.

Das kann man aber nur sagen, wenn man das komplette Projekt sieht.

Du solltest deinen Variablen treffendere Namen geben, statt da
alles in ein großes globales Array zu knallen.

Beitrag #5227223 wurde von einem Moderator gelöscht.
von A. S. (Gast)


Lesenswert?

Wenn es mit dem lokalen Array funktioniert, dann überschreibt jemand 
Dein globales, ursprüngliches Array. Also z.B. ein Interrupt.


Oder es ist doch noch etwa anderes anders.

von little_H (Gast)


Lesenswert?

volatile habe ich niergens hingeschrieben da die Variable momentan nur 
in der funktion benutzt wird ich will sie aber im nächsten schritt im 
uart int. benutzen aber auch da werden sie nicht geändert sie werden 
einfach nur rausgesendet.

von Adapter (Gast)


Lesenswert?

vermutlich wird ein array erst richtig gefüllt, aber durch eine 
Racekondition danach ausgenullt. Ab wann ist die füllende Instanz aktiv?

Du kannst mal ganz einfach das Ausnullen durch das Besetzen mit einer 
festen Signatur (z.B. 0xa5) autauschen. Wenn Du zum zeitpunkt, an dem 
der Test gegen 3 gemacht wird, 0xa5 da findest, kam das Initialisieren 
später.

Willkommen in der wunderbaren Welt der nebenläufigen Programmierung!

von Falk B. (falk)


Lesenswert?

@little_H (Gast)

>volatile habe ich niergens hingeschrieben da die Variable momentan nur
>in der funktion benutzt wird ich will

Schon mal was von Satzbau gehört? Ohne Punkt und Komma schreiben ist 
nicht nur schlechter Stil sondern bisweilen auch unverständlich.

> sie aber im nächsten schritt im
>uart int. benutzen aber auch da werden sie nicht geändert sie werden
>einfach nur rausgesendet.

Das reicht um Probleme zu machen, denn die Variable muss dabei gelesen 
werden.

https://www.mikrocontroller.net/articles/Interrupt#Volatile_Variablen

von little_H (Gast)


Lesenswert?

@Falk Brunner
Tut mir leid ich war abgelenkt. Versuche es nicht mehr vorkommen zu 
lassen.
:-(

@ Adapter (Gast)
Habe den test schnell mal gemacht.
Init schein ok zu sein
Es ist auch so das die Daten immer wieder kommen(alle 50ms).
Momentan sind es immer die selbe Daten(zum testen).

Ich habe auch die alles mit einem neuen Namen nochmal angelegt falls 
doch ihrgenwo was reinspielt.


wenn ich die Daten jetzt nur in BLE.c und noch nicht weiter benutze, 
muss ich sie dann auch schon kenzeichnen?

und muss das so ausehen:
also auserhalb des mains so definieren
volatile  uint8 RX_BLE[17];

und dann in den Header BLE.h so

extern volatile uint8 RX_BLE[17];
ist das richtig

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mach aber nur die Variablen "volatile", die das auch brauchen.

U. U. muss das nicht das ganze Array sein.

von little_H (Gast)


Lesenswert?

Hilft auch nicht.
Noch wer ne Idee.
Ist übrigens ein Cypress chip falls das noch ne wichtige info ist.
Ich wünsche mir glaube ich mein assembler zurück da hat man solche 
probeme nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

little_H schrieb:
> Ich wünsche mir glaube ich mein assembler zurück da hat man solche
> probeme nicht.

Assembler hilft gegen Programmierfehler?  Das wäre neu …

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Kannst Du mal wenn nicht den vollständigen Code wenigstens den map file 
veröffentlichen?

von Marco H. (damarco)


Lesenswert?

Der Funktion als Pointer übergeben. Rx oder Tx Buffer da anlegen wo sie 
benötigt werden oder per initBLE(rxBuf,rxBufSize); auf pointer übergeben 
aber mit der Größe des buffers!.

alle internen Funktionen verwenden den static Pointer vom Buffer.

Das nennt man Struktur vom Code. Der zugebender maßen nicht immer 
einfach ist. Blöd ist nur wenn man zu spät merkt das man unten doch 
hätte ein Fenster mehr einbauen können. Um das zu vermeiden nimmt man 
sich einen Stift und macht sich Gedanken über die Struktur des Codes.

Außerdem lauern bei dem Code Style erheblich Risiken ;)

von W.S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Assembler hilft gegen Programmierfehler?  Das wäre neu

Ja - nämlich gegen die Programmierfehler, die aus un- oder falsch 
verstandenen Details von C herrühren.


little_H schrieb:
> void HandleBLE_RXTraffic(void * eventparam)
> {
>    while(n!=0)
>   {
>    RX_BLE[i]=RxBLEparm->handleValPair.value.val[i];
>    n--;
>    i++;

So, meine Kritik:
Erstens, wo ist bei dem Gezeigten das Initialisieren von n und i 
geblieben? Schreibst du vielleicht in die Irre mit RX_BLE[i]= ... ?

Zweitens, nur ne Formsache: Wenn deine RX_BLE Membes schon "in den uart 
übergeben" werden sollen, dann solltest du das auch als char RX_BLE[16] 
deklarieren, denn es sind ja wohl Char's, oder?

Aber das ist keine Formsache:
uint8 RX_BLE[16]
...
  RX_BLE[1]=0x00;
  ...
  ...
  RX_BLE[16]=0x00;



little_H schrieb:
> Uart.c
>
> hier sollen später die RX_BLE Daten wenn eine anfrage auf die daten
> kommt in den uart übergeben werden.

OK, du hast aus meiner Sicht eher seltsame Ansichten, was in einen Unit 
namens Uart.c hinein soll, aber bittesehr. Ich würde dir da eher 
anraten, dort lediglich die tatsächliche UART-Bedienung aka 
Low-Level-Treiber hineinzuschreiben und deinen Algorithmus in eine 
separate Quelle zu verlagern. Das würde dann auch den 
quellübergreifenden Zugriff auf deine 16 RX_BLS's beseitigen.

Nochwas: Schreibe für so eine separate Quelle eine Init-Funktion, die 
all die unit-internen Dinge richtig aufsetzt, anstatt sowas in main tun 
zu wollen. Und du kannst dort auch sowas wie memset oder ne eigene 
einfache Schleife nehmen, als stattdessen alle 16 Char's separat zu 
nullen. Und vertraue in diesem speziellen Punkt dem Jörg nicht gar zu 
sehr, denn was er gepostet hat, ist lediglich der fromme Wunsch der 
C-Programmierer, daß ab Start des µC der RAM ausgenullt sein soll. 
Sätze, die in einem C-Papier stehen sind das Eine, die Realität ist oft 
was Anderes.

W.S.

von A. S. (Gast)


Lesenswert?

little_H schrieb:
> Noch wer ne Idee.

Nochmal:

Dein gezeigter Code ist nicht lauffähig.

Dein echter Code wird ja sicher ohne Warnungen compilieren, ansonsten 
einfach einschalten. Wenn er dann immer noch nicht funktionieren sollte, 
stelle ihn hier ein und das Problem löst sich beim drüberschauen. (ggf. 
mit Angabe der Warnmeldungen)

Im gezeigten Codefragment ist volatile nicht das Problem (da das Element 
ja Deinen Angaben nach vorher auf 1 gesetzt wird).

Wenn Du einen Debugger hast, steppe dadurch.

Sperre die Interrupts (dann kann die Variable niemand überschreiben)

Stelle sicher, dass wirklich eine 1 reingeschrieben wird. Notfalls 
hangle dich von der Zeile vor dem if zurück zum Schreiben per 
RxBLEparm->handleValPair.value.val[i].

von Dirk B. (dirkb2)


Lesenswert?

little_H schrieb:
> (Byte3 müsste 1 sein)

Wie zählst du die Bytes? 1, 2, 3 oder 0, 1, 2, 3

von grundschüler (Gast)


Lesenswert?

Vorschlag für globale Variabeln in einer main.h:
1
//  Globals
2
#ifdef globals_main
3
#define ex 
4
#else
5
#define ex extern
6
#endif
7
8
ex v u8 down_timer1;
9
ex v u16 TIM3_CNT;
10
ex v u8 ir_start;
11
...

Die Variabeln werden nur an einer Stelle initialisiert/deklariert.

von Peter D. (peda)


Lesenswert?

little_H schrieb:
> was mache ich falsch.

Du stellst keinen compilierbaren Testcode bereit, mit dem man den Fehler 
analysieren könnte.

Bisher hat (fast) jeder Fragesteller, der nur Schnipselchen postet, nur 
solche gepostet, die den Fehler nicht enthalten oder die nicht dem 
tatsächlich getesteten Code entsprechen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

grundschüler schrieb:
> Vorschlag für globale Variabeln in einer main.h:

Kann man machen, aber wirklich toll finde ich das inzwischen nicht mehr.

> ex v u8 down_timer1;

Auf Bezeichner wie "u8" sollte man mittlerweile zugunsten der seit
knapp 20 Jahren in <stdint.h> standardisierten uint8_t, uint_fast8_t
etc. ohnehin verzichten …

> ex v u16 TIM3_CNT;

… und GROSSBUCHSTABEN sind von jeher per üblicher Konvention für
Makros da.

> Die Variabeln werden nur an einer Stelle initialisiert/deklariert.

Spätestens, wenn man globale Variable explizit (also nicht nur
implizit mit 0) initialisieren möchte, ist so ein Headerfile, wie von
dir zitiert, eher unpraktikabel.  Du fängst dann nämlich noch an,
einen weiteren klumpigen Makro dranzuhängen für den/die Initializer,
so a la:
1
#ifdef globals_main
2
#  define INIT(x) = x
3
#else
4
#  define INIT(x)
5
#endif
6
7
// …
8
9
ex v u8 ir_start INIT(42);

Ich finde das alles eher obfuscated.

von soundso (Gast)


Lesenswert?

also was jetzt ???

uint8 RX_BLE[16];

oder

uint8 RX_BLE[17];

Zugriffe auf RX_BLE[16] wären nur erlaubt bei der zweiten Deklaration 
!!!

Indizes von Arrays beginnen immer bei 0 und die Grösse beim deklarieren 
ist immer in Anzahl Elemente.

wenn du also

typ array[16];

schreibts, kannst du auf array[0] bis array[15] zugreifen ...

von grundschüler (Gast)


Lesenswert?

Jörg W. schrieb:
> Kann man machen, aber wirklich toll finde ich das inzwischen nicht mehr.

Danke, zumindest kein völliger Verriss.

Das Problem, das ich immer hatte - und was mich immer extrem geärgert 
hat - war, dass bei Trennung von Initialisierung und Deklaration 
Änderungen an mehreren Stellen im Code vorgenommen werden müssen. Mit 
der expliziten Initialisierung hast du recht. Das muss man dann 
konventionell machen.

>Auf Bezeichner wie "u8" sollte man mittlerweile zugunsten der seit
knapp 20 Jahren in <stdint.h> standardisierten uint8_t, uint_fast8_t
etc. ohnehin verzichten …


uint8_t ist wegen des '_' eine Menge Tastenarbeit. Ich meine, bei ARMs 
ist u8 als "#define u8 uint8_t" sogar irgendwo im Standard-code 
enthalten.
u8 geht wesentlich schneller, ist völlig eindeutig und wegen des 
häufigen Gebrauchs für faule Menschen nahezu ein Muss.


>GROSSBUCHSTABEN

Du hast natürlich recht, aber die Umschalttaste...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

grundschüler schrieb:

> Das Problem, das ich immer hatte - und was mich immer extrem geärgert
> hat - war, dass bei Trennung von Initialisierung und Deklaration
> Änderungen an mehreren Stellen im Code vorgenommen werden müssen.

Ja, und?

Wenn du eine neue Variable einführst, musst du sowieso an vielen
Stellen was ändern, da kommt's darauf nun wirklich nicht an.

> uint8_t ist wegen des '_' eine Menge Tastenarbeit.

Ach du Schreck …

Dafür fehlen mir die Worte, ehrlich gesagt.

> Ich meine, bei ARMs
> ist u8 als "#define u8 uint8_t" sogar irgendwo im Standard-code
> enthalten.

Selbst wenn: gerade im ARM-Umfeld dürfte oft ein uint_fast8_t viel
angebrachter sein.  uint8_t sollte man dort eigentlich nur benutzen,
wenn es tatsächlich wichtig ist, dass die Variable exakt 8 Bits
belegt (weil man bspw. den Überlauf von 255 nach 0 braucht oder das
zu einem externen Protokoll passen muss).  Ansonsten kostet die
Ausmaskierung nicht genutzter Bits aus einem 32-Bit-Register
zusätzlichen Code.

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.