SPI 3 Bytes einlesen

Janiiix3

Aktives Mitglied
28. Sep. 2013
1.333
10
38
Hannover
Sprachen
  1. ANSI C
  2. C#
Hallo,

wie lese ich genau mit einem MEGA32U4 3 Bytes ein?
Habe folgendes Versucht.:

main


CodeBox C
int main(void)
{
   
   DDRD |= (1<<PD5);
     
   lcd_init(LCD_DISP_ON);
   spi_master_init(64,2);
   
  while (1)
  {
     
     lcd_gotoxy(0,0);     
     int8_t tmp = ADE7758_readTEMP();
     sprintf(Buffer,"T:%d", tmp);
     lcd_puts(Buffer);
     
     _delay_ms(10);
     
     spi_enable_chip();
     spi_disable_chip();
     
     spi_master_transmit(REG_BVRMS);
     spi_master_transmit(0x00);
     
     int8_t byte_one = (int8_t)spi_receive();

     sprintf(Buffer," 1:%d", byte_one);
     lcd_puts(Buffer);
     
     spi_master_transmit(0x00);
     int8_t byte_two = (int8_t)spi_receive();
     sprintf(Buffer," 2:%d", byte_two);
     lcd_puts(Buffer);

     spi_master_transmit(0x00);
     int8_t byte_three = spi_receive();
     sprintf(Buffer," 3:%d", byte_three);
     lcd_puts(Buffer);
     
     spi_enable_chip();
     
           
     unsigned long messwert = (unsigned long)16<<byte_one | (unsigned long)8 << byte_two |(signed long)byte_one;       
           
     long voltage =   ((long)messwert / FULL_SCALE_VRMS) * RMS_SPANNUNG_MAX;   
           
     lcd_gotoxy(0,1);
     sprintf(Buffer,"L1: %lu", voltage);       
     lcd_puts(Buffer);       
     _delay_ms(800);   
                 
  }
}


spi


CodeBox C
void spi_master_transmit(uint8_t cData)
{
   /* start transmission */
   SPDR = cData;
   
   /* wait for transmission complete */
   while(!(SPSR & (1<<SPIF)));   
}

uint8_t spi_receive(void)
{   
   /* Wait for reception complete */
   //while(!(SPSR & (1<<SPIF)));

   /* return data register */
   return SPDR;   
}




CodeBox C
void spi_master_init(uint8_t prescaler, uint8_t clock_option)
{   
   /* ONLY FOR MEGA32! */
   #if defined(__AVR_ATmega32__)
   {
     /* set MOSI and SCK output, all others input */
     MOSI_DDR |= (1<<MOSI_BIT);
     SCK_DDR    |=   (1<<SCK_BIT);
     SS_DDR    |= (1<<SS_BIT);
   
     /* enable SPI, Master */
     SPCR |= (1<<SPE) | (1<<MSTR);
     
     /* clear the bit´s (for multi init) */
     SPCR &= ~((1<<SPI2X) | (1<<SPR0) | (1<<SPR1)); // fclk/4
   
     /* config SPI Bus Speed fclk/prescaler */
     switch (prescaler)
     {
       case 2:  {SPCR |=  (1<<SPI2X);                };break;
       case 8:  {SPCR |=  ((1<<SPI2X) | (1<<SPR0));        };break;
       case 32:  {SPCR |=  ((1<<SPI2X) | (1<<SPR1));        };break;
       case 64:  {SPCR |=  ((1<<SPI2X) | (1<<SPR1) | (1<<SPR0));};break;
       default:  {SPCR |=  (1<<SPI2X);                };break;
     }
   }
   #endif   
   
   /* ONLY FOR MEGA32U4! */
   #if defined (__AVR_ATmega32U4__)
   {
       /* set MOSI and SCK output, all others input */
       MOSI_DDR   |= (1<<MOSI_BIT);
       SCK_DDR     |=   (1<<SCK_BIT);
       SS_DDR     |= (1<<SS_BIT);    // software slave select signal
       SS_HA_DDR   |= (1<<SS_HA_BIT); // hardware slave select signal
       
       /* enable SPI, Master */
       SPCR |= ((1<<SPE) | (1<<MSTR));       
       
       /* config "Clock Polarity and "Clock Phase" */
       switch(clock_option)
       {
         case 0 : {SPCR &= ~((1<<CPOL) | (1<<CPHA)); }break; // mode 1
         case 1 : {SPCR |=  (1<<CPHA);         }break; // mode 2
         case 2 : {SPCR |=  (1<<CPOL);         }break; // mode 3
         case 3 : {SPCR |=  ((1<<CPOL) | (1<<CPHA));   }break; // mode 4
       }
       
       /* config SPI Bus Speed fclk/prescaler */
       switch (prescaler)
       {
         case 2:  {SPSR |= (1<<SPI2X);                  }break; // prescaler 2
         case 8:  {SPSR |= (1<<SPI2X); SPCR |= (1<<SPR0);        }break; // prescaler 8
         case 32:  {SPSR |= (1<<SPI2X); SPCR |= (1<<SPR1);        }break; // prescaler 32
         case 64:  {SPSR |= (1<<SPI2X); SPCR |= (1<<SPR1) | (1<<SPR0); }break; // prescaler 64
         default:  {SPSR |= (1<<SPI2X);                  }break; // default = 2
       }
   }
   #endif
}


Was genau mache ich falsch?
1 Byte empfangen und korrekt auswerten klappt.
 
Kenne mich mit C nicht aus, aber es scheint als wenn Du nach dem Senden (und somit vor dem Empfang) auf das SPIF warten willst. Du setzt es aber nicht wieder zurück, folglich ist es nach dem ersten immer gesetzt, Du liest zu früh...
 
Hallo,

soweit ich weiß wird es nach dem lesen von selbst wieder zurück gesetzt.
 
Stimmt, erst das Statusregister mit gesetztem SPIF lesen, das nächste lesen des SPDR löscht das SPIF...

sollte passen...
 
Wenn ich jetzt das dummy Byte sende... Sprich 0x00 liegt auf MOSI ne 0 und es wird ein Takt generiert sehe ich das richtig? So sollte ich doch eigentlich meine 24 Bit richtig einlesen können?
 
Vill. Rechne ich ja auch was falsch.

Hier sind meine Empfangenen Bytes (signed int8_t)

Byte1 = 13
Byte2 = -30
Byte3 = 50 (schwangt ziemlich doll)

eingestellt habe ich den Stelltrafo auf ~200VAC

Was würde jetzt raus kommen wenn ich die 3 Bytes zusammen fasse?

Hätte jetzt folgendes Ergebniss:

000011011110001000110010

Könnte das die Formel sein? Ich bin ziemlich unsicher...




CodeBox C
#define FULL_SCALE_IRMS       0x182A7F   // 0x1D51C0 --> aprox. full-scale value of the current rms register for 50Hz, 5A and Integrattor off (Chip Manual Reference Page 29)
#define RMS_SPANNUNG_MAX     364        // 364.513   --> Maximale Mess-RMS-Spannunng = (0,5V / (R22 / (R14+R17+R22))) / SQRT(2); +-0,5V is the specified full-scale analog input signal
#define FULL_SCALE_VRMS       0x198F24   // 0x199B82 --> aprox. full-scale value of the Voltage RMS register for 50Hz, 364,5V                  (Chip Manual Reference Page 29)
#define WIRKLEISTUNG_MAX     1820       // RMS_STROM_MAX * RMS_SPANNUNG_MAX bei ohmsche Last = 5 * 364
#define FULL_SCALE_WATT       0xD93DA     // full-scale value  of the Apparent Power register




CodeBox C
VOLTAGE = ((float)Messwert.RMS / FULL_SCALE_VRMS) * RMS_SPANNUNG_MAX;
 
Zuletzt bearbeitet:
Wenn ich jetzt das dummy Byte sende... Sprich 0x00 liegt auf MOSI ne 0 und es wird ein Takt generiert sehe ich das richtig?
SPDR ist eigentlich nicht ein Register, wird SPDR gelesen, wird der Inhalt aus dem SPI-Read-Buffer gelesen (wurde ein komplettes Byte über das SPI-Schieberegister empfangen, wird es in den Lesepuffer kopiert (und SPIF gesetzt). Es kann sofort ein weiteres Byte eingetaktet werden.
Wird SPDR geschrieben, dann landet das zu schreibende Byte direkt im Schieberegister, und wird ausgetaktet (durch den Master).
Also Antwort auf die Frage: Ja, wenn der Controller Master ist - Nein, wenn er Slave ist. Dann wird das Schieberegister direkt durch den externen Takt (SCK) gesteuert.

Wenn Du unterschiedliche Bytes empfängst, paßt die Empfangsroutine. Zur Rechnerei kann ich jetzt nichts sagen...
 
Okay. Dann wird das soweit schon mal passen. Vielleicht mag mir @Dirk ja noch mal helfen.
 
Ich gehe davon aus, dass SPI in Ordnung ist, LotadaC hatte hier ja schon geschaut.

Dein Code aus einem der ersten Beiträge:


CodeBox C
unsigned long messwert = (unsigned long)16<<byte_one | (unsigned long)8 << byte_two |(signed long)byte_one; 

Ich finde in dieser Zeile vier Fehler:
  • (unsigned long)16 oder (unsigned long)8 brauchst du nicht
  • du castest byte_one als "signed long", das möchtest du sicher nicht
  • du shiftest nicht die Ihnalte der Variablen, sondern die Konstanten
  • wo ist dein byte_tree?

das sollte eher so aussehen (ich schreibe es mal mit uint32_t):


CodeBox C
uint32_t messwert = (uint32_t)(byte_three<<16) | (uint32_t)(byte_two<<8) | (uint32_t)byte_one;


Schau erst mal danach, bevor du dich mit der Gleichung befasst.

Dirk :ciao:
 
Hallo Dirk,

unsigned long 8
unsigned long 16..?

Ich kenne nur unsigned long oder long.

Und wie meinst du das, dass ich die konstanten shiften würde? Das sind doch keine konstanten?

Und kann ich überhaupt mit sprintf uint32 variablen umwandeln?
 
Du castest die Kontante 16 oder die Konstante 8 mit "unsigned long". Du musst deine Byte Variable (uint8_t) auf 32Bit casten, bzw. das Ergebnis, damit beim Shiften keine Bits verloren gehen.

Die Sache mit den Konstanten shiften:

Deine Version:
Konstante<<Variable
8<<byte_two
Du shiftest hier die Konstante um soviel Bitstellen nach links wie der Inhalt von Variable ist.

So sollte es sein:
Variable<<Konstante
byte_two<<8
"byte_two" wird um 8 Bit nach links geshiftet

Schau dir einfach nochmal meine Zeile im Beitrag zuvor an und versuche zu verstehen, was da passiert.
 
Ich kann das nachvollziehen nur ich war mir nicht sicher.
8<<byte1 (byte1= 10) jetzt würde die 8 10 stellen nach links geschoben oder?

Wie ist das mit uint32 und sprintf, klappt das?
 
Wenn du uint32_t ausgeben möchtest, probiere es so:



CodeBox C
#include <inttypes.h>
// ...

sprintf(buffer, "%" PRIu32, messwert);


buffer ist pointer zum char Array, das muss zuvor definiert sein und alle Zeichen der Ziffer aufnehmen können, also ausreichend großes Array verwenden.
 
  • Like
Reaktionen: Janiiix3
Danke Dirk.
Wo kann ich das mit dem sprintf nachlesen? Habe es nirgends gut erklärt gefunden. Hast du eine Seite? Mit PRIu32
 
@Dirk Du bist mal wieder die Rettung gewesen. Es lag wirklich nur an dem schieben und dem casting.

Mit sprintf bekomme ich leider nur ein "?" angezeigt. Habe jetzt dtostr genommen und siehe da, klappt einwandfrei.

Besten dank nochmal!

:):):)
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)