อ้างอิงถึง Arduino Uno, Mega2560, Leonardo และบอร์ดที่คล้ายกัน:
- SPI ทำงานอย่างไร
- SPI เร็วแค่ไหน
- ฉันจะเชื่อมต่อระหว่างนายกับทาสได้อย่างไร?
- ฉันจะสร้างทาส SPI ได้อย่างไร
โปรดทราบ: นี่เป็นคำถามสำหรับการอ้างอิง
อ้างอิงถึง Arduino Uno, Mega2560, Leonardo และบอร์ดที่คล้ายกัน:
โปรดทราบ: นี่เป็นคำถามสำหรับการอ้างอิง
คำตอบ:
อนุกรมอุปกรณ์ต่อพ่วงอินเตอร์เฟสบัส (SPI) อินเตอร์เฟซที่ใช้สำหรับการสื่อสารระหว่างอุปกรณ์หลายในระยะทางสั้น ๆ และที่ความเร็วสูง
โดยทั่วไปจะมีอุปกรณ์ "หลัก" เดียวซึ่งจะเริ่มการสื่อสารและส่งสัญญาณนาฬิกาที่ควบคุมอัตราการถ่ายโอนข้อมูล อาจมีทาสตั้งแต่หนึ่งตัวขึ้นไป สำหรับทาสมากกว่าหนึ่งคนแต่ละคนมีสัญญาณ "ทาสเลือก" ของตัวเองอธิบายไว้ในภายหลัง
ในระบบ SPI แบบเต็มคุณจะมีสี่สายสัญญาณ:
เมื่อทาสหลายตัวเชื่อมต่อกับสัญญาณ MISO พวกเขาคาดว่าจะเป็นสามสถานะ (เก็บที่อิมพีแดนซ์สูง) ที่เส้น MISO จนกว่าพวกเขาจะถูกเลือกโดย Slave Select ที่ถูกเลือก โดยปกติ Slave Select (SS) จะต่ำเพื่อยืนยัน นั่นคือมันใช้งานต่ำ เมื่อเลือกทาสเฉพาะควรกำหนดค่าสาย MISO เป็นเอาท์พุทเพื่อให้สามารถส่งข้อมูลไปยังต้นแบบ
รูปภาพนี้แสดงวิธีการแลกเปลี่ยนข้อมูลเมื่อส่งหนึ่งไบต์:
โปรดทราบว่าสัญญาณทั้งสามเป็นสัญญาณจากอาจารย์ (MOSI, SCK, SS) และสัญญาณหนึ่งเป็นสัญญาณเข้า (MISO)
ลำดับเหตุการณ์คือ:
SS
ต่ำลงเพื่อยืนยันและเปิดใช้งานทาสSCK
สายสลับเพื่อระบุว่าเมื่อสายข้อมูลที่ควรจะเก็บตัวอย่างSCK
(ใช้เฟสนาฬิกาเริ่มต้น)SCK
(ใช้เฟสนาฬิกาเริ่มต้น) โดยการเปลี่ยนMISO
/ MOSI
หากจำเป็นSS
จะสูงเพื่อยกเลิกการยืนยันโปรดทราบว่า:
เนื่องจากข้อมูลถูกส่งและรับในพัลส์นาฬิกาเดียวกันมันเป็นไปไม่ได้ที่ทาสจะตอบกลับนายทันที โปรโตคอล SPI มักจะคาดหวังว่าเจ้านายจะขอข้อมูลจากการส่งครั้งเดียวและได้รับการตอบกลับในครั้งต่อไป
การใช้ไลบรารี SPI บน Arduino การถ่ายโอนครั้งเดียวจะมีลักษณะดังนี้ในรหัส:
byte outgoing = 0xAB;
byte incoming = SPI.transfer (outgoing);
ตัวอย่างการส่งเท่านั้น (ไม่สนใจข้อมูลที่เข้ามา):
#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
รหัสข้างต้น (ซึ่งส่งเท่านั้น) อาจถูกใช้เพื่อขับเคลื่อนการลงทะเบียนซีเรียลเอาต์พุตอนุกรม อุปกรณ์เหล่านี้เป็นอุปกรณ์เอาท์พุทเท่านั้นดังนั้นเราจึงไม่ต้องกังวลเกี่ยวกับข้อมูลขาเข้าใด ๆ ในกรณีของพวกเขาพิน SS อาจเรียกว่า "store" หรือ "latch" pin
ตัวอย่างของสิ่งนี้คือการลงทะเบียนซีเรียล 74HC595 และแถบ LED ต่าง ๆ เพียงพูดถึงสองสามอย่าง ตัวอย่างเช่นจอแสดงผล LED 64 พิกเซลนี้ขับเคลื่อนด้วยชิป MAX7219:
ในกรณีนี้คุณจะเห็นว่าผู้ผลิตบอร์ดใช้ชื่อสัญญาณที่แตกต่างกันเล็กน้อย:
บอร์ดส่วนใหญ่จะเป็นไปตามรูปแบบที่คล้ายกัน บางครั้ง DIN เป็นเพียง DI (Data In)
นี่เป็นอีกตัวอย่างหนึ่งคราวนี้บอร์ดแสดงผล LED 7 ส่วน (ตามชิป MAX7219):
ใช้ชื่อสัญญาณตรงกับบอร์ดอื่น ๆ ในทั้งสองกรณีนี้คุณจะเห็นได้ว่าบอร์ดต้องการสายไฟ 5 เส้นเท่านั้นสายไฟสามสายสำหรับ SPI รวมทั้งพลังงานและกราวด์
มีสี่วิธีที่คุณสามารถสุ่มตัวอย่างนาฬิกา SPI ได้
โปรโตคอล SPI อนุญาตให้มีการเปลี่ยนแปลงในขั้วของพัลส์นาฬิกา CPOL เป็นขั้วนาฬิกาและ CPHA เป็นเฟสสัญญาณนาฬิกา
สิ่งเหล่านี้แสดงในกราฟิกนี้:
คุณควรอ้างอิงแผ่นข้อมูลสำหรับอุปกรณ์ของคุณเพื่อให้เฟสและขั้วถูกต้อง โดยปกติจะมีไดอะแกรมซึ่งแสดงวิธีการสุ่มตัวอย่างนาฬิกา ตัวอย่างเช่นจากแผ่นข้อมูลสำหรับชิป 74HC595:
ตามที่คุณเห็นว่านาฬิกาอยู่ในระดับต่ำ (CPOL = 0) และถูกสุ่มตัวอย่างที่ขอบนำ (CPHA = 0) ดังนั้นนี่จึงเป็นโหมด SPI 0
คุณสามารถเปลี่ยนขั้วนาฬิกาและเฟสเป็นรหัสได้เช่นนี้ (เลือกอย่างใดอย่างหนึ่งเท่านั้น):
SPI.setDataMode (SPI_MODE0);
SPI.setDataMode (SPI_MODE1);
SPI.setDataMode (SPI_MODE2);
SPI.setDataMode (SPI_MODE3);
วิธีนี้เลิกใช้ในรุ่น 1.6.0 เป็นต้นไปของ Arduino IDE สำหรับรุ่นล่าสุดคุณเปลี่ยนโหมดนาฬิกาในการSPI.beginTransaction
โทรเช่นนี้
SPI.beginTransaction (SPISettings (2000000, MSBFIRST, SPI_MODE0)); // 2 MHz clock, MSB first, mode 0
ค่าเริ่มต้นคือบิตที่สำคัญที่สุดก่อนอย่างไรก็ตามคุณสามารถบอกให้ฮาร์ดแวร์ประมวลผลบิตที่มีนัยสำคัญน้อยที่สุดก่อนเช่นนี้:
SPI.setBitOrder (LSBFIRST); // least significant bit first
SPI.setBitOrder (MSBFIRST); // most significant bit first
อีกครั้งสิ่งนี้เลิกใช้แล้วในรุ่น 1.6.0 เป็นต้นไปของ Arduino IDE สำหรับรุ่นล่าสุดคุณเปลี่ยนลำดับบิตในการSPI.beginTransaction
โทรเช่นนี้
SPI.beginTransaction (SPISettings (1000000, LSBFIRST, SPI_MODE2)); // 1 MHz clock, LSB first, mode 2
การตั้งค่าเริ่มต้นสำหรับ SPI คือการใช้ความเร็วสัญญาณนาฬิกาของระบบหารด้วยสี่นั่นคือหนึ่งนาฬิกา SPI พัลส์ทุก 250 ns สมมติว่านาฬิกาซีพียู 16 MHz คุณสามารถเปลี่ยนตัวแบ่งนาฬิกาโดยใช้setClockDivider
ดังนี้:
SPI.setClockDivider (divider);
โดยที่ "ตัวแบ่ง" เป็นหนึ่งใน:
อัตราที่เร็วที่สุดคือ "หารด้วย 2" หรือหนึ่งพัลส์นาฬิกา SPI ทุก ๆ 125 ns โดยถือว่านาฬิกาซีพียู 16 MHz ดังนั้นจะใช้เวลา 8 * 125 ns หรือ 1 tos ในการส่งหนึ่งไบต์
วิธีนี้เลิกใช้ในรุ่น 1.6.0 เป็นต้นไปของ Arduino IDE สำหรับรุ่นล่าสุดคุณเปลี่ยนความเร็วในการโอนSPI.beginTransaction
สายเช่นนี้:
SPI.beginTransaction (SPISettings (4000000, MSBFIRST, SPI_MODE0)); // 4 MHz clock, MSB first, mode 0
อย่างไรก็ตามการทดสอบเชิงประจักษ์แสดงให้เห็นว่าจำเป็นต้องมีพัลส์นาฬิกาสองอันระหว่างไบต์ดังนั้นอัตราสูงสุดที่สามารถโอเวอร์คล็อกไบต์ได้คือ 1.125 eachs ต่อวินาที (โดยมีตัวแบ่งสัญญาณนาฬิกาเป็น 2)
เพื่อสรุปแต่ละไบต์สามารถส่งในอัตราสูงสุดหนึ่งต่อ 1.125 (s (ด้วยนาฬิกา 16 MHz) ให้อัตราการถ่ายโอนสูงสุดทางทฤษฎีของ 1 / 1.125 µs หรือ 888,888 ไบต์ต่อวินาที (ยกเว้นค่าใช้จ่ายเช่นการตั้งค่า SS ต่ำและดังนั้น บน).
การเชื่อมต่อผ่านหมุดดิจิตอล 10 ถึง 13:
การเชื่อมต่อผ่านส่วนหัว ICSP:
การเชื่อมต่อผ่านพินดิจิตอล 50 ถึง 52:
คุณยังสามารถใช้ส่วนหัว ICSP คล้ายกับ Uno ด้านบน
Leonardo และ Micro ไม่เปิดเผย SPI ของพินดิจิตอลซึ่งแตกต่างจาก Uno และ Mega ตัวเลือกเดียวของคุณคือใช้พินส่วนหัว ICSP ดังที่แสดงไว้ด้านบนสำหรับ Uno
ต้นแบบสามารถสื่อสารกับทาสหลายคน (ครั้งละเพียงคนเดียว) มันทำเช่นนี้โดยการเข้าไปยุ่งกับเอสเอสอสำหรับทาสคนหนึ่ง ทาสซึ่งมี SS ยืนยัน (โดยปกติหมายถึงต่ำ) กำหนดค่า MISO พินของมันเป็นเอาต์พุตเพื่อให้ทาสและทาสนั้นเพียงอย่างเดียวสามารถตอบสนองต่อต้นแบบได้ ทาสอื่น ๆ จะไม่สนใจสัญญาณนาฬิกาที่เข้ามาหากไม่มีการยืนยัน SS ดังนั้นคุณต้องการสัญญาณเพิ่มเติมหนึ่งสัญญาณสำหรับแต่ละทาสเช่นนี้:
ในภาพนี้คุณจะเห็นได้ว่า MISO, MOSI, SCK จะถูกแชร์ระหว่างทาสทั้งสองอย่างไรก็ตามทาสแต่ละคนมีสัญญาณ SS (เลือกทาส) ของตัวเอง
ข้อมูลจำเพาะ SPI ไม่ได้ระบุโปรโตคอลเช่นนี้ดังนั้นจึงขึ้นอยู่กับการจับคู่ของ Master / Slave แต่ละคนที่จะเห็นด้วยกับความหมายของข้อมูล ในขณะที่คุณสามารถส่งและรับไบต์พร้อมกันได้รับไม่สามารถตอบสนองโดยตรงไปยังไบต์ที่ส่ง (เนื่องจากพวกเขากำลังรวมกันพร้อมกัน)
ดังนั้นมันจะมีเหตุผลมากขึ้นสำหรับปลายด้านหนึ่งที่จะส่งคำขอ (เช่น 4 อาจหมายถึง "รายการไดเรกทอรีของดิสก์") และจากนั้นทำการถ่ายโอน การตอบกลับอาจยุติลงด้วยการขึ้นบรรทัดใหม่หรืออักขระ 0x00
อ่านแผ่นข้อมูลสำหรับอุปกรณ์สลาฟของคุณเพื่อดูว่าโพรโทคอลลำดับใดที่คาดหวัง
ตัวอย่างก่อนหน้านี้แสดงให้เห็นว่า Arduino เป็นต้นแบบการส่งข้อมูลไปยังอุปกรณ์ทาส ตัวอย่างนี้แสดงให้เห็นว่า Arduino สามารถเป็นทาสได้อย่างไร
เชื่อมต่อ Arduino Unos สองตัวพร้อมกับหมุดต่อไปนี้ซึ่งเชื่อมต่อเข้าด้วยกัน:
13 (SCK)
+ 5v (ถ้าจำเป็น)
บน Arduino Mega หมุดมี 50 (MISO), 51 (MOSI), 52 (SCK), และ 53 (SS)
ไม่ว่าในกรณีใด MOSI ที่ปลายด้านหนึ่งจะเชื่อมต่อกับ MOSI ที่ปลายอีกด้านหนึ่งคุณจะไม่สลับไปมา (นั่นคือคุณไม่มี MOSI <-> MISO) ซอฟต์แวร์กำหนดค่าปลายด้านหนึ่งของ MOSI (ต้นแบบปลาย) เป็นเอาต์พุตและปลายอีกด้าน (ปลายทาส) เป็นอินพุต
#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
#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
ทาสนั้นถูกขัดจังหวะโดยสิ้นเชิงดังนั้นมันจึงสามารถทำสิ่งอื่นได้ ข้อมูล SPI ที่เข้ามาจะถูกรวบรวมในบัฟเฟอร์และตั้งค่าสถานะเมื่อ "ไบต์สำคัญ" (ในกรณีนี้มีการขึ้นบรรทัดใหม่) สิ่งนี้จะบอกให้ทาสเริ่มทำงานและเริ่มประมวลผลข้อมูล
ตามจากโค้ดด้านบนซึ่งส่งข้อมูลจากต้นแบบ SPI ไปยังสลาฟตัวอย่างด้านล่างแสดงการส่งข้อมูลไปยังสลาฟให้ทำข้อมูลและส่งคืนการตอบกลับ
ต้นแบบมีลักษณะคล้ายกับตัวอย่างด้านบน อย่างไรก็ตามจุดสำคัญคือเราต้องเพิ่มความล่าช้าเล็กน้อย (บางอย่างเช่น 20 ไมโครวินาที) มิฉะนั้นทาสไม่มีโอกาสโต้ตอบกับข้อมูลที่เข้ามาและทำอะไรกับมัน
ตัวอย่างแสดงการส่งคำสั่ง "" ในกรณีนี้ "a" (เพิ่มบางอย่าง) หรือ "s" (ลบบางอย่าง) นี่คือการแสดงให้เห็นว่าทาสกำลังทำอะไรกับข้อมูล
หลังจากยืนยันการเลือก slave (SS) เพื่อเริ่มต้นการทำธุรกรรมมาสเตอร์จะส่งคำสั่งตามด้วยจำนวนไบต์ใด ๆ แล้วจึงยก SS เพื่อยกเลิกการทำธุรกรรม
จุดสำคัญมากคือทาสไม่สามารถตอบสนองต่อไบต์ขาเข้าในเวลาเดียวกัน การตอบสนองจะต้องอยู่ในไบต์ต่อไป นี่เป็นเพราะบิตที่ถูกส่งและบิตที่ได้รับถูกส่งพร้อมกัน ดังนั้นเมื่อต้องการเพิ่มบางสิ่งลงในหมายเลขสี่เราต้องมีการถ่ายโอนห้าแบบดังนี้:
transferAndWait ('a'); // add command
transferAndWait (10);
a = transferAndWait (17);
b = transferAndWait (33);
c = transferAndWait (42);
d = transferAndWait (0);
ก่อนอื่นเราขอให้ดำเนินการตามข้อ 10 แต่เราไม่ได้รับคำตอบจนกว่าจะถึงการถ่ายโอนครั้งต่อไป (อันที่ 17) อย่างไรก็ตาม "a" จะถูกตั้งค่าเป็นคำตอบที่ 10 ในที่สุดเราก็สิ้นสุดการส่ง "dummy" หมายเลข 0 เพื่อรับการตอบกลับสำหรับ 42
#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
โดยทั่วไปแล้วรหัสสำหรับทาสจะทำเกือบทุกอย่างในรูทีนการขัดจังหวะ (เรียกว่าเมื่อมีข้อมูล SPI ขาเข้ามาถึง) มันใช้เวลาไบต์ที่เข้ามาและเพิ่มหรือลบตามที่จำได้ว่า "คำสั่งไบต์" โปรดทราบว่าการตอบสนองจะ "รวบรวม" ในครั้งถัดไปผ่านลูป นี่คือสาเหตุที่อาจารย์ต้องส่งการถ่ายโอน "จำลอง" ครั้งสุดท้ายเพื่อรับคำตอบสุดท้าย
ในตัวอย่างของฉันฉันใช้ลูปหลักเพียงแค่ตรวจสอบเมื่อ SS สูงและล้างคำสั่งที่บันทึกไว้ ด้วยวิธีนี้เมื่อ SS ถูกดึงต่ำอีกครั้งสำหรับธุรกรรมถัดไปไบต์แรกจะถือเป็นไบต์คำสั่ง
น่าเชื่อถือยิ่งขึ้นสิ่งนี้จะเกิดขึ้นเมื่อมีการขัดจังหวะ นั่นคือคุณจะต้องเชื่อมต่อ SS กับอินพุตอินเตอร์รัปต์อย่างใดอย่างหนึ่ง (เช่นบน Uno เชื่อมต่อพิน 10 (SS) ไปยังพิน 2 (อินเทอร์รัปต์อินพุท) หรือใช้อินเตอร์รัปต์ pin-change บนพิน 10
จากนั้นอินเทอร์รัปต์สามารถใช้สังเกตได้เมื่อ SS ถูกดึงต่ำหรือสูง
// 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
Adding results:
25
32
48
57
Subtracting results:
2
9
25
34
Adding results:
25
32
48
57
Subtracting results:
2
9
25
34
สิ่งนี้แสดงระยะเวลาระหว่างการส่งและรับในรหัสด้านบน:
IDE เวอร์ชัน 1.6.0 มีการเปลี่ยนแปลงวิธีการทำงานของ SPI ในระดับหนึ่ง คุณยังต้องทำ SPI.begin()
ก่อนใช้ SPI ที่ตั้งค่าฮาร์ดแวร์ SPI อย่างไรก็ตามตอนนี้เมื่อคุณกำลังจะเริ่มการสื่อสารกับทาสคุณก็ต้องSPI.beginTransaction()
ทำการตั้งค่า SPI (สำหรับทาสนี้) ด้วยวิธีที่ถูกต้อง:
SPI.endTransaction()
เมื่อคุณทำในการสื่อสารกับทาสที่คุณเรียก ตัวอย่างเช่น:
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
ฉันจะเพิ่มคำถามเบื้องต้นหนึ่งคำถาม: เมื่อใด / ทำไมคุณจะใช้ SPI ความจำเป็นสำหรับการกำหนดค่าหลายหลักหรือทาสจำนวนมากจะเอียงสเกลไปทาง I2C
นี่เป็นคำถามที่ยอดเยี่ยม คำตอบของฉันคือ:
ทั้งสองวิธีมีที่ของพวกเขา I 2 C ช่วยให้คุณเชื่อมต่ออุปกรณ์จำนวนมากกับบัสเดี่ยว (สายสองเส้นและกราวด์) ดังนั้นจึงเป็นตัวเลือกที่ต้องการหากคุณต้องการสอบถามอุปกรณ์จำนวนมากซึ่งอาจไม่บ่อยนัก อย่างไรก็ตามความเร็วของ SPI อาจเกี่ยวข้องกับสถานการณ์ที่คุณต้องการส่งออกอย่างรวดเร็ว (เช่นแถบ LED) หรืออินพุตอย่างรวดเร็ว (เช่นตัวแปลง ADC)
หน้าของฉันเกี่ยวกับ SPI - ยังมีรายละเอียดเกี่ยวกับ SPI บิตกระแทกและใช้ USART เพื่อรับ SPI ฮาร์ดแวร์ตัวที่สองบนชิป Atmega328
Are you going to cover the weirdness that is the Due's SPI?
- ฉันไม่รู้อะไรเกี่ยวกับ SPI ของ Due (นอกเหนือจากการสันนิษฐานว่าโปรโตคอลโดยรวมเหมือนกัน) คุณสามารถเพิ่มการตอบกลับที่ครอบคลุมเนื้อหานั้นได้