【问题标题】:Unreliable SPI byte array transfer from Arduino to Raspberry Pi从 Arduino 到 Raspberry Pi 的不可靠 SPI 字节数组传输
【发布时间】:2016-08-31 20:37:41
【问题描述】:

我正在开展一个项目,该项目从 Arduino Pro Mini 收集数据并使用 SPI 将其发送到树莓派进行存储。

Pro Mini 将读取模拟输入并计算电压(一旦我完成),并在使用 ISR 提示时将值传递给 Pi。

我在两个平台上都使用 C/C++ 以保持统一。从代码使用 Arduino IDE 剪辑在一起,主代码基于 Pi 的 BCM2835 SPI 库示例。

Arduino 代码用于计算 float 值并将浮点值预处理为 4 个字节/字符的数组(我正在拍摄二进制,因为我认为这是最好的方法去)。 一旦 Pi 提示,每个字节都会被发送并重新编译为浮点数。

这是我现在拥有的:

从属

/*************************************************************
ARDUINO BREAKER READ/SPI PRE-PROC/TRANSMIT CASES
****************************************************************/

/***************************************************************
 Global Variables
***************************************************************/

byte command = 0; //command from PI
byte bytes[4];    //

int sensorVoltage, sensorCurrent; //eventual live reading vars
float Voltage, Current, RealCurrent, RealVoltage, Power;

/***************************************************************
 Set Up
  -designate arudino as slave
  -turn on interrupts
***************************************************************/

void setup (void)
{
  //debugging with serial monitor
  Serial.begin(9600);

  // Set up arduino as slave
  pinMode(MOSI, INPUT);
  pinMode(SCK, INPUT);
  pinMode(SS, INPUT);   
  pinMode(MISO, OUTPUT);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // turn on interrupts
  SPCR |= _BV(SPIE);

}  // end of setup

/*************************************************************
 Interrupt Service Routine 
 ************************************************************/

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  delay(500); //for errors

  // Create union of shared memory space
  union 
  {
    float f_var;
    unsigned char bytes[4];
  } u;

  // Overwrite bytes of union with float variable
  u.f_var = RealVoltage;

  // Assign bytes to input array
  memcpy(bytes, u.bytes, 4);

  byte c = SPDR;
  command = c; 

  switch (command)
  {
  // null command zeroes register
  case 0:

    SPDR = 0;
    break;

  // case a - d reserved for voltage
  case 'a':
    SPDR = bytes[3];  
    break;

  // incoming byte, return byte result
  case 'b':

    SPDR = bytes[2];  
    break;

  // incoming byte, return byte result    
  case 'c':

    SPDR =  bytes[1];  
    break;


  // incoming byte, return byte result    
  case 'd':

    SPDR = bytes[0];  
    break;

 /**  // case e -h reserved for current
  case 'e':

    SPDR = amps.b[0];  
    break;

  // incoming byte, return byte result
  case 'f':

    SPDR = amps.b[1];  
    break;

  // incoming byte, return byte result    
  case 'g':

    SPDR = amps.b[2];  
    break;

  // incoming byte, return byte result    
  case 'h':

    SPDR = amps.b[3];  
    break;

   // case i - l reserved for wattage
  case 'i':

    SPDR = watts.b[0];  
    break;

  // incoming byte, return byte result
  case 'j':

    SPDR = watts.b[1];  
    break;

  // incoming byte, return byte result    
  case 'k':

    SPDR = watts.b[2];  
    break;

  // incoming byte, return byte result    
  case 'l':

    SPDR = watts.b[3];  
    break;**/

  } // end of switch

}  // end of interrupt service routine (ISR) SPI_STC_vect

/***************************************************************  
 Loop until slave is enabled by Pi.
****************************************************************/
void loop (void)
{
/*************************************************************
Read and Calculate
****************************************************************/

  /**
  sensorVoltage = analogRead(A2);
  sensorCurrent = analogRead(A3);
  Voltage = sensorVoltage*(5.0/1023.0);
  Current = sensorCurrent*(5.0/1023.0);
  RealCurrent = Current/0.204545;
  RealVoltage = (Voltage/0.022005);
  Power = RealVoltage*RealCurrent;
**/
  RealVoltage = 1.234;
/*************************************************************
Loop Check for SS activation
****************************************************************/

  // if SPI not active, clear current command, else preproc floats and pass to SPI
  if (digitalRead (SS) == HIGH){
    command = 0;
  }
/*************************************************************
Debug with serial monitor
****************************************************************/
/*
  Serial.print("Byte 3: ");
  Serial.println(bytes[3],BIN);
  delay(500);
  Serial.print("Byte 2: ");
  Serial.println(bytes[2],BIN);
  delay(500);
  Serial.print("Byte 1: ");
  Serial.println(bytes[1],BIN);
  delay(500);
  Serial.print("Byte 0: ");
  Serial.println(bytes[0],BIN);
  delay(1000);
  Serial.println();*/
}

大师

#include <bcm2835.h>
#include <stdio.h>


void setup()
{
    bcm2835_spi_begin();
    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST);      // The default
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);                   // The default
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default
    bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default
}

char getByte(const char command){

    char read_data = bcm2835_spi_transfer(command);
    delay(100);
    return read_data;
}

int main(int argc, char **argv)
{
//If you call this, it will not actually access the GPIO
//Use for testing
//bcm2835_set_debug(1);

    if (!bcm2835_init())
        return 1;
    setup();

//Start communication       
    bcm2835_spi_chipSelect(BCM2835_SPI_CS0);// Enable 0

    //voltage 1-4  
    char read_data = getByte('a');
    printf("byte is %02d\n", read_data);

    read_data = getByte('b');
    printf("byte is %02d\n", read_data);

    read_data = getByte('c');
    printf("byte is %02d\n", read_data);

    read_data = getByte('d');
    printf("byte is %02d\n", read_data);    

   /** voltage = volts.f;   
    printf("%.6f", voltage);
    printf("\n");
    **/
    delay(1000);   

    bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, HIGH);
    bcm2835_spi_chipSelect(BCM2835_SPI_CS0);// Disable 0
    bcm2835_spi_end();
    bcm2835_close();

    return 0;
}

我使用固定值来调试代码。有时 Pi 上的 SPI 输出是准确的,但除此之外它会发生变化并输出部分准确和/或随机字节。

我无法解决的问题是 Pi 方面的稳定性,因此我正在寻求帮助来评估我的代码是否导致不准确或者它是否是我的硬件。

【问题讨论】:

    标签: c++ c arduino spi raspberry-pi3


    【解决方案1】:

    我猜我会说这是发送者和接收者之间的时间问题。尝试查看您收到的数据位,看看它们是向前还是向后移动。这可能表明 pi 等待太久才开始接收,或者等待所有数据的时间不够长。我认为问题可能与延迟有关:

    delay(500); //for errors
    

    在 Arduino 上,以及

    delay(1000); 
    

    在接收器上。你为什么用这些? 500ms 是让 pi 等待对 SPI 数据的响应的较长时间。

    请注意,现在还有一个用于 pi 的 SPI 内核驱动程序 (spidev) - 这是一种更符合行业标准的方法,并且可能是一种更强大的方法。

    在树莓派 github 网站上有一个很好的例子:https://github.com/raspberrypi/linux/blob/rpi-4.4.y/Documentation/spi/spidev_test.c

    【讨论】:

    • 感谢 js441 的回复。我转而使用 python 和 spiDev,因为它更直接。让我问你,你认为 python over C 在行业标准方面同样可以接受吗?
    • @giri 这是一个很难回答的问题。两者都在工业中使用,更多的是适合您的情况。如果您可以用一种语言比另一种更容易地制作有效的工作解决方案,那么这就是您的语言。
    猜你喜欢
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 1970-01-01
    相关资源
    最近更新 更多