Forum: Mikrocontroller und Digitale Elektronik high & low Byte zusammensetzen


von new (Gast)


Lesenswert?

Hallo,

ich versuche gerade 2 Bytes die ich über I2C gesendet bekomme zusammen 
zusetzen und zwar in der Rheinfolge erst High Byte dann Low Byte.


ist das logisch korrekt ?
1
  uint16_t Akkuspannung;
2
  uint8_t Akkuspannung_Wert1_low_byte, Akkuspannung_Wert2_high_byte;
3
4
    
5
  smb_start_wait(AdresseSlave_1+SMB_WRITE);
6
  smb_write (0x5A); //0x09
7
  smb_rep_start(AdresseSlave_1+SMB_READ);
8
  Akkuspannung_Wert1_low_byte = smb_readAck();
9
  Akkuspannung_Wert2_high_byte = smb_readNak();
10
  smb_stop();
11
12
  Akkuspannung = Akkuspannung_Wert2_high_byte * 256;
13
  Akkuspannung = Akkuspannung + Akkuspannung_Wert1_low_byte;  
14
    
15
16
  while(Akkuspannung >= 8320)
17
  {
18
    //__enable_interrupt();
19
    PORTB &= ~ ( 1 << PB1 | 1 << PB2 );
20
    __disable_interrupt();
21
    PORTB |=  (1 << PB2);
22
    //PORTC &= ~  (1 << PC0 | 1 << PC4 | 1 << PC1 | 1 << PC5 | 1 << PC3 | 1 << PC2);
23
    
24
  }

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

new schrieb:
> ist das logisch korrekt ?

ja aber recht umständlich. üblich schreibt man einfach



Akkuspannung = (Akkuspannung_Wert2_high_byte << 8) | 
Akkuspannung_Wert1_low_byte;

von Karl H. (kbuchegg)


Lesenswert?

Du kannst es aber auch so schreiben
1
  Akkuspannung = Akkuspannung_Wert2_high_byte * 256 + Akkuspannung_Wert1_low_byte;

zum einen ist das ja nicht BASCOM, wo man jede kompliziertere Berechnung 
in mehrere Teile aufteilen muss, zum anderen ist der COmpiler schon so 
intelligent, dass er weiß, das eine Multiplikation mit 256 ganz einfach 
durch Verschieben bzw. entsprechende Bytezuweisungen erfolgen kann. Es 
gibt da keinen Grund, schlauer als der Compiler sein zu wollen - man 
benutzt einfach die Schreibweise, die die Absicht am besten ausdrückt 
und der Compiler kümmert sich darum, wie das effizient zu implementieren 
ist.

von Rolf Magnus (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> zum anderen ist der COmpiler schon so intelligent, dass er weiß, das eine
> Multiplikation mit 256 ganz einfach durch Verschieben bzw. entsprechende
> Bytezuweisungen erfolgen kann.

Man muß aber auch nicht unbedingt überall eine Multiplikation 
hinschreiben, nur um dem Compiler die Gelegenheit zu geben, besonders 
schlau zu sein.

> Es gibt da keinen Grund, schlauer als der Compiler sein zu wollen - man
> benutzt einfach die Schreibweise, die die Absicht am besten ausdrückt
> und der Compiler kümmert sich darum, wie das effizient zu implementieren
> ist.

Ich finde aber, daß gerade dort der Bit-Schiebe-Operator besser 
ausdrückt, was man machen will. Es geht ja hier gerade nicht darum, eine 
Zahl mit 256 zu multiplizieren, sondern darum, das erste Byte in die 
oberen 8 Bit rüberzuschieben.

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:

> Ich finde aber, daß gerade dort der Bit-Schiebe-Operator besser
> ausdrückt, was man machen will. Es geht ja hier gerade nicht darum, eine
> Zahl mit 256 zu multiplizieren, sondern darum, das erste Byte in die
> oberen 8 Bit rüberzuschieben.


Ja, du hast natürlich recht. An dieser Stelle wäre Schieben für mich 
auch 'natürlicher'.

Mir ging es eher darum, dass das Original vom TO
1
  Akkuspannung = Akkuspannung_Wert2_high_byte * 256;
2
  Akkuspannung = Akkuspannung + Akkuspannung_Wert1_low_byte;

in Bezug auf dieses Thema deshalb nicht falsch ist. Wenn für ihn die 
Multiplikation natürlicher ist, dann ist das ok und keineswegs ein Grund 
die Hände über dem Kopf zusammenzuschlagen und 'Ineffizenz!' zu rufen.

Hätte das vielleicht besser ausdrücken sollen.

Ich würde ja auch die ganze Operation sowieso erst mal in eine Funktion 
kapseln, deren Aufgabe es ist einen 16 Bit Wert auszulesen und die dann 
benutzen. Aber das ist eine andere Geschichte. Genauso wie da natürlich 
in der while Schleife ein logischer Fehler steckt (denn wie soll sich 
denn der Wert in der Schleife verändern. ISR wäre noch möglich, aber 
dann müsste man unter Interruptsperre die Variable auslesen).

: Bearbeitet durch User
von new (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:

>
> Ich würde ja auch die ganze Operation sowieso erst mal in eine Funktion
> kapseln, deren Aufgabe es ist einen 16 Bit Wert auszulesen und die dann
> benutzen. Aber das ist eine andere Geschichte. Genauso wie da natürlich
> in der while Schleife ein logischer Fehler steckt (denn wie soll sich
> denn der Wert in der Schleife verändern. ISR wäre noch möglich, aber
> dann müsste man unter Interruptsperre die Variable auslesen).


was meinst du mit in der Schleife ist ein logischer Fehler kannst du das 
bitte erörtern?

von Rolf Magnus (Gast)


Lesenswert?

new schrieb:
> was meinst du mit in der Schleife ist ein logischer Fehler kannst du das
> bitte erörtern?

Hat er doch:

new schrieb:
> wie soll sich denn der Wert in der Schleife verändern. ISR wäre noch
> möglich, aber dann müsste man unter Interruptsperre die Variable auslesen

Du fragst in der Schleife bei jedem Durchlauf die Variable 
"Akkuspannung" ab. Da du sie aber innerhalb der Schleife nie 
beschreibst, wird sich ihr Wert auch nie mehr ändern.

von Rolf Magnus (Gast)


Lesenswert?

Rolf Magnus schrieb:
> new schrieb:
>> wie soll sich denn der Wert in der Schleife verändern. ISR wäre noch
>> möglich, aber dann müsste man unter Interruptsperre die Variable auslesen

Ups. Das war natürlich nicht "new", der das geschrieben hat, sondern 
Karl Heinz.

von new (Gast)


Lesenswert?

also muss ich dann folgendes machen?


uint16_t Akkuspannung;
  uint8_t Akkuspannung_Wert1_low_byte, Akkuspannung_Wert2_high_byte;


  smb_start_wait(AdresseSlave_1+SMB_WRITE);
  smb_write (0x5A); //0x09
  smb_rep_start(AdresseSlave_1+SMB_READ);
  Akkuspannung_Wert1_low_byte = smb_readAck();
  Akkuspannung_Wert2_high_byte = smb_readNak();
  smb_stop();

  Akkuspannung = Akkuspannung_Wert2_high_byte * 256;
  Akkuspannung = Akkuspannung + Akkuspannung_Wert1_low_byte;


  while(Akkuspannung >= 8320)
  {

        smb_start_wait(AdresseSlave_1+SMB_WRITE);
  smb_write (0x5A); //0x09
  smb_rep_start(AdresseSlave_1+SMB_READ);
  Akkuspannung_Wert1_low_byte = smb_readAck();
  Akkuspannung_Wert2_high_byte = smb_readNak();
  smb_stop();

  Akkuspannung = Akkuspannung_Wert2_high_byte * 256;
  Akkuspannung = Akkuspannung + Akkuspannung_Wert1_low_byte;


    //__enable_interrupt();
    PORTB &= ~ ( 1 << PB1 | 1 << PB2 );
    __disable_interrupt();
    PORTB |=  (1 << PB2);
    //PORTC &= ~  (1 << PC0 | 1 << PC4 | 1 << PC1 | 1 << PC5 | 1 << PC3 
| 1 << PC2);

  }

von Karl H. (kbuchegg)


Lesenswert?

new schrieb:
> also muss ich dann folgendes machen?
>

Oh. Mann.
Warum lernst du nicht einfach mal ein bischen Grundlagen in C.
Das hat doch keinen Sinn, jedes Codestück im Editor auf Biegen und 
Brehcen zu duplizieren
1
uint16_t ValueFrom( uint8_t Address )
2
{
3
  uint16_t value;
4
  uint8_t  lowByte, HighByte;
5
6
  smb_start_wait(AdresseSlave_1+SMB_WRITE);
7
  smb_write (Address);
8
  smb_rep_start(AdresseSlave_1+SMB_READ);
9
10
  lowByte = smb_readAck();
11
  highByte = smb_readNak();
12
  smb_stop();
13
14
  value = ( highByte << 8 ) | lowByte;
15
16
  return value;
17
}

damit hast du erst mal eine Funktion, die dir den ganzen Teil 'Hole 
einen 16 Bit Wert aus einem bestimmten Register abnimmt, so dass du das 
nicht jedesmal immer wieder neu ausformulieren brauchst.

Und damit schreibt sich dann der Rest unter Verwendung dieser Funktion 
als
1
    Akkuspannung = ValueFrom( 0x5A );
2
3
    while(Akkuspannung >= 8320)
4
    {
5
      //__enable_interrupt();
6
      PORTB &= ~ ( 1 << PB1 | 1 << PB2 );
7
      __disable_interrupt();
8
      PORTB |=  (1 << PB2);
9
      //PORTC &= ~  (1 << PC0 | 1 << PC4 | 1 << PC1 | 1 << PC5 | 1 << PC3  | 1 << PC2);
10
 
11
      Akkuspannung = ValueFrom( 0x5A );
12
    }

siehst du, um wieviel einfacher und verständlicher der ganze Code durch 
die Funktion plötzlich geworden ist?
Und wenn man dann auch noch die 'magische Konstante' 0x5A mittels 
#define mit einem sprechenden Namen ersetzt
1
#define AKKU_VOLTAGE_REGISTER 0x5A
2
3
....
4
5
    Akkuspannung = ValueFrom( AKKU_VOLTAGE_REGISTER );
6
7
    while(Akkuspannung >= 8320)
8
    {
9
      //__enable_interrupt();
10
      PORTB &= ~ ( 1 << PB1 | 1 << PB2 );
11
      __disable_interrupt();
12
      PORTB |=  (1 << PB2);
13
      //PORTC &= ~  (1 << PC0 | 1 << PC4 | 1 << PC1 | 1 << PC5 | 1 << PC3  | 1 << PC2);
14
 
15
      Akkuspannung = ValueFrom( AKKU_VOLTAGE_REGISTER );
16
    }

dann wird das ganze schon immer mehr zu einem fast natürlichsprachigen 
Text, bei dem ein paar Zwischenwörter fehlen.

Lern ordentlich programmieren. Es lohnt sich auf lange Sicht!
Oder bist du bereits mit dem Auto rumgefahren, als du ausser dem 
Blinkerhebel noch keine anderen Kontrollen in deinem Auto gekannt hast? 
Nicht? Na also!

: Bearbeitet durch User
von new (Gast)


Lesenswert?

Vielen Dank das ist sehr schön erklärt, bis auf die spöttischen 
Bemerkungen ;-).


Macht natürlich mehr Sinn mit eine Funktion zu arbeiten mit 
Rückgabewert.

Allerdings bekomme ich einen Konflikt beim compilieren:
"conflictings types for  ValueForm"

Karl Heinz Buchegger schrieb:
> uint16_t ValueFrom( uint8_t Address )
> {
>   uint16_t value;
>   uint8_t  lowByte, HighByte;
>
>   smb_start_wait(AdresseSlave_1+SMB_WRITE);
>   smb_write (Address);
>   smb_rep_start(AdresseSlave_1+SMB_READ);
>
>   lowByte = smb_readAck();
>   highByte = smb_readNak();
>   smb_stop();
>
>   value = ( highByte << 8 ) | lowByte;
>
>   return value;
> }


Wieso steht bei smb_write (Adresse)? Wo ist denn Adresse als 0x5A 
definiert oder wird es hier


Akkuspannung = ValueFrom( 0x5A );

    while(Akkuspannung >= 8320)
    {
      //__enable_interrupt();
      PORTB &= ~ ( 1 << PB1 | 1 << PB2 );
      __disable_interrupt();
      PORTB |=  (1 << PB2);
      //PORTC &= ~  (1 << PC0 | 1 << PC4 | 1 << PC1 | 1 << PC5 | 1 << 
PC3  | 1 << PC2);

      Akkuspannung = ValueFrom( 0x5A );
    }


übergeben?

von Karl H. (kbuchegg)


Lesenswert?

new schrieb:
> Vielen Dank das ist sehr schön erklärt, bis auf die spöttischen
> Bemerkungen ;-).

Die sind in all den Jahren entstanden, in denen ich gemerkt habe, dass 
immer mehr Leute immer weniger Basiswissen haben und trotzdem meinen, 
ein Projekt stemmen zu können. Wenn ich keine Ahnung von klempnern habe, 
wie kommt man dann auf die Idee, man könne in seinem Haus die Heizung in 
Eigenregie aufbauen?

Eben. Bei solchen Dingen sieht das jeder ein. Nur seltsamerweise beim 
Programmieren nicht. Da glaubt jeder, das geht so in ein paar Stunden. 3 
Schlüsselwörter genügen und dann passt das schon.


> Allerdings bekomme ich einen Konflikt beim compilieren:
> "conflictings types for  ValueForm"

Da ich den Rest deines Programms nicht kenne, bzw. wie du die Codestücke 
eingebaut hast, kann ich dazu nicht viel sagen. Aber ich schätze mal, 
dass du die Funktion unterhalb von main() angeordnet hast und keinen 
Protoyp für die Funktion gemacht hast.

> Wieso steht bei smb_write (Adresse)? Wo ist denn Adresse als 0x5A
> definiert oder wird es hier


Siehst du. Genau das meine ich mit fehlendem Basiswissen.
Schau in deinem bevorzugtem C-Lehrbuch unter "Funktionen" bzw. 
"Funktionsargumente" nach. Das entsprechende Kapitel sollte sich 
irgendwo im ersten Drittel des Buches finden lassen.

: Bearbeitet durch User
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.