极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 112308|回复: 40

两个Arduino之间进行SPI通信

[复制链接]
发表于 2013-5-30 16:37:16 | 显示全部楼层 |阅读模式
原文地址: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


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

从机:

  1. #include <SPI.h>

  2. void setup (void)
  3. {
  4.   Serial.begin(9600);        // 开始串口通讯
  5.   digitalWrite(SS, HIGH);
  6.   SPI.begin ();              // PI通讯开始
  7.   //SPI.setClockDivider(SPI_CLOCK_DIV8); //??
  8. }

  9. void loop (void)
  10. {
  11.   char c;

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

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

  19.   // 取消从机
  20.   digitalWrite(SS, HIGH);
  21.   delay (1000);
  22. }
复制代码



主机:

  1. #include <SPI.h>

  2. char buf [100];
  3. volatile byte pos;
  4. volatile boolean process_it;

  5. void setup (void)
  6. {
  7.   Serial.begin (9600);

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

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

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

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


  18. // SPI 中断程序
  19. ISR (SPI_STC_vect)
  20. {
  21.   byte c = SPDR;  // 从 SPI 数据寄存器获取数据
  22.   if (pos < sizeof(buf))
  23.   {
  24.     buf [pos++] = c;
  25.     if (c == '\n')
  26.       process_it = true;
  27.   }
  28. }

  29. void loop (void)
  30. {
  31.   if (process_it)
  32.   {
  33.     buf [pos] = 0;  
  34.     Serial.println (buf);
  35.     pos = 0;
  36.     process_it = false;
  37.   }
  38. }
复制代码


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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

参与人数 1 +1 收起 理由
幻生幻灭 + 1 赞一个!

查看全部评分

回复

使用道具 举报

发表于 2013-5-30 18:10:41 | 显示全部楼层
LZ 的  "从机:/ 主机:" 代码 与 原文地址 (http://www.gammon.com.au/forum/?id=10892) 的相反 !!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-30 22:39:13 | 显示全部楼层
hmjack2008 发表于 2013-5-30 18:10
LZ 的  "从机:/ 主机:" 代码 与 原文地址 (http://www.gammon.com.au/forum/?id=10892) 的相反 !!

好吧,反正能通信就是了~~~
回复 支持 反对

使用道具 举报

发表于 2013-6-1 09:35:38 | 显示全部楼层
共地。。。。。一定要共地。。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-6-1 09:42:52 | 显示全部楼层
friskit 发表于 2013-6-1 09:35
共地。。。。。一定要共地。。。。

不用啊,有SCK就不用共地了,这个我试验过
回复 支持 反对

使用道具 举报

发表于 2013-12-17 22:27:11 | 显示全部楼层
哈哈,不供地貌似不能形成回路,难道其他的接口有?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-12-18 17:28:16 | 显示全部楼层
哈哈顺 发表于 2013-12-17 22:27
哈哈,不供地貌似不能形成回路,难道其他的接口有?

哦~~~我是接到一台电脑上了~~~
回复 支持 反对

使用道具 举报

发表于 2013-12-29 23:38:43 | 显示全部楼层


回复 支持 反对

使用道具 举报

发表于 2013-12-29 23:42:54 | 显示全部楼层
http://www.gammon.com.au/forum/?id=10892

one example : slave send data back to master
回复 支持 反对

使用道具 举报

发表于 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
回复 支持 反对

使用道具 举报

发表于 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
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-12-31 22:31:59 | 显示全部楼层
kwleung 发表于 2013-12-29 23:47
slave code:

// Written by Nick Gammon

Thanks for your share
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-12-31 22:32:33 | 显示全部楼层
hi55234 发表于 2013-12-30 10:54
SPI.setClockDivider(SPI_CLOCK_DIV8);
=設置SPI串列通信的時鐘。
通信時鐘是由系統時鐘分頻而得到,分頻 ...

学习一下,多谢!!
回复 支持 反对

使用道具 举报

发表于 2014-3-24 21:12:22 | 显示全部楼层
不知道为什么要将3.3V的电压接口连接在一起?
另外,传输过程中有单个字符的丢包现象。
回复 支持 反对

使用道具 举报

发表于 2014-3-24 22:53:32 | 显示全部楼层
本帖最后由 shihaipeng04 于 2014-3-24 23:42 编辑

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

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


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


问题解决鸟~~
//_________________happyend______________

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 10:36 , Processed in 0.061242 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表