आप एक Arduino पर SPI का उपयोग कैसे करते हैं?


44

Arduino Uno, Mega2560, लियोनार्डो और इसी तरह के बोर्डों के संदर्भ में:

  • एसपीआई कैसे काम करता है?
  • SPI कितनी तेज है?
  • मैं एक स्वामी और दास के बीच कैसे जुड़ूं?
  • मैं एक SPI गुलाम कैसे बनाऊं?

कृपया ध्यान दें: यह एक संदर्भ प्रश्न के रूप में है।


आप इस संबंधित सवाल का जवाब कर सकते हैं arduino.stackexchange.com/questions/60703/...
qwr

जवाबों:


80

एसपीआई का परिचय

सीरियल परिधीय इंटरफेस बस (एसपीआई) इंटरफ़ेस उच्च गति से कम दूरी पर कई उपकरणों के बीच संचार के लिए प्रयोग किया जाता है, और।

आमतौर पर एक एकल "मास्टर" डिवाइस है, जो संचार शुरू करता है और उस घड़ी की आपूर्ति करता है जो डेटा ट्रांसफर दर को नियंत्रित करता है। एक या अधिक दास हो सकते हैं। एक से अधिक दासों के लिए, प्रत्येक का अपना "दास चयन" संकेत होता है, जिसे बाद में वर्णित किया गया है।


एसपीआई संकेत

एक पूर्ण विकसित SPI प्रणाली में आपके पास चार सिग्नल लाइनें होंगी:

  • मास्टर आउट, स्लेव इन ( MOSI ) - जो मास्टर से दास के लिए जाने वाला डेटा है
  • मास्टर इन, स्लेव आउट ( MISO ) - जो गुलाम से मास्टर तक जाने वाला डेटा है
  • सीरियल क्लॉक ( एससीके ) - जब यह मास्टर और गुलाम दोनों को अगले बिट का नमूना देता है
  • गुलाम चयन ( एसएस ) - यह एक विशेष दास को "सक्रिय" जाने के लिए कहता है

जब कई दास MISO सिग्नल से जुड़े होते हैं तो उनसे त्रिकोणीय स्थिति की उम्मीद की जाती है (उच्च प्रतिबाधा रखें) कि MISO लाइन तब तक चुनी जाती है जब तक कि वे स्लेव सेलेक्ट नहीं हो जाते। आम तौर पर स्लेव सेलेक्ट (SS) का जोर कम होता है। यही है, यह सक्रिय कम है। एक बार जब एक विशेष दास का चयन किया जाता है, तो उसे MISO लाइन को आउटपुट के रूप में कॉन्फ़िगर करना चाहिए ताकि वह मास्टर को डेटा भेज सके।

इस छवि से पता चलता है कि डेटा का आदान-प्रदान एक बाइट के रूप में किया जाता है:

एसपीआई प्रोटोकॉल 4 संकेत दिखा रहा है

ध्यान दें कि तीन सिग्नल मास्टर (MOSI, SCK, SS) से आउटपुट हैं और एक इनपुट (MISO) है।


समय

घटनाओं का क्रम है:

  • SS यह जोर देने और दास को सक्रिय करने के लिए कम हो जाता है
  • SCKलाइन से संकेत मिलता है जब डेटा लाइनों नमूना किया जाना चाहिए टॉगल
  • डेटा को मास्टर और स्लेव दोनों द्वारा नमूना किया जाता है, जिसके प्रमुख किनारे SCK(डिफ़ॉल्ट घड़ी चरण का उपयोग करके)
  • मास्टर और स्लेव दोनों अगले बिट के लिए (डिफ़ॉल्ट घड़ी चरण का उपयोग करके), या यदि आवश्यक हो , के पीछे के किनारे के लिए तैयार करते हैंSCKMISOMOSI
  • एक बार ट्रांसमिशन खत्म हो गया है (संभवतः कई बाइट्स भेजे जाने के बाद) फिर SSइसे डी-एसेर करने के लिए उच्च जाता है

ध्यान दें कि:

  • सबसे महत्वपूर्ण बिट पहले भेजा जाता है (डिफ़ॉल्ट रूप से)
  • डेटा उसी त्वरित (पूर्ण द्वैध) पर भेजा और प्राप्त किया जाता है

क्योंकि डेटा को उसी घड़ी पल्स पर भेजा और प्राप्त किया जाता है, इसलिए दास के लिए तुरंत मास्टर को जवाब देना संभव नहीं है। एसपीआई प्रोटोकॉल आमतौर पर मास्टर से एक ट्रांसमिशन पर डेटा का अनुरोध करने की उम्मीद करते हैं, और बाद में एक प्रतिक्रिया प्राप्त करते हैं।

Arduino पर SPI लाइब्रेरी का उपयोग करते हुए, एक ही हस्तांतरण कोड में इस तरह दिखता है:

 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

आउटपुट के लिए वायरिंग केवल SPI

उपरोक्त कोड (जो केवल भेजता है) का उपयोग आउटपुट सीरियल शिफ्ट रजिस्टर को चलाने के लिए किया जा सकता है। ये आउटपुट-ओनली डिवाइस हैं, इसलिए हमें किसी भी आने वाले डेटा के बारे में चिंता करने की आवश्यकता नहीं है। उनके मामले में एसएस पिन को "स्टोर" या "लैच" पिन कहा जा सकता है।

एसपीआई प्रोटोकॉल 3 संकेत दिखा रहा है

इसका उदाहरण 74HC595 सीरियल शिफ्ट रजिस्टर और विभिन्न एलईडी स्ट्रिप्स हैं, बस एक जोड़े का उल्लेख करना है। उदाहरण के लिए, MAX7219 चिप द्वारा संचालित यह 64 पिक्सेल एलईडी डिस्प्ले:

64 पिक्सेल एलईडी डिस्प्ले

इस मामले में आप देख सकते हैं कि बोर्ड निर्माता ने थोड़े अलग संकेत नामों का उपयोग किया है:

  • दीन (डेटा में) MOSI (मास्टर आउट, गुलाम में) है
  • सीएस (चिप चयन) एसएस (दास चयन) है
  • सीएलके (क्लॉक) एससीके (सीरियल क्लॉक)

अधिकांश बोर्ड एक समान पैटर्न का पालन करेंगे। कभी-कभी DIN सिर्फ DI (डेटा इन) होता है।

यहाँ एक और उदाहरण है, इस बार एक 7-खंड एलईडी डिस्प्ले बोर्ड (MAX7219 चिप पर आधारित):

7-सेगमेंट एलईडी डिस्प्ले

यह अन्य बोर्ड की तरह बिल्कुल उसी सिग्नल नामों का उपयोग करता है। इन दोनों मामलों में आप देख सकते हैं कि बोर्ड को केवल 5 तारों की आवश्यकता है, तीन SPI, प्लस पावर और ग्राउंड के लिए।


घड़ी का चरण और ध्रुवता

एसपीआई घड़ी का नमूना लेने के चार तरीके हैं।

एसपीआई प्रोटोकॉल घड़ी की दालों की ध्रुवता पर बदलाव के लिए अनुमति देता है। CPOL घड़ी ध्रुवीयता है, और CPHA घड़ी चरण है।

  • मोड 0 (डिफ़ॉल्ट) - घड़ी सामान्य रूप से कम होती है (CPOL = 0), और डेटा को निम्न से उच्च (अग्रणी किनारे) (CPHA = 0) में परिवर्तित किया जाता है।
  • मोड 1 - घड़ी सामान्य रूप से कम (CPOL = 0) होती है, और डेटा को उच्च से निम्न (अनुगामी किनारे) (CPHA = 1) के संक्रमण पर नमूना लिया जाता है
  • मोड 2 - घड़ी सामान्य रूप से उच्च (CPOL = 1) है, और डेटा को उच्च से निम्न (अग्रणी किनारे) (CPHA = 0) में संक्रमण पर नमूना लिया जाता है
  • मोड 3 - घड़ी सामान्य रूप से उच्च (CPOL = 1) है, और डेटा को निम्न से उच्च (अनुगामी किनारे) (CPHA = 1) के संक्रमण पर नमूना लिया जाता है

इनका वर्णन इस ग्राफिक में किया गया है:

एसपीआई घड़ी चरण और ध्रुवीयता

आपको चरण और ध्रुवता को सही करने के लिए अपने डिवाइस के लिए डेटाशीट का संदर्भ लेना चाहिए। आमतौर पर एक आरेख होगा जो दिखाता है कि घड़ी का नमूना कैसे लिया जाए। उदाहरण के लिए, 74HC595 चिप के लिए डेटशीट से:

74HC595 घड़ी

जैसा कि आप देख सकते हैं कि घड़ी सामान्य रूप से कम (CPOL = 0) है और इसे प्रमुख किनारे (CPHA = 0) पर नमूना लिया गया है इसलिए यह SPI मोड 0 है।

आप इस तरह कोड में घड़ी की ध्रुवता और चरण को बदल सकते हैं (केवल एक को चुनें, निश्चित रूप से):

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

यह विधि Arduino IDE के बाद के संस्करणों में 1.6.0 में निकाली गई है। हाल के संस्करणों के लिए आप 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

फिर से, यह Arduino IDE के 1.6.0 संस्करणों में अपग्रेड किया गया है। हाल के संस्करणों के लिए आप SPI.beginTransactionकॉल में बिट ऑर्डर बदलते हैं , जैसे:

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

गति

एसपीआई के लिए डिफ़ॉल्ट सेटिंग सिस्टम घड़ी की गति को चार से विभाजित करने के लिए उपयोग करना है, अर्थात, प्रत्येक 250 एनएस में एक एसपीआई क्लॉक पल्स, एक 16 मेगाहर्ट्ज सीपीयू घड़ी मानकर। आप setClockDividerइस तरह का उपयोग करके घड़ी विभक्त को बदल सकते हैं :

SPI.setClockDivider (divider);

जहां "विभक्त" में से एक है:

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

सबसे तेज़ दर है "विभाजित करके 2" या एक एसपीआई घड़ी पल्स हर 125 एनएस, एक 16 मेगाहर्ट्ज सीपीयू घड़ी मान। इसलिए यह एक बाइट संचारित करने के लिए 8 * 125 ns या 1 *s लगेगा।

यह विधि Arduino IDE के बाद के संस्करणों में 1.6.0 में निकाली गई है। हाल के संस्करणों के लिए आप SPI.beginTransactionकॉल में स्थानांतरण गति को बदलते हैं , जैसे:

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

हालाँकि अनुभवजन्य परीक्षण से पता चलता है कि बाइट्स के बीच दो घड़ी की दालों का होना आवश्यक है, इसलिए बाइट्स को जिस अधिकतम दर पर देखा जा सकता है, वह प्रत्येक का 1.125 (है (2 के क्लॉक डिवाइडर के साथ)।

संक्षेप में, प्रत्येक बाइट को 1.125 125 प्रति (16 मेगाहर्ट्ज घड़ी के साथ) प्रति 1 / 1.125, की सैद्धांतिक अधिकतम अंतरण दर, या 888,888 बाइट प्रति सेकंड (ओवरहेड को छोड़कर एसएस कम और इतने पर छोड़कर) की अधिकतम दर पर भेजा जा सकता है। पर)।


Arduino से कनेक्ट कर रहा है

अरुडिनो उनो

डिजिटल पिंस 10 से 13 के माध्यम से कनेक्ट करना:

Arduino Uno SPI पिंस

ICSP हेडर के माध्यम से कनेक्ट करना:

ICSP पिनआउट्स - Uno

ICSP हेडर

अरुडिनो अटमेगा 2560

50 से 52 तक डिजिटल पिन के माध्यम से जुड़ना:

Arduino Mega2560 SPI पिन

आप ऊपर Uno के समान ICSP हैडर का भी उपयोग कर सकते हैं।

अरुडिनो लियोनार्डो

लियोनार्डो और माइक्रो, यूआई और मेगा के विपरीत, डिजिटल पिंस पर एसपीआई पिन को उजागर नहीं करते हैं। आपका एकमात्र विकल्प आईसीएसपी हेडर पिन का उपयोग करना है, जैसा कि ऊनो के लिए ऊपर वर्णित है।


एकाधिक दास

एक मास्टर कई दासों के साथ संवाद कर सकता है (हालांकि एक समय में केवल एक ही)। यह एसएस को एक गुलाम के रूप में बताकर और बाकी सभी के लिए यह दावा करता है। जिस दास ने एसएस का दावा किया है (आमतौर पर इसका मतलब है कि कम है) अपने MISO पिन को आउटपुट के रूप में कॉन्फ़िगर करता है ताकि गुलाम, और वह गुलाम अकेले ही मास्टर को जवाब दे सके। अन्य दास किसी भी आने वाली घड़ी दालों की उपेक्षा करते हैं यदि एसएस मुखर नहीं है। इस प्रकार आपको प्रत्येक दास के लिए एक अतिरिक्त संकेत की आवश्यकता है, जैसे:

एकाधिक एसपीआई दास

इस ग्राफिक में आप देख सकते हैं कि MISO, MOSI, SCK दोनों दासों के बीच साझा किए जाते हैं, हालांकि प्रत्येक दास का अपना SS (दास चयन) संकेत होता है।


प्रोटोकॉल

SPI कल्पना प्रोटोकॉल को इस तरह निर्दिष्ट नहीं करती है, इसलिए यह व्यक्तिगत मास्टर / दास की जोड़ी पर निर्भर है कि डेटा का क्या अर्थ है। जब तक आप एक साथ बाइट भेज और प्राप्त कर सकते हैं, प्राप्त बाइट भेजे गए बाइट का सीधा जवाब नहीं हो सकता है (जैसा कि उन्हें एक साथ इकट्ठा किया जा रहा है)।

इसलिए एक अनुरोध भेजने के लिए एक छोर के लिए यह अधिक तर्कसंगत होगा (उदाहरण। 4 का मतलब "डिस्क निर्देशिका को सूचीबद्ध कर सकता है") और फिर पूर्ण प्रतिक्रिया प्राप्त होने तक स्थानांतरण (शायद सिर्फ शून्य को बाहर की ओर भेजना) करें। प्रतिक्रिया एक नई रेखा या 0x00 वर्ण के साथ समाप्त हो सकती है।

अपने गुलाम डिवाइस के लिए डेटाशीट पढ़ें कि यह क्या प्रोटोकॉल अनुक्रम की उम्मीद करता है।


एसपीआई को गुलाम कैसे बनाया जाए

पहले का उदाहरण अरुडिनो को स्वामी के रूप में दर्शाता है, एक दास डिवाइस को डेटा भेज रहा है। यह उदाहरण दिखाता है कि कैसे Arduino गुलाम हो सकता है।

हार्डवेयर सेटअप

एक दूसरे से जुड़े निम्नलिखित पिन के साथ दो Arduino Unos कनेक्ट करें:

  • 10 (एसएस)
  • 11 (MOSI)
  • 12 (MISO)
  • 13 (SCK)

  • + 5 v (यदि आवश्यक हो)

  • GND (सिग्नल वापसी के लिए)

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

दास पूरी तरह से बाधित-संचालित है, इस प्रकार यह अन्य सामान कर सकता है। आने वाले एसपीआई डेटा को एक बफर में एकत्र किया जाता है, और "महत्वपूर्ण बाइट" (इस मामले में एक नई पंक्ति) आने पर एक ध्वज सेट होता है। यह दास को डेटा प्राप्त करने और चालू करने के लिए कहता है।

एसपीआई का उपयोग करके मास्टर को दास से जोड़ने का उदाहरण

Arduino SPI मास्टर और गुलाम


दास से प्रतिक्रिया कैसे प्राप्त करें

ऊपर दिए गए कोड से, जो एक स्लाइस में SPI मास्टर से डेटा भेजता है, नीचे उदाहरण एक गुलाम को डेटा भेजने से पता चलता है, यह उसके साथ कुछ कर रहा है, और एक प्रतिक्रिया लौटाता है।

गुरु ऊपर के उदाहरण के समान है। हालांकि एक महत्वपूर्ण बिंदु यह है कि हमें थोड़ी देरी (20 माइक्रोसेकंड की तरह कुछ) जोड़ने की आवश्यकता है। अन्यथा दास के पास आने वाले डेटा पर प्रतिक्रिया करने और उसके साथ कुछ करने का मौका नहीं होता है।

उदाहरण "कमांड" भेजना दिखाता है। इस स्थिति में "a" (कुछ जोड़ें) या "s" (कुछ घटाएँ)। यह यह दिखाना है कि दास वास्तव में डेटा के साथ कुछ कर रहा है।

लेन-देन शुरू करने के लिए दास-चयन (एसएस) का दावा करने के बाद, मास्टर आदेश भेजता है, उसके बाद किसी भी संख्या में बाइट्स, और फिर लेनदेन को समाप्त करने के लिए एसएस को उठाता है।

एक बहुत महत्वपूर्ण बिंदु यह है कि दास एक ही समय में आने वाली बाइट का जवाब नहीं दे सकता है। प्रतिक्रिया अगले बाइट में होना है। ऐसा इसलिए है क्योंकि जो बिट्स भेजे जा रहे हैं, और जो बिट्स प्राप्त हो रहे हैं, उन्हें एक साथ भेजा जा रहा है। इस प्रकार कुछ संख्याओं को जोड़ने के लिए हमें पाँच हस्तांतरणों की आवश्यकता है, जैसे:

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

पहले हम 10 नंबर पर कार्रवाई का अनुरोध करते हैं। लेकिन हमें अगले ट्रांसफर (17 के लिए एक) तक कोई प्रतिक्रिया नहीं मिलती है। हालाँकि "10" उत्तर के लिए सेट किया जाएगा। अंत में हम एक "डमी" नंबर 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

दास के लिए कोड मूल रूप से रुकावट दिनचर्या में लगभग सब कुछ करता है (जब आने वाले एसपीआई डेटा आता है)। यह आने वाली बाइट लेता है, और याद किए गए "कमांड बाइट" के अनुसार जोड़ या घटाता है। ध्यान दें कि अगली बार लूप के माध्यम से प्रतिक्रिया "एकत्र" की जाएगी। यही कारण है कि मास्टर को अंतिम उत्तर पाने के लिए एक अंतिम "डमी" हस्तांतरण भेजना पड़ता है।

मेरे उदाहरण में मैं मुख्य लूप का उपयोग कर रहा हूं ताकि एसएस उच्च हो, और सहेजे गए कमांड को साफ कर सके। इस तरह, जब एसएस को अगले लेनदेन के लिए फिर से कम खींचा जाता है, तो पहले बाइट को कमांड बाइट माना जाता है।

अधिक मज़बूती से, यह एक रुकावट के साथ किया जाएगा। यही है, आप SS को बाधित इनपुट्स में से एक से जोड़ेंगे (जैसे, Uno पर, pin 10 (SS) को pin 2 से कनेक्ट करें (एक इंटरप्ट इनपुट)), या pin 10 पर पिन-चेंज इंटरप्ट का उपयोग करें।

तब व्यवधान का उपयोग यह देखने के लिए किया जा सकता है कि एसएस को कम या उच्च खींचा जा रहा है।

दास (उदाहरण)

// 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

तर्क विश्लेषक उत्पादन

यह उपरोक्त कोड में भेजने और प्राप्त करने के बीच के समय को दर्शाता है:

एसपीआई मास्टर और गुलाम समय


आईडीई 1.6.0 में बाद में नई कार्यक्षमता

आईडीई के संस्करण 1.6.0 ने एसपीआई के काम करने के तरीके को एक हद तक बदल दिया है। आपको अभी भी SPI.begin() SPI का उपयोग करने से पहले करने की आवश्यकता है । यह SPI हार्डवेयर सेट करता है। हालाँकि अब, जब आप एक दास के साथ संवाद शुरू करने वाले होते हैं, तो आप सही के साथ SPI (इस दास के लिए) स्थापित करने के लिए भी करते हैं SPI.beginTransaction():

  • घड़ी की गति
  • बिट क्रम
  • घड़ी का चरण और ध्रुवता

जब आप दास के साथ संवाद कर रहे होते हैं, तो आप कॉल करते हैं 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 का उपयोग क्यों करें?

मैं एक प्रारंभिक प्रश्न जोड़ूंगा: कब / क्यों आप SPI का उपयोग करेंगे? मल्टी-मास्टर कॉन्फ़िगरेशन या दासों की एक बहुत बड़ी संख्या की आवश्यकता I2C की ओर पैमाने को झुकाएगी।

यह एक अच्छा सवाल है। मेरे उत्तर हैं:

  • कुछ डिवाइस (काफी कुछ) केवल SPI हस्तांतरण विधि का समर्थन करते हैं। उदाहरण के लिए 74HC595 आउटपुट शिफ्ट रजिस्टर, 74HC165 इनपुट शिफ्ट रजिस्टर, MAX7219 एलईडी ड्राइवर, और काफी कुछ एलईडी स्ट्रिप्स जो मैंने देखी हैं। इसलिए, आप इसका उपयोग कर सकते हैं क्योंकि लक्ष्य डिवाइस केवल इसका समर्थन करता है।
  • एसपीआई वास्तव में एटमेगा 328 (और समान) चिप्स पर उपलब्ध सबसे तेज़ विधि है। ऊपर उद्धृत सबसे तेज दर 888,888 बाइट्स प्रति सेकंड है। I 2 C का उपयोग करके आप केवल 40,000 बाइट्स प्रति सेकंड प्राप्त कर सकते हैं। I 2 C का ओवरहेड काफी पर्याप्त है, और यदि आप वास्तव में जल्दी से इंटरफ़ेस करने की कोशिश कर रहे हैं, तो SPI पसंदीदा विकल्प है। कुछ चिप परिवारों (जैसे। MCP23017 और MCP23S17) वास्तव में I 2 C और SPI दोनों का समर्थन करते हैं, इसलिए आप अक्सर गति के बीच चयन कर सकते हैं, और एक ही बस में कई डिवाइस रखने की क्षमता।
  • SPI और I 2 C डिवाइस दोनों को Atmega328 पर हार्डवेयर में सपोर्ट किया गया है, ताकि आप I 2 C के साथ एक साथ SPI के माध्यम से एक ट्रांसफर कर सकें ।

दोनों विधियों का अपना स्थान है। I 2 C आपको कई उपकरणों को एक बस (दो तारों, प्लस ग्राउंड) से जोड़ने की सुविधा देता है, इसलिए यह एक पसंदीदा विकल्प होगा यदि आपको पर्याप्त संख्या में उपकरणों की पूछताछ करने की आवश्यकता होती है, शायद काफी अनैतिक रूप से। हालांकि एसपीआई की गति उन स्थितियों के लिए अधिक प्रासंगिक हो सकती है जहां आपको तेजी से आउटपुट करने की आवश्यकता होती है (जैसे। एक एलईडी पट्टी) या तेजी से इनपुट (जैसे। एक एडीसी कनवर्टर)।


संदर्भ


क्या आप विचित्रता को कवर करने जा रहे हैं जो कि ड्यू एसपीआई है? जहाँ SPI पोर्ट का कॉन्फ़िगरेशन उपयोग किए गए SS पिन से जुड़ा होता है, और वहाँ (IIRC) 4 हार्डवेयर SS पिन होते हैं, जिन्हें SPI पोर्ट को सौंपा जाता है?
Majenko

चयन के बारे में अन्य बिंदु: कभी-कभी आपके पास वास्तव में कोई विकल्प नहीं होता है क्योंकि आप जो सेंसर चाहते हैं / उपयोग करने की आवश्यकता होती है वह केवल I2C के रूप में उपलब्ध है।
इगोर स्टोपा

Are you going to cover the weirdness that is the Due's SPI?- मुझे ड्यू के एसपीआई के बारे में कुछ भी पता नहीं है (इसके अलावा समग्र प्रोटोकॉल समान है)। उस पहलू को कवर करने वाले उत्तर को जोड़ने के लिए आपका स्वागत है।
निक गैमन

जब इस उत्तर का ऑडियोबुक सामने आ रहा है, और क्या आप इसे स्वयं पढ़ रहे होंगे?)
AMADANON Inc. 20

1
@AMADANONInc। शायद एक संगीत वीडियो? या एक एनीमेशन? मुझे यकीन नहीं है कि मेरा ऑस्ट्रेलियाई उच्चारण समझ में आ जाएगा। : पी
निक गैमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.