Arduino和PIC(8位微控制器)之间的SPI信号转换

时间:2017-03-16 06:02:37

标签: c arduino pic spi

我正在测试Arduino UNO和PIC16F1(PC16F1827)之间的SPI通信。

这是我的布线和源代码:

MPLAB X IDE 3.55 / XC8 v1.4.1(免费)

#include <xc.h>

#pragma config FOSC = INTOSC    // Inner clock
#pragma config WDTE = OFF       // Watchdog timer
#pragma config PWRTE = OFF      // Power-Up timer
#pragma config MCLRE = ON       // MCLR pin
#pragma config CP = OFF         // Code protection
#pragma config CPD = OFF        // Memory protection
#pragma config BOREN = ON       // Brown-out Reset
#pragma config CLKOUTEN = OFF   // Outer clock
#pragma config IESO = OFF       // Oscillator switchover
#pragma config FCMEN = OFF      // Fail-Safe clockmonitor

#pragma config WRT = OFF        // Power-up Timer
#pragma config PLLEN = ON       // Use 4xPLL
#pragma config STVREN = OFF     // Reset when stack error
#pragma config LVP = OFF        // Low voltage program

#define _XTAL_FREQ 32000000 // 32MHz

void main(void)
{
    // PIC initialization
    OSCCON = 0b00110100; // Inner clock = 4Mhz

    ANSELA = 0b00000000; // All RA are digital
    TRISA = 0b00000001; // RA0 is input
    PORTA = 0b00000000; // Initialize RA

    // SPI initalization
    SDO1SEL = 0; // RB2 sets to SDO pin
    SSP1CON1 = 0b00100101; // Slave mode(Unuse SS)
    SSP1STAT = 0b01000000; // Slave mode(Clock phase is LOW)

    SSP1BUF = 0;

    unsigned char read_data; // Current is dummy
    unsigned char count = 255;
    while(1){
        // Read byte from master
        read_data = SSP1BUF;       
        while(!SSP1STATbits.BF);

        // Write byte to master
        if(count == 255) count = 0; else count++;
        SSP1BUF = count;
        while(!SSPSTATbits.BF);
    }
}

Arduino IDE 1.8.1

#include <SPI.h>

void setup()
{
  Serial.begin(9600);

  SPI.begin() ;
  SPI.setBitOrder(MSBFIRST) ;
  SPI.setDataMode(SPI_MODE1) ;

  delay(1500) ;
}

void loop()
{
  char msg[100];
  byte i, n;

  for (i = 0 ; i < 10 ; i++) {
    n = SPI.transfer(i) ;

    sprintf(msg, "%d/%d,", n, i);
    Serial.print(msg);
  }

  Serial.print("\n");
}

Wiring image

我的理想是Arduino接收0-255的值(我忽略了SPI的频率,因为它是编程测试)。但SPI.transfer()返回值i(0-9)。

我担心我应该在哪里修复,因为网上的这些IC几乎没有技术信息。有人知道这个好方法吗?

2 个答案:

答案 0 :(得分:0)

我查看了PIC 16F1826数据表以检查您的连接。

用于从SPI1传输数据的引脚(名为SDO1)可以是RA6或RB2(来自数据表,第12页[表1-2])。

鉴于您向SDO1SEL写入0(复位时它已经为0),SDO1似乎在RB2上。实际上,您连接了RB2而不是RA6。

但是您没有清除相应的TRISB位以使RB2成为输出,如第236页(第25.2.2章)中所述。您当前的程序无法从RB2 / SDO1传输数据。

也许还有其他错误,可能是设置寄存器。我建议仔细阅读数据表并修改PIC方面的所有设置。然后,如果您仍有问题,请更新您的问题,我将更新我的答案(留下评论以唤醒我)。例如,我没有检查你从RB2的连接是否到达Arduino的正确位置(我看到它转到引脚11,但我没有检查它是否正确:像一些编译器,我停止第一个错误)

答案 1 :(得分:0)

我修复了布线(MISO到MISO,MOSI到MOSI,连接SS)。

Fixed wiring

我改变了PIC16F1上的程序。它将初始化RB引脚和信号接收作为中断附加。

unsigned char count = 0;

void interrupt OnInterSpi()
{
    if (SSP1IF == HIGH){
        SSP1IF = LOW;

        unsigned char read_data = SSP1BUF;
        if(count == 255) count = 0; else count++;
        SSP1BUF = count;
    }
}

void main(void)
{
    OSCCON = 0b00110100;    

    ANSELA = 0b00000000;    
    TRISA = 0b00000001;     
    PORTA = 0b00000000;     


    ANSELB = 0b00000000;
    TRISB = 0b00010010;     
    PORTB = 0b00000000;     

    SDO1SEL = 0;             
    SSP1CON1 = 0b00100100;    
    SSP1STAT = 0b01000000;    

    SSP1IF = 0;  
    SSP1IE = 1;  
    PEIE = 1;   
    GIE = 1;   

    while(1) ;
}

在Arduino上,我启用了SS信号。

#include <SPI.h>

#define SS_PIN 10

void setup()
{
    Serial.begin(9600);

    pinMode(SS_PIN, OUTPUT);
    digitalWrite(SS_PIN, HIGH);

    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
}

char msg[100];
byte i, n;

void loop()
{
    digitalWrite(SS_PIN, LOW);
    n = SPI.transfer(i);
    digitalWrite(SS_PIN, HIGH);

    sprintf(msg, "%d/%d, ", n, i);
    Serial.print(msg);
}

至少在我的环境中,Arduino的串行监视器上的接收值正确增加。