2016-08-31 3 views
0

Arduino Pro Mini에서 데이터를 수집하고이를 SPI를 사용하여 저장 용 라즈베리 파이에 보내는 프로젝트를 진행 중입니다.Arduino에서 Raspberry Pi 로의 신뢰할 수없는 SPI 바이트 배열 전송

Pro Mini는 아날로그 입력을 읽고 전압을 계산하고 (일단 완료되면) ISR을 사용하여 프롬프트 될 때 Pi에 값을 전달합니다.

두 플랫폼 모두 C/C++을 사용하여 일관되게 유지합니다. 슬레이브 코드는 Arduino IDE를 사용하여 함께 자르고 마스터 코드는 Pi의 BCM2835 SPI 라이브러리 예제를 기반으로합니다.

Arduino 코드는 float 값을 계산하고 float 값을 4 바이트/문자 배열로 사전 처리하기위한 것입니다 (이진 코드로 촬영하는 것이 최선의 방법이라고 생각하기 때문에). Pi에 의해 프롬프트가 표시되면 각 바이트가 보내지고 float로 다시 컴파일됩니다. 여기

내가 지금 무엇을 가지고 :

슬레이브

/************************************************************* 
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 측면에서의 안정성입니다. 따라서 코드가 부정확하거나 하드웨어인지 여부를 평가하는 데 도움이 필요합니다.

답변

0

나는 이것이 발신자와 수신자 사이의 타이밍 문제라고 생각한다. 수신중인 데이터의 비트를보고 앞으로 또는 뒤로 이동했는지 확인하십시오. 이것은 pi가 수신을 시작하는 데 너무 오랜 시간 대기하거나 모든 데이터를 충분히 길게 기다리지 않았 음을 나타낼 수 있습니다.

delay(500); //for errors 
아두 이노에

, 수신기에

delay(1000); 

: 나는 문제가 지연 주위에 아마 생각합니다. 왜 이걸 쓰고 있니? 500ms는 SPI 데이터에 대한 응답을 기다리는 동안 pi를 오랜 시간 동안 기다립니다.

이제는 파이에 대한 SPI 커널 드라이버 (spidev)가 있습니다. 이것은 훨씬 더 업계 표준 방식이며 잠재적으로보다 강력한 방법입니다. 회신 js441에 대한 https://github.com/raspberrypi/linux/blob/rpi-4.4.y/Documentation/spi/spidev_test.c

+0

감사 :

라즈베리 파이 GitHub의 사이트에서 이것의 좋은 예는있다. 나는 훨씬 더 솔직하기 때문에 spiDev로 파이썬을 사용하기로 바꿨다. 내가 C로 파이썬이 산업 표준에 대해 똑같이 받아 들일 수 있다고 생각하니? – giri

+0

@giri 대답하기 어려운 질문입니다. 두 가지 모두 업계에서 사용되고 있으며, 이는 여러분에게 맞는 것보다 더 중요합니다. 하나의 언어로 유효한 작업 솔루션을 다른 언어보다 쉽게 ​​만들 수 있다면, 그것은 당신을위한 언어입니다. – js441