shenhaiyu 发表于 2013-5-30 16:37:16

两个Arduino之间进行SPI通信

原文地址:http://www.gammon.com.au/forum/?id=10892

最近需要研究一下两台Arduino之间使用SPI通信的例子,搜了一下,只有国外大神们做过这种通讯,我们的坛子上找不到相关的资料,于是我结合自己的研究把这一通讯方式记录下来,给需要的同学们作参考:

使用两块Arduino UNO,一主一从。

Arduino UNO A: SPI 主机
Arduino UNO B: SPI 从机

连线方式:
      A--------------------B
(10) SS---------->(10) SS
(11) MOSI------->(11) MOSI
(12) MISO<-------(12) MISO
(13) SCLK------->(13) SCLK


主机从机分别写入如下代码:

从机:

#include <SPI.h>

void setup (void)
{
Serial.begin(9600);      // 开始串口通讯
digitalWrite(SS, HIGH);
SPI.begin ();            // PI通讯开始
//SPI.setClockDivider(SPI_CLOCK_DIV8); //??
}

void loop (void)
{
char c;

// 片选为从机
digitalWrite(SS, LOW);    // SS - pin 10

// 发送字串
for (const char * p = "Hello, world!\n" ; c = *p; p++) {
    SPI.transfer (c);
    Serial.print(c);
}

// 取消从机
digitalWrite(SS, HIGH);
delay (1000);
}


主机:

#include <SPI.h>

char buf ;
volatile byte pos;
volatile boolean process_it;

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

// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);

// 设置为接收状态
SPCR |= _BV(SPE);

// 准备接受中断
pos = 0;   // 清空缓冲区
process_it = false;

// 开启中断
SPI.attachInterrupt();
}


// SPI 中断程序
ISR (SPI_STC_vect)
{
byte c = SPDR;// 从 SPI 数据寄存器获取数据
if (pos < sizeof(buf))
{
    buf = c;
    if (c == '\n')
      process_it = true;
}
}

void loop (void)
{
if (process_it)
{
    buf = 0;
    Serial.println (buf);
    pos = 0;
    process_it = false;
}
}

写入后打开各自的串口监视器,就能看到两个Arduino进行字串通信了。

hmjack2008 发表于 2013-5-30 18:10:41

LZ 的"从机:/ 主机:" 代码 与 原文地址 (http://www.gammon.com.au/forum/?id=10892) 的相反 !!

shenhaiyu 发表于 2013-5-30 22:39:13

hmjack2008 发表于 2013-5-30 18:10 static/image/common/back.gif
LZ 的"从机:/ 主机:" 代码 与 原文地址 (http://www.gammon.com.au/forum/?id=10892) 的相反 !!

好吧,反正能通信就是了~~~

friskit 发表于 2013-6-1 09:35:38

共地。。。。。一定要共地。。。。

shenhaiyu 发表于 2013-6-1 09:42:52

friskit 发表于 2013-6-1 09:35 static/image/common/back.gif
共地。。。。。一定要共地。。。。

不用啊,有SCK就不用共地了,这个我试验过

哈哈顺 发表于 2013-12-17 22:27:11

哈哈,不供地貌似不能形成回路,难道其他的接口有?

shenhaiyu 发表于 2013-12-18 17:28:16

哈哈顺 发表于 2013-12-17 22:27 static/image/common/back.gif
哈哈,不供地貌似不能形成回路,难道其他的接口有?

哦~~~我是接到一台电脑上了~~~

kwleung 发表于 2013-12-29 23:38:43

http://avrbeginners.net/architecture/img/spi_fig1_a.gif

kwleung 发表于 2013-12-29 23:42:54

http://www.gammon.com.au/forum/?id=10892

one example : slave send data back to master

kwleung 发表于 2013-12-29 23:47:13

slave code:

// Written by Nick Gammon
// April 2011

#include "pins_arduino.h"

// what to do with incoming data
byte command = 0;

// start of transaction, no command yet
void ss_falling ()
{
command = 0;
}// end of interrupt service routine (ISR) ss_falling

void setup (void)
{

// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);

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

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

// interrupt for SS falling edge
attachInterrupt (0, ss_falling, FALLING);

}// end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;

switch (command)
{
// no command? then this is the command
case 0:
    command = c;
    SPDR = 0;
    break;
   
// add to incoming byte, return result
case 'a':
    SPDR = c + 15;// add 15
    break;
   
// subtract from incoming byte, return result
case 's':
    SPDR = c - 8;// subtract 8
    break;

} // end of switch

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

void loop (void)
{
// all done with interrupts
}// end of loop


//////////////////////////////////////////////////////////////////////////////////////////////
Master (example)




// Written by Nick Gammon
// April 2011


#include <SPI.h>
#include "pins_arduino.h"

void setup (void)
{
Serial.begin (115200);
Serial.println ();

digitalWrite(SS, HIGH);// ensure SS stays high for now

// Put SCK, MOSI, SS pins into output mode
// also put SCK, MOSI into LOW state, and SS into HIGH state.
// Then put SPI hardware into Master mode and turn SPI on
SPI.begin ();

// Slow down the master a bit
SPI.setClockDivider(SPI_CLOCK_DIV8);

}// end of setup

byte transferAndWait (const byte what)
{
byte a = SPI.transfer (what);
delayMicroseconds (20);
return a;
} // end of transferAndWait

void loop (void)
{

byte a, b, c, d;

// enable Slave Select
digitalWrite(SS, LOW);   

transferAndWait ('a');// add command
transferAndWait (10);
a = transferAndWait (17);
b = transferAndWait (33);
c = transferAndWait (42);
d = transferAndWait (0);

// disable Slave Select
digitalWrite(SS, HIGH);

Serial.println ("Adding results:");
Serial.println (a, DEC);
Serial.println (b, DEC);
Serial.println (c, DEC);
Serial.println (d, DEC);

// enable Slave Select
digitalWrite(SS, LOW);   

transferAndWait ('s');// subtract command
transferAndWait (10);
a = transferAndWait (17);
b = transferAndWait (33);
c = transferAndWait (42);
d = transferAndWait (0);

// disable Slave Select
digitalWrite(SS, HIGH);

Serial.println ("Subtracting results:");
Serial.println (a, DEC);
Serial.println (b, DEC);
Serial.println (c, DEC);
Serial.println (d, DEC);

delay (1000);// 1 second delay
}// end of loop

hi55234 发表于 2013-12-30 10:54:18

SPI.setClockDivider(SPI_CLOCK_DIV8);
=設置SPI串列通信的時鐘。
通信時鐘是由系統時鐘分頻而得到,分頻值有2,4,8,16,32,64或128。
預設設置是SPI_CLOCK_DIV4,設置SPI串列通信時鐘系統時鐘的四分之一。

語法

SPI.setClockDivider(divider)

參數

divider:

SPI_CLOCK_DIV2
SPI_CLOCK_DIV4
SPI_CLOCK_DIV8
SPI_CLOCK_DIV16
SPI_CLOCK_DIV32
SPI_CLOCK_DIV64
SPI_CLOCK_DIV128

shenhaiyu 发表于 2013-12-31 22:31:59

kwleung 发表于 2013-12-29 23:47 static/image/common/back.gif
slave code:

// Written by Nick Gammon


Thanks for your share

shenhaiyu 发表于 2013-12-31 22:32:33

hi55234 发表于 2013-12-30 10:54 static/image/common/back.gif
SPI.setClockDivider(SPI_CLOCK_DIV8);
=設置SPI串列通信的時鐘。
通信時鐘是由系統時鐘分頻而得到,分頻 ...

学习一下,多谢!!

leicheng 发表于 2014-3-24 21:12:22

不知道为什么要将3.3V的电压接口连接在一起?
另外,传输过程中有单个字符的丢包现象。

shihaipeng04 发表于 2014-3-24 22:53:32

本帖最后由 shihaipeng04 于 2014-3-24 23:42 编辑

我开始没有共地,误码奇高。可能之前是因为公用同一电脑勉强还可以传输,所以乱码了还能坚持。偶尔会死机。 现在共地了完全没有误码了,也不死机了。

哈哈,刚才又测试了一下 共usb hub,误码率也降低了不少,但是依然有误码。 可见一个短小精炼的共地回路是多么的重要啊。


就按我这个水平,别说是飞机会跑偏,就是个玩具车都能开失联了。。。


问题解决鸟~~
//_________________happyend______________
页: [1] 2 3
查看完整版本: 两个Arduino之间进行SPI通信