Forum: Mikrocontroller und Digitale Elektronik Vermtliches Pointer Problem


von Antny (Gast)


Lesenswert?

Hallo Leute, kann mal bitte jemand in den Code gucken und mir sagen, 
warum die werte in dem Struct nicht aktualisiert werden, bzw. nur 
unvollständig ich bekomme es irgendwie einfach nicht zum laufen...

Dankeschön
1
void ADC_Messung ()
2
{
3
  if (ADCprescaler >6)
4
  {
5
    PORT_CS_ADC_STEU &= ~( 1 << PIN_CS_ADC_STEU );
6
    SPCR =  (1<<SPE)  |  //SPI- Enable
7
        (1<<MSTR)  |
8
        (1<<SPR1);  //Set Master
9
10
    _delay_ms(10);
11
12
    switch (nextChannel)
13
    {
14
      case TempCh1:  read_adc(&(Ch1.Temperatur[2]));
15
              Ch1.Temperatur[2]&=0x0F;
16
              read_adc(&(Ch1.Temperatur[1]));
17
              read_adc(&(Ch1.Temperatur[0]));
18
              nextChannel=ULast1;
19
              break;
20
      case CurrCh1:  read_adc(&Ch1.Strom[2]);
21
              Ch1.Strom[2]&=0x0F;
22
              read_adc(&Ch1.Strom[1]);
23
              read_adc(&Ch1.Strom[0]);
24
              nextChannel=ULast1;
25
              break;
26
      case ULast1:  read_adc(&Ch1.Spannung[2]);
27
              Ch1.Spannung[2]&=0x0F;
28
              read_adc(&Ch1.Spannung[2]);
29
              read_adc(&Ch1.Spannung[2]);
30
              nextChannel=TempCh1;
31
              break;
32
      /*case TempCh2:  Ch2.Temperatur[2]=0x0F & read_adc();
33
              Ch2.Temperatur[1]=read_adc();
34
              Ch2.Temperatur[0]=read_adc();
35
              nextChannel=CurrCh2;
36
              break;
37
      case CurrCh2:  Ch2.Strom[2]=0x0F & read_adc();
38
              Ch2.Strom[1]=read_adc();
39
              Ch2.Strom[0]=read_adc();
40
              nextChannel=ULast2;
41
              break;
42
      case ULast2:  Ch2.Spannung[2]=0x0F & read_adc();
43
              Ch2.Spannung[1]=read_adc();
44
              Ch2.Spannung[0]=read_adc();
45
              nextChannel=TempCh1;
46
              //luefterregelung(&msb,&Ch1.PWM_Fan,1,&Ch1.temp_old,&Ch1.t_delta_sum);
47
              break;*/
48
    }
49
    PORT_CS_ADC_STEU |=  ( 1 << PIN_CS_ADC_STEU );
50
    _delay_ms(1);
51
    SPDR=nextChannel;
52
    while ( ! ( SPSR&(1<<SPIF) ) );
53
    SPDR=nextChannel;
54
    while ( ! ( SPSR&(1<<SPIF) ) );
55
56
    uint16_t msb=Ch1.Temperatur[2]<<11;
57
    msb|=Ch1.Temperatur[1]<<3;
58
    msb|=Ch1.Temperatur[0]>>3;
59
    ADCprescaler=0;
60
    uart_sendc('A');
61
//    uart_sendc(&Ch1.Temperatur[2]);
62
//    uart_sendc(&Ch1.Temperatur[1]);
63
//    uart_sendc(&Ch1.Temperatur[0]);
64
//    uart_sendc('B');
65
//    uart_sendc(&Ch1.Spannung[2]);
66
//    uart_sendc(&Ch1.Spannung[1]);
67
//    uart_sendc(&Ch1.Spannung[0]);
68
69
    //Einstellen des mächsten Kanals
70
71
72
73
  }
74
}
75
76
void read_adc (uint8_t *value)
77
{
78
  PORT_CS_ADC_STEU &= ~( 1 << PIN_CS_ADC_STEU );
79
  SPCR =  (1<<SPE)  |  //SPI- Enable
80
      (1<<MSTR)  |
81
      (1<<SPR1);  //Set Master
82
  SPDR=0b10101010;
83
  while ( ! ( SPSR&(1<<SPIF) ) );
84
  *value=SPDR;
85
}

von Karl H. (kbuchegg)


Lesenswert?

Antny schrieb:
> Hallo Leute, kann mal bitte jemand in den Code gucken und mir sagen,
> warum die werte in dem Struct nicht aktualisiert werden,

welche Struct?

> bzw. nur
> unvollständig

Welche werden aktualisiert, welche nicht?

> ich bekomme es irgendwie einfach nicht zum laufen...

Das könnte an deiner Codeformatierung liegen.
Viel zu dicht.


Das sieht seltsam aus:

>     switch (nextChannel)
>     {
>       case TempCh1:  read_adc(&(Ch1.Temperatur[2]));
>               Ch1.Temperatur[2]&=0x0F;
>               read_adc(&(Ch1.Temperatur[1]));
>               read_adc(&(Ch1.Temperatur[0]));
>               nextChannel=ULast1;
>               break;

beim nächsten Aufruf gehts also weiter mit ULast1


>       case CurrCh1:  read_adc(&Ch1.Strom[2]);
>               Ch1.Strom[2]&=0x0F;
>               read_adc(&Ch1.Strom[1]);
>               read_adc(&Ch1.Strom[0]);
>               nextChannel=ULast1;
>               break;

auch hier gehts beim nächsten mal weiter mit ULast1


>       case ULast1:  read_adc(&Ch1.Spannung[2]);
>               Ch1.Spannung[2]&=0x0F;
>               read_adc(&Ch1.Spannung[2]);
>               read_adc(&Ch1.Spannung[2]);
>               nextChannel=TempCh1;
>               break;

und wieder von vorne, beim nächsten mal mit TempCh1.

Wenn du ausserhalb nie nextChannel auf CurrCh1 setzt, wirst du den Fall 
das nextChannel irgendwann CurrCh1 ist, nie haben. Damit sind schon mal 
Ch1.Strom[2], [1], [0] ohne Werte. Ich vermute mal im Fall TempCh1 
sollte nextChannel eigentlich auf CurrCh1 gesetzt werden und nicht auf 
ULast1

Aus Analogiegründen sieht auch das seltsam aus:

>       case ULast1:  read_adc(&Ch1.Spannung[2]);
>               Ch1.Spannung[2]&=0x0F;
>               read_adc(&Ch1.Spannung[2]);
>               read_adc(&Ch1.Spannung[2]);
>               nextChannel=TempCh1;
>               break;

In allen anderen Fällen verteilst du die ADC Ergebnisse jeweils auf [2], 
[1], [0]. Nur hier nicht. Hier landen alle 3 Ergebnisse in [2], die 
letzte Zuweisung gewinnt.

von Antny (Gast)


Lesenswert?

Hallo danke für die schnelle Antwort, joa das ist "richtig" so weil ich 
den Code gerade komplett durchgeplügt habe um das System zu verstehen 
was da schief geht, allerdings bisher erfolglos.

Hier nocheinmal der komplette Code, TempCh1 usw. sind defines, später 
wenn es irgendwann mal laufen sollte... ist die switch/case- Struktur 
dazu gedacht periodisch die Kanäle durchzuscannen und die Structs zu 
aktualisieren.
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include "uart.h"
4
#include "config.h"
5
#include "twi.h"
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
#define Startbit 2
9
#define Single_Ended 1
10
11
struct KanalMesswerte {
12
   uint8_t Temperatur[3];
13
   uint8_t Strom[3];
14
   uint8_t Spannung[3];
15
   uint8_t PWM_Fan;
16
   uint16_t temp_old;
17
   int16_t t_delta_sum;
18
}Ch1={"","","",PWM_Start,0},Ch2={"","","",PWM_Start,0};
19
20
uint8_t nextChannel=TempCh1; //Erster Kanal, welcher gelesen wird
21
volatile uint8_t ADCprescaler=0;
22
23
24
//Schreiben und konfigurieren des ADC's
25
void ADC_Messung ()
26
{
27
  if (ADCprescaler >6)
28
  {
29
    PORT_CS_ADC_STEU &= ~( 1 << PIN_CS_ADC_STEU );
30
    SPCR =  (1<<SPE)  |  //SPI- Enable
31
        (1<<MSTR)  |
32
        (1<<SPR1);  //Set Master
33
34
    _delay_ms(10);
35
36
    switch (nextChannel)
37
    {
38
      case TempCh1:  read_adc(&(Ch1.Temperatur[2]));
39
              Ch1.Temperatur[2]&=0x0F;
40
              read_adc(&(Ch1.Temperatur[1]));
41
              read_adc(&(Ch1.Temperatur[0]));
42
              nextChannel=TempCh1;
43
              break;
44
//      case CurrCh1:  read_adc(&Ch1.Strom[2]);
45
//              Ch1.Strom[2]&=0x0F;
46
//              read_adc(&Ch1.Strom[1]);
47
//              read_adc(&Ch1.Strom[0]);
48
//              nextChannel=ULast1;
49
//              break;
50
//      case ULast1:  read_adc(&Ch1.Spannung[2]);
51
//              Ch1.Spannung[2]&=0x0F;
52
//              read_adc(&Ch1.Spannung[2]);
53
//              read_adc(&Ch1.Spannung[2]);
54
//              nextChannel=TempCh1;
55
//              break;
56
      /*case TempCh2:  Ch2.Temperatur[2]=0x0F & read_adc();
57
              Ch2.Temperatur[1]=read_adc();
58
              Ch2.Temperatur[0]=read_adc();
59
              nextChannel=CurrCh2;
60
              break;
61
      case CurrCh2:  Ch2.Strom[2]=0x0F & read_adc();
62
              Ch2.Strom[1]=read_adc();
63
              Ch2.Strom[0]=read_adc();
64
              nextChannel=ULast2;
65
              break;
66
      case ULast2:  Ch2.Spannung[2]=0x0F & read_adc();
67
              Ch2.Spannung[1]=read_adc();
68
              Ch2.Spannung[0]=read_adc();
69
              nextChannel=TempCh1;
70
              //luefterregelung(&msb,&Ch1.PWM_Fan,1,&Ch1.temp_old,&Ch1.t_delta_sum);
71
              break;*/
72
    }
73
    PORT_CS_ADC_STEU |=  ( 1 << PIN_CS_ADC_STEU );
74
    _delay_ms(1);
75
    SPDR=nextChannel;
76
    while ( ! ( SPSR&(1<<SPIF) ) );
77
    SPDR=nextChannel;
78
    while ( ! ( SPSR&(1<<SPIF) ) );
79
80
    uint16_t msb=Ch1.Temperatur[2]<<11;
81
    msb|=Ch1.Temperatur[1]<<3;
82
    msb|=Ch1.Temperatur[0]>>3;
83
    ADCprescaler=0;
84
    uart_sendc('A');
85
    uart_sendc(&Ch1.Temperatur[2]);
86
    uart_sendc(&Ch1.Temperatur[1]);
87
    uart_sendc(&Ch1.Temperatur[0]);
88
//    uart_sendc('B');
89
//    uart_sendc(&Ch1.Spannung[2]);
90
//    uart_sendc(&Ch1.Spannung[1]);
91
//    uart_sendc(&Ch1.Spannung[0]);
92
93
    //Einstellen des mächsten Kanals
94
95
96
97
  }
98
}
99
100
void read_adc (uint8_t *value)
101
{
102
  PORT_CS_ADC_STEU &= ~( 1 << PIN_CS_ADC_STEU );
103
  SPCR =  (1<<SPE)  |  //SPI- Enable
104
      (1<<MSTR)  |
105
      (1<<SPR1);  //Set Master
106
  SPDR=0b10101010;
107
  while ( ! ( SPSR&(1<<SPIF) ) );
108
  *value=SPDR;
109
}
110
111
112
113
114
115
//Interrupt alle 37 ms
116
ISR(TIMER0_OVF_vect)
117
{
118
  TCNT0 = 0;
119
  ADCprescaler++;
120
121
}

von Antny (Gast)


Angehängte Dateien:

Lesenswert?

Und hier noch ein Foto von dem was ausgegeben wird, wie es weiter geht 
kann man unten sehen ich habe mal versucht das mit Linien zu 
verdeutlichen.

von Karl H. (kbuchegg)


Lesenswert?

Ich kann mir nicht vorstellen, dass dich hier

    uart_sendc(&Ch1.Temperatur[2]);


das Low-Byte der Adresse interessiert, an der Ch1.Temperatur[2] 
gespeichert ist.

Hat dein Compiler da gar nichts dazu gesagt, dass die Funktion einen 
char haben möchte und du ihm aber einen unsigned char* (mit der Betonung 
auf *) anbietest?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Antny schrieb:
1
struct KanalMesswerte {
2
    uint8_t Temperatur[3];
3
    uint8_t Strom[3];
4
    uint8_t Spannung[3];
5
    uint8_t PWM_Fan;
6
    uint16_t temp_old;
7
    int16_t t_delta_sum;
8
}Ch1={"","","",PWM_Start,0},Ch2={"","","",PWM_Start,0};

Was sollen denn dies Initialiser??? Du initialisierst ein uint8-Array 
mit char*?

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:
> Antny schrieb:
>
>
1
> struct KanalMesswerte {
2
>     uint8_t Temperatur[3];
3
>     uint8_t Strom[3];
4
>     uint8_t Spannung[3];
5
>     uint8_t PWM_Fan;
6
>     uint16_t temp_old;
7
>     int16_t t_delta_sum;
8
> }Ch1={"","","",PWM_Start,0},Ch2={"","","",PWM_Start,0};
9
>
>
> Was sollen denn dies Initialiser??? Du initialisierst ein uint8-Array
> mit char*?

Ist zwar ein wenig seltsam, letzten Endes werden dadurch nur 
Temperatur[0], Strom[0] und Spannung[0] mit '\0' initialisiert, die 
anderen haben keine definierten Werte.

ist auch nichts anders als

   char Dummy[20] = "Hallo World";

von Mark B. (markbrandis)


Lesenswert?

Vielleicht hab ich mich verzählt und brauche eine neue Brille, aber ich 
sehe da sechs Member in der struct und nur fünf davon werden 
initialisiert. Wenn schon denn schon.

von Antny (Gast)


Lesenswert?

@Mark uups richtig, der Ordnung halber...
@Karl- Heinz mensch auf dich ist immer noch Verlass, bei meinen ersten 
Gehversuchen mit dem µP hast du mir schon super das mit Bittoggeln mit 
Hilfe von und/ oder erklärt, und jetzt wieder den Fehler gefunden 
dankeschön :)

von Andreas F. (aferber)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ist zwar ein wenig seltsam, letzten Endes werden dadurch nur
> Temperatur[0], Strom[0] und Spannung[0] mit '\0' initialisiert, die
> anderen haben keine definierten Werte.

Doch, die Variablen haben static storage duration, deshalb werden alle 
nicht explizit aufgeführten Elemente implizit mit 0 initialisiert.

Andreas

von Andreas F. (aferber)


Lesenswert?

Andreas Ferber schrieb:
> Doch, die Variablen haben static storage duration, deshalb werden alle
> nicht explizit aufgeführten Elemente implizit mit 0 initialisiert.

Bzw., um mich selbst zu ergänzen: selbst bei automatic storage duration 
werden bei teilweiser Initialisierung (sei es wegen weniger Elementen in 
einer Initializer-Liste oder eben auch einem Stringliteral) die 
restlichen Elemente implizit mit 0 initialisiert (bzw. NULL-Pointer bei 
Pointertypen). Siehe Absatz 21 in Abschnitt 6.7.8 im C99-Standard.

Andreas

von Andreas F. (aferber)


Lesenswert?

Ingrid^2: die Initialisierung des uint8_t-Arrays mit einem Stringliteral 
ist allerdings eigentlich nicht zulässig, nur "array of character 
type" darf so initialisiert werden, und "character type" sind 
ausschliesslich "char", "signed char" und "unsigned char".

Vermutlich wird man aber den Bastard C-Compiler From Hell suchen müssen, 
um einen zu finden, bei dem der Unterschied in diesem Fall wirklich 
relevant wird.

Andreas

von Florian L. (muut) Benutzerseite


Lesenswert?

Andreas Ferber schrieb:
> ist allerdings eigentlich nicht zulässig, nur "array of character
> type" darf so initialisiert werden, und "character type" sind
> ausschliesslich "char", "signed char" und "unsigned char".

wird daran liegen das uint8_t eigentlich ein unsigned char ist. 
(typedef)

Über den Sinn und Unsinn, einen Zahlenwert mit dem NUL-Symbol zu 
initialisieren, kann man sich streiten :-D

von Karl H. (kbuchegg)


Lesenswert?

Andreas Ferber schrieb:

> Doch, die Variablen haben static storage duration, deshalb werden alle
> nicht explizit aufgeführten Elemente implizit mit 0 initialisiert.

Ah ja. Du hast natürlich recht.
Darauf hab ich jetzt nicht geachtet.

Ich geh normalerweise nach dem Grundsatz vor:
Wenn ich initialisiere, dann alles.

Das ist mir nämlich zu mühsam, bei einer Strukturänderung im Nachhinein 
wieder abzählen zu müssen, was ich initialisiert habe, was der Compiler 
für mich macht und was keine Initialisierung bekommt.

von Karl H. (kbuchegg)


Lesenswert?

Florian Löffler schrieb:

> Über den Sinn und Unsinn, einen Zahlenwert mit dem NUL-Symbol zu
> initialisieren, kann man sich streiten :-D

Ich denke das Problem wird gewesen sein, dass die korrekte Syntax nicht 
bekannt war
1
struct KanalMesswerte {
2
   uint8_t Temperatur[3];
3
   uint8_t Strom[3];
4
   uint8_t Spannung[3];
5
   uint8_t PWM_Fan;
6
   uint16_t temp_old;
7
   int16_t t_delta_sum;
8
}
9
10
 Ch1 = { { 0, 0, 0 },
11
         { 0, 0, 0 },
12
         { 0, 0, 0 },
13
         PWM_Start,
14
         0,
15
         0
16
       },
17
18
 Ch2 = { { 0, 0, 0 },
19
         { 0, 0, 0 },
20
         { 0, 0, 0 },
21
         PWM_Start,
22
         0,
23
         0
24
       };

Das ich von solchen 'all in one line' Rundumschlägen nicht viel halte, 
genausowenig von diesem 'möglichst alles in eine Deklaration quetschen 
und am besten noch ein typedef davor' Kompaktschreibweisen, sollte 
diejenigen die meinen Stil mittlerweile kennen, nicht weiter wundern.

von Andreas F. (aferber)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ich geh normalerweise nach dem Grundsatz vor:
> Wenn ich initialisiere, dann alles.
>
> Das ist mir nämlich zu mühsam, bei einer Strukturänderung im Nachhinein
> wieder abzählen zu müssen, was ich initialisiert habe,

In aller Regel benutze ich bei struct-Initializern inzwischen 
grundsätzlich Designatoren, damit die Initialisierung komplett 
unabhängig von der Abfolge der struct-Felder wird. Erspart schonmal ein 
paar Fehlerquellen.

> was der Compiler
> für mich macht und was keine Initialisierung bekommt.

Wie gesagt, selbst bei automatischen Variablen, sobald auch nur ein 
einziges Feld initialisiert wird, wird der gesamte Rest (rekursiv) in 
jedem Fall auf 0 initialisiert, exakt wie es bei statischen Objekten der 
Fall wäre. Oder anders: ein "teilweise" initialisiertes Aggregate gibt 
es in C nur im Zusammenhang mit dynamischer Speicherverwaltung, in allen 
anderen Fällen wird entweder ganz oder garnicht initialisiert.

Andreas

von Andreas F. (aferber)


Lesenswert?

Beispiel wär vielleicht auch nicht schlecht. Die vorliegende struct 
würde ich persönlich ungefähr so initialisieren:
1
struct KanaMesswerte {
2
    [...]
3
};
4
5
struct KanalMesswerte Ch1 = { .PWM_Fan = PWM_Start },
6
                      Ch2 = { .PWM_Fan = PWM_Start };

Andreas

von Antny (Gast)


Lesenswert?

Hey, das finde ich gut, dass ihr mir gleich noch gezeigt habt wie es 
besser geht, in der Tat ich wußte einfach nicht wie man sie anders 
initialisieren kann.

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.