Làm thế nào để bạn sử dụng SPI trên Arduino?


44

Với tham chiếu đến Arduino Uno, Mega2560, Leonardo và các bảng tương tự:

  • SPI hoạt động như thế nào?
  • SPI nhanh như thế nào?
  • Làm thế nào để tôi kết nối giữa chủ và nô lệ?
  • Làm thế nào để tôi làm nô lệ SPI?

Xin lưu ý: Đây là một câu hỏi tham khảo.


Bạn có thể trả lời câu hỏi liên quan này arduino.stackexchange.com/questions/60703/NH
qwr

Câu trả lời:


80

Giới thiệu về SPI

Các ngoại vi Interface Serial Bus (SPI) giao diện được sử dụng để giao tiếp giữa nhiều thiết bị trên một khoảng cách ngắn, và ở tốc độ cao.

Thông thường có một thiết bị "chính" duy nhất, khởi tạo liên lạc và cung cấp đồng hồ điều khiển tốc độ truyền dữ liệu. Có thể có một hoặc nhiều nô lệ. Đối với nhiều hơn một nô lệ, mỗi người có tín hiệu "chọn nô lệ" của riêng mình, được mô tả sau.


Tín hiệu SPI

Trong hệ thống SPI toàn diện, bạn sẽ có bốn đường tín hiệu:

  • Master Out, Slave In ( MOSI ) - là dữ liệu đi từ chủ đến nô lệ
  • Master In, Slave Out ( MISO ) - là dữ liệu đi từ nô lệ đến chủ
  • Đồng hồ nối tiếp ( SCK ) - khi điều này bật cả mẫu chính và mẫu nô lệ bit tiếp theo
  • Chọn nô lệ ( SS ) - điều này cho biết một nô lệ cụ thể sẽ "hoạt động"

Khi nhiều nô lệ được kết nối với tín hiệu MISO, chúng được dự kiến ​​sẽ ở trạng thái ba (giữ ở mức trở kháng cao) mà dòng MISO cho đến khi chúng được chọn bởi Slave Chọn được xác nhận. Thông thường Slave Chọn (SS) xuống thấp để khẳng định nó. Đó là, nó đang hoạt động thấp. Khi một nô lệ cụ thể được chọn, nó sẽ cấu hình dòng MISO làm đầu ra để nó có thể gửi dữ liệu đến bản gốc.

Hình ảnh này cho thấy cách dữ liệu được trao đổi khi một byte được gửi:

Giao thức SPI hiển thị 4 tín hiệu

Lưu ý rằng ba tín hiệu là đầu ra từ bản gốc (MOSI, SCK, SS) và một tín hiệu là đầu vào (MISO).


Thời gian

Chuỗi sự kiện là:

  • SS xuống thấp để khẳng định nó và kích hoạt nô lệ
  • Các SCKdòng Toggles để cho biết khi các dòng dữ liệu cần được lấy mẫu
  • Dữ liệu được lấy mẫu bởi cả chủ và nô lệ ở cạnh đầu của SCK(sử dụng pha đồng hồ mặc định)
  • Cả chủ và nô lệ đều chuẩn bị cho bit tiếp theo trên cạnh sau của SCK(sử dụng pha đồng hồ mặc định), bằng cách thay đổi MISO/ MOSInếu cần
  • Khi quá trình truyền kết thúc (có thể sau khi nhiều byte được gửi), sau đó SSchuyển sang xác nhận lại

Lưu ý rằng:

  • Bit quan trọng nhất được gửi trước (theo mặc định)
  • Dữ liệu được gửi và nhận cùng một lúc (song công hoàn toàn)

Vì dữ liệu được gửi và nhận trên cùng một xung đồng hồ, nên nô lệ không thể trả lời chủ ngay lập tức. Các giao thức SPI thường mong đợi chủ yêu cầu dữ liệu trên một lần truyền và nhận được phản hồi ở lần truyền tiếp theo.

Sử dụng thư viện SPI trên Arduino, thực hiện một lần chuyển giống như mã này:

 byte outgoing = 0xAB;
 byte incoming = SPI.transfer (outgoing);

Mã mẫu

Ví dụ về chỉ gửi (bỏ qua mọi dữ liệu đến):

#include <SPI.h>

void setup (void)
  {
  digitalWrite(SS, HIGH);  // ensure SS stays high
  SPI.begin ();
  } // end of setup

void loop (void)
  {
  byte c;

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  // send test string
  for (const char * p = "Fab" ; c = *p; p++)
    SPI.transfer (c);

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

  delay (100);
  } // end of loop

Đấu dây cho SPI chỉ đầu ra

Đoạn mã trên (chỉ gửi) có thể được sử dụng để lái một thanh ghi dịch chuyển nối tiếp đầu ra. Đây là những thiết bị chỉ xuất ra, vì vậy chúng tôi không cần phải lo lắng về bất kỳ dữ liệu nào đến. Trong trường hợp của họ, chân SS có thể được gọi là chân "cửa hàng" hoặc "chốt".

Giao thức SPI hiển thị 3 tín hiệu

Ví dụ về điều này là thanh ghi dịch chuyển nối tiếp 74HC595 và các dải đèn LED khác nhau, chỉ đề cập đến một cặp vợ chồng. Ví dụ: màn hình LED 64 pixel này được điều khiển bởi chip MAX7219:

Màn hình LED 64 pixel

Trong trường hợp này, bạn có thể thấy rằng nhà sản xuất bảng đã sử dụng các tên tín hiệu hơi khác nhau:

  • DIN (Data In) là MOSI (Master Out, Slave In)
  • CS (Chọn chip) là SS (Chọn nô lệ)
  • CLK (Đồng hồ) là SCK (Đồng hồ nối tiếp)

Hầu hết các bảng sẽ theo một mô hình tương tự. Đôi khi DIN chỉ là DI (Data In).

Đây là một ví dụ khác, lần này là bảng hiển thị LED 7 đoạn (cũng dựa trên chip MAX7219):

Màn hình LED 7 đoạn

Cái này sử dụng chính xác tên tín hiệu giống như bảng khác. Trong cả hai trường hợp này, bạn có thể thấy rằng bo mạch chỉ cần 5 dây, ba dây cho SPI, cộng với nguồn và đất.


Đồng hồ pha và cực

Có bốn cách bạn có thể lấy mẫu đồng hồ SPI.

Giao thức SPI cho phép các biến thể về cực của các xung đồng hồ. CPOL là cực của đồng hồ, và CPHA là pha đồng hồ.

  • Chế độ 0 (mặc định) - đồng hồ thường ở mức thấp (CPOL = 0) và dữ liệu được lấy mẫu khi chuyển từ thấp sang cao (cạnh đầu) (CPHA = 0)
  • Chế độ 1 - đồng hồ thường ở mức thấp (CPOL = 0) và dữ liệu được lấy mẫu khi chuyển từ cao sang thấp (cạnh đuôi) (CPHA = 1)
  • Chế độ 2 - đồng hồ thường cao (CPOL = 1) và dữ liệu được lấy mẫu khi chuyển từ cao sang thấp (cạnh đầu) (CPHA = 0)
  • Chế độ 3 - đồng hồ thường cao (CPOL = 1) và dữ liệu được lấy mẫu khi chuyển từ thấp sang cao (cạnh đuôi) (CPHA = 1)

Chúng được minh họa trong đồ họa này:

Pha đồng hồ SPI và cực

Bạn nên tham khảo biểu dữ liệu cho thiết bị của mình để có được pha và cực đúng. Thường sẽ có một sơ đồ chỉ ra cách lấy mẫu đồng hồ. Ví dụ: từ biểu dữ liệu cho chip 74HC595:

Đồng hồ 74HC595

Như bạn có thể thấy đồng hồ thường ở mức thấp (CPOL = 0) và nó được lấy mẫu ở cạnh đầu (CPHA = 0) do đó đây là chế độ SPI 0.

Bạn có thể thay đổi phân cực đồng hồ và pha trong mã như thế này (tất nhiên chỉ chọn một)

SPI.setDataMode (SPI_MODE0);
SPI.setDataMode (SPI_MODE1);
SPI.setDataMode (SPI_MODE2);
SPI.setDataMode (SPI_MODE3);

Phương pháp này không được dùng trong các phiên bản 1.6.0 trở đi của Arduino IDE. Đối với các phiên bản gần đây, bạn thay đổi chế độ đồng hồ trong SPI.beginTransactioncuộc gọi, như thế này:

SPI.beginTransaction (SPISettings (2000000, MSBFIRST, SPI_MODE0));  // 2 MHz clock, MSB first, mode 0

Thứ tự dữ liệu

Mặc định đầu tiên là bit đáng kể nhất, tuy nhiên bạn có thể yêu cầu phần cứng xử lý bit có trọng số thấp nhất trước tiên như thế này:

SPI.setBitOrder (LSBFIRST);   // least significant bit first
SPI.setBitOrder (MSBFIRST);   // most significant bit first

Một lần nữa, điều này không được chấp nhận trong các phiên bản 1.6.0 trở đi của Arduino IDE. Đối với các phiên bản gần đây, bạn thay đổi thứ tự bit trong SPI.beginTransactioncuộc gọi, như thế này:

SPI.beginTransaction (SPISettings (1000000, LSBFIRST, SPI_MODE2));  // 1 MHz clock, LSB first, mode 2

Tốc độ

Cài đặt mặc định cho SPI là sử dụng tốc độ xung nhịp hệ thống chia cho bốn, nghĩa là, một xung đồng hồ SPI cứ sau 250 ns, giả sử xung nhịp CPU 16 MHz. Bạn có thể thay đổi bộ chia đồng hồ bằng cách sử dụng setClockDividernhư thế này:

SPI.setClockDivider (divider);

Trong đó "dải phân cách" là một trong:

  • SPI_CLOCK_DIV2
  • SPI_CLOCK_DIV4
  • SPI_CLOCK_DIV8
  • SPI_CLOCK_DIV16
  • SPI_CLOCK_DIV32
  • SPI_CLOCK_DIV64
  • SPI_CLOCK_DIV128

Tốc độ nhanh nhất là "chia cho 2" hoặc một xung đồng hồ SPI cứ sau 125 ns, giả sử xung nhịp CPU 16 MHz. Do đó, sẽ mất 8 * 125 ns hoặc 1 sóng để truyền một byte.

Phương pháp này không được dùng trong các phiên bản 1.6.0 trở đi của Arduino IDE. Đối với các phiên bản gần đây, bạn thay đổi tốc độ truyền trong SPI.beginTransactioncuộc gọi, như sau:

SPI.beginTransaction (SPISettings (4000000, MSBFIRST, SPI_MODE0));  // 4 MHz clock, MSB first, mode 0

Tuy nhiên, thử nghiệm theo kinh nghiệm cho thấy cần phải có hai xung đồng hồ giữa các byte, do đó tốc độ tối đa mà byte có thể được đưa ra là 1,125 mỗi nhịp (với một vạch chia 2 xung nhịp).

Tóm lại, mỗi byte có thể được gửi với tốc độ tối đa là 1 trên 1.125, (với xung nhịp 16 MHz) cho tốc độ truyền tối đa theo lý thuyết là 1 / 1.125, hoặc 888.888 byte mỗi giây (không bao gồm chi phí thấp như SS trên, bật).


Kết nối với Arduino

Arduino Uno

Kết nối qua chân kỹ thuật số 10 đến 13:

Chân Arduino Uno SPI

Kết nối thông qua tiêu đề ICSP:

Sơ đồ chân ICSP - Uno

Tiêu đề ICSP

Arduino Atmega2560

Kết nối qua chân kỹ thuật số 50 đến 52:

Chân cắm Arduino Mega2560 SPI

Bạn cũng có thể sử dụng tiêu đề ICSP, tương tự như Uno ở trên.

Arduino Leonardo

Leonardo và Micro không để lộ các chân SPI trên các chân kỹ thuật số, không giống như Uno và Mega. Tùy chọn duy nhất của bạn là sử dụng các chân tiêu đề ICSP, như minh họa ở trên cho Uno.


Nhiều nô lệ

Một bậc thầy có thể giao tiếp với nhiều nô lệ (tuy nhiên chỉ có một người một lúc). Nó thực hiện điều này bằng cách khẳng định SS cho một nô lệ và khử xác nhận nó cho tất cả những người khác. Các nô lệ đã được SS khẳng định (thường có nghĩa là THẤP) định cấu hình chân MISO của nó làm đầu ra để nô lệ và một mình nô lệ đó có thể phản hồi với chủ. Các nô lệ khác bỏ qua mọi xung đồng hồ đến nếu SS không được xác nhận. Do đó, bạn cần thêm một tín hiệu cho mỗi nô lệ, như thế này:

Nhiều nô lệ SPI

Trong đồ họa này, bạn có thể thấy MISO, MOSI, SCK được chia sẻ giữa cả hai nô lệ, tuy nhiên mỗi nô lệ có tín hiệu SS (chọn nô lệ) riêng.


Giao thức

Thông số SPI không chỉ định các giao thức như vậy, do đó, tùy thuộc vào từng cặp chủ / nô lệ để thống nhất ý nghĩa của dữ liệu. Trong khi bạn có thể gửi và nhận byte đồng thời, byte nhận được không thể là phản hồi trực tiếp cho byte đã gửi (vì chúng đang được lắp ráp đồng thời).

Vì vậy, sẽ hợp lý hơn khi một đầu gửi yêu cầu (ví dụ: 4 có thể có nghĩa là "liệt kê thư mục đĩa") và sau đó thực hiện chuyển (có lẽ chỉ gửi số không ra ngoài) cho đến khi nhận được phản hồi hoàn chỉnh. Phản hồi có thể chấm dứt với một dòng mới hoặc ký tự 0x00.

Đọc biểu dữ liệu cho thiết bị nô lệ của bạn để xem trình tự giao thức mà nó mong đợi.


Cách tạo nô lệ SPI

Ví dụ trước đó cho thấy Arduino là chủ, gửi dữ liệu đến một thiết bị nô lệ. Ví dụ này cho thấy Arduino có thể là nô lệ như thế nào.

Thiết lập phần cứng

Kết nối hai Arduino Unos với nhau bằng các chân sau được kết nối với nhau:

  • 10 (SS)
  • 11 (MOSI)
  • 12 (MISO)
  • 13 (SCK)

  • + 5v (nếu cần)

  • GND (để trả lại tín hiệu)

Trên Arduino Mega, các chân là 50 (MISO), 51 (MOSI), 52 (SCK) và 53 (SS).

Trong mọi trường hợp, MOSI ở một đầu được kết nối với MOSI ở đầu kia, bạn không trao đổi chúng xung quanh (đó là bạn không có MOSI <-> MISO). Phần mềm cấu hình một đầu của MOSI (đầu cuối chính) làm đầu ra và đầu kia (đầu cuối phụ) làm đầu vào.

Ví dụ chủ

#include <SPI.h>

void setup (void)
{

  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


void loop (void)
{

  char c;

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  // send test string
  for (const char * p = "Hello, world!\n" ; c = *p; p++)
    SPI.transfer (c);

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

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

Ví dụ nô lệ

#include <SPI.h>

char buf [100];
volatile byte pos;
volatile bool process_it;

void setup (void)
{
  Serial.begin (115200);   // debugging

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

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

  // get ready for an interrupt
  pos = 0;   // buffer empty
  process_it = false;

  // now turn on interrupts
  SPI.attachInterrupt();

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;  // grab byte from SPI Data Register

  // add to buffer if room
  if (pos < sizeof buf)
    {
    buf [pos++] = c;

    // example: newline means time to process buffer
    if (c == '\n')
      process_it = true;

    }  // end of room available
}  // end of interrupt routine SPI_STC_vect

// main loop - wait for flag set in interrupt routine
void loop (void)
{
  if (process_it)
    {
    buf [pos] = 0;
    Serial.println (buf);
    pos = 0;
    process_it = false;
    }  // end of flag set

}  // end of loop

Các nô lệ hoàn toàn bị gián đoạn điều khiển, do đó nó có thể làm những thứ khác. Dữ liệu SPI đến được thu thập trong bộ đệm và cờ được đặt khi "byte đáng kể" (trong trường hợp này là một dòng mới) đến. Điều này nói với nô lệ để có được và bắt đầu xử lý dữ liệu.

Ví dụ về kết nối chủ với nô lệ bằng SPI

Bậc thầy và nô lệ Arduino SPI


Làm thế nào để nhận được phản hồi từ một nô lệ

Theo dõi từ đoạn mã trên để gửi dữ liệu từ một chủ SPI đến một nô lệ, ví dụ dưới đây cho thấy việc gửi dữ liệu tới một nô lệ, để nó làm gì đó với nó và trả về một phản hồi.

Các chủ tương tự như ví dụ trên. Tuy nhiên, một điểm quan trọng là chúng ta cần thêm một chút độ trễ (khoảng 20 micro giây). Mặt khác, nô lệ không có cơ hội phản ứng với dữ liệu đến và làm gì đó với nó.

Ví dụ cho thấy việc gửi một "lệnh". Trong trường hợp này "a" (thêm một cái gì đó) hoặc "s" (trừ một cái gì đó). Điều này là để cho thấy rằng nô lệ thực sự đang làm gì đó với dữ liệu.

Sau khi xác nhận chọn nô lệ (SS) để bắt đầu giao dịch, chủ sẽ gửi lệnh, theo sau là bất kỳ số byte nào, và sau đó tăng SS để chấm dứt giao dịch.

Một điểm rất quan trọng là nô lệ không thể đáp ứng với một byte đến cùng một lúc. Phản hồi phải ở byte kế tiếp. Điều này là do các bit đang được gửi và các bit đang được nhận đang được gửi đồng thời. Do đó, để thêm một số thứ vào bốn số, chúng ta cần năm lần chuyển, như sau:

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

Đầu tiên, chúng tôi yêu cầu hành động trên số 10. Nhưng chúng tôi không nhận được phản hồi cho đến lần chuyển tiếp theo (lần thứ 17). Tuy nhiên "a" sẽ được đặt thành trả lời thành 10. Cuối cùng, chúng tôi cuối cùng đã gửi một "số giả" số 0, để nhận được câu trả lời cho 42.

Thầy (ví dụ)

  #include <SPI.h>

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

    digitalWrite(SS, HIGH);  // ensure SS stays high for now
    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

Mã cho nô lệ về cơ bản thực hiện hầu hết mọi thứ trong thói quen ngắt (được gọi khi dữ liệu SPI đến). Nó nhận byte đến và thêm hoặc bớt theo "byte lệnh" đã nhớ. Lưu ý rằng phản hồi sẽ được "thu thập" lần sau thông qua vòng lặp. Đây là lý do tại sao chủ phải gửi một chuyển khoản "giả" cuối cùng để nhận được trả lời cuối cùng.

Trong ví dụ của tôi, tôi đang sử dụng vòng lặp chính để đơn giản phát hiện khi SS lên cao và xóa lệnh đã lưu. Theo cách đó, khi SS được kéo xuống mức thấp cho giao dịch tiếp theo, byte đầu tiên được coi là byte lệnh.

Đáng tin cậy hơn, điều này sẽ được thực hiện với một ngắt. Nghĩa là, bạn sẽ kết nối vật lý SS với một trong các đầu vào ngắt (ví dụ: trên Uno, kết nối chân 10 (SS) với chân 2 (đầu vào ngắt) hoặc sử dụng ngắt thay đổi pin trên chân 10.

Sau đó, ngắt có thể được sử dụng để thông báo khi SS bị kéo xuống thấp hoặc cao.

Nô lệ (ví dụ)

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

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);

  }  // 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)
  {

  // if SPI not active, clear current command
  if (digitalRead (SS) == HIGH)
    command = 0;
  }  // end of loop

Ví dụ đầu ra

Adding results:
25
32
48
57
Subtracting results:
2
9
25
34
Adding results:
25
32
48
57
Subtracting results:
2
9
25
34

Đầu ra phân tích logic

Điều này cho thấy thời gian giữa gửi và nhận trong đoạn mã trên:

SPI chủ và thời gian nô lệ


Chức năng mới trong IDE 1.6.0 trở đi

Phiên bản 1.6.0 của IDE đã thay đổi cách thức hoạt động của SPI. Bạn vẫn cần phải làm SPI.begin() trước khi sử dụng SPI. Điều đó thiết lập phần cứng SPI. Tuy nhiên bây giờ, khi bạn là về để bắt đầu giao tiếp với một nô lệ bạn cũng làm SPI.beginTransaction()để thiết lập SPI (đối với nô lệ này) với đúng:

  • Tốc độ đồng hồ
  • Thứ tự bit
  • Đồng hồ pha và cực

Khi bạn đã hoàn thành giao tiếp với nô lệ, bạn gọi SPI.endTransaction(). Ví dụ:

SPI.beginTransaction (SPISettings (2000000, MSBFIRST, SPI_MODE0));
digitalWrite (SS, LOW);        // assert Slave Select
byte foo = SPI.transfer (42);  // do a transfer
digitalWrite (SS, HIGH);       // de-assert Slave Select
SPI.endTransaction ();         // transaction over

Tại sao nên sử dụng SPI?

Tôi sẽ thêm một câu hỏi sơ bộ: khi nào / tại sao bạn sẽ sử dụng SPI? Nhu cầu cấu hình đa chủ hoặc một số lượng rất lớn nô lệ sẽ nghiêng quy mô về phía I2C.

Đây là một câu hỏi tuyệt vời. Câu trả lời của tôi là:

  • Một số thiết bị (khá nhiều) chỉ hỗ trợ phương thức chuyển SPI. Ví dụ, thanh ghi dịch chuyển đầu ra 74HC595, thanh ghi dịch chuyển đầu vào 74HC165, trình điều khiển LED MAX7219 và khá nhiều dải đèn LED mà tôi đã thấy. Vì vậy, bạn có thể sử dụng nó vì thiết bị đích chỉ hỗ trợ nó.
  • SPI thực sự là phương pháp nhanh nhất có sẵn trên chip Atmega328 (và tương tự). Tốc độ nhanh nhất được trích dẫn ở trên là 888.888 byte mỗi giây. Sử dụng I 2 C, bạn chỉ có thể nhận được khoảng 40.000 byte mỗi giây. Chi phí hoạt động của I 2 C khá lớn và nếu bạn đang cố gắng giao diện thực sự nhanh chóng, SPI là lựa chọn ưu tiên. Khá nhiều họ chip (ví dụ: MCP23017 và MCP23S17) thực sự hỗ trợ cả I 2 C và SPI để bạn thường có thể chọn giữa tốc độ và khả năng có nhiều thiết bị trên một xe buýt.
  • Cả hai thiết bị SPI và I 2 C đều được hỗ trợ phần cứng trên Atmega328, do đó bạn có thể hình dung được việc chuyển đổi qua SPI đồng thời với I 2 C giúp tăng tốc độ.

Cả hai phương pháp đều có vị trí của chúng. I 2 C cho phép bạn kết nối nhiều thiết bị với một xe buýt (hai dây, cộng với mặt đất), vì vậy nó sẽ là lựa chọn ưu tiên nếu bạn cần thẩm vấn một số lượng đáng kể các thiết bị, có lẽ không thường xuyên. Tuy nhiên, tốc độ của SPI có thể phù hợp hơn cho các tình huống bạn cần xuất nhanh (ví dụ: dải đèn LED) hoặc đầu vào nhanh (ví dụ: bộ chuyển đổi ADC).


Người giới thiệu


Bạn sẽ che đậy sự kỳ lạ đó là SPI của Do? Trường hợp cấu hình của cổng SPI được gắn với chân SS được sử dụng và có các chân SS phần cứng (IIRC) 4 được gán cho cổng SPI?
Majenko

Điểm khác về lựa chọn: đôi khi bạn thực sự không có lựa chọn nào vì cảm biến bạn muốn / cần sử dụng chỉ có sẵn dưới dạng I2C.
Igor Stoppa

Are you going to cover the weirdness that is the Due's SPI?- Tôi không biết gì về SPI của Do (ngoài việc cho rằng giao thức tổng thể là như nhau). Bạn được chào đón để thêm một câu trả lời bao gồm khía cạnh của nó.
Nick Gammon

Khi nào audiobook của câu trả lời này xuất hiện, và bạn sẽ tự đọc nó chứ?)
AMADANON Inc.

1
@AMADANONInc. Có lẽ là một video âm nhạc? Hay một hình ảnh động? Tôi không chắc giọng Úc của tôi có thể hiểu được không. : P
Nick Gammon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.