2016年5月10日 星期二

Arduino - 使用SPI與週邊設備進行通訊

SPI(Serial peripheral interface)是一種主從式架構的同步資料協定,可以讓多個裝置在短距離互相通訊。

在使用SPI最基本會有四個腳位:

  1. MISO:Master In, Slave Out
  2. MOSI:Master Out, Slave In
  3. SCK(SCLK or Clock):Serial 時脈
  4. SS/CS(Slave Select/Chip Select):LOW表示裝置可以與Master通訊;HIGH表示不與Master通訊
此四個腳位與Arduino UNO對應的腳位如下:
  • SS/CS -- Pin 10
  • MOSI -- Pin 11
  • MISO -- Pin 12
  • SCK -- Pin 13


對於SPI的使用,我們只要了解這幾個腳位即可。接下來,我們以SD卡模組來實作練習看看(因為SD卡也是使用SPI來和Arduino進行通訊)。需要準備的材料如下:
  1. Arduino控制板(我的版本是Arduino UNO)


  2. SD卡模組(這個是很久之前買的模組,現在很多都出Micro SD(小卡)的了,但使用方法大同小異)


  3. 六條連接線

硬體的接線方法,可參考在官網上找到的這張圖接線即可:



在程式碼的部份,我以Arduino 內建的範例來示範。請先開啟Arduino IDE,依序選擇File > Examples > SD > Datalogger




完整的程式碼如下:
/* ==================================================== */
/*
  SD card datalogger

 This example shows how to log data from three analog sensors
 to an SD card using the SD library.

 The circuit:
 * analog sensors on analog ins 0, 1, and 2
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4

 created  24 Nov 2010
 modified 9 Apr 2012
 by Tom Igoe

 This example code is in the public domain.

 */

#include <SPI.h>
#include <SD.h>

const int chipSelect = 4; 

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");
  pinMode(10,OUTPUT);          // 嚴謹一點的話,程式應該加上此行
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ",";
    }
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
    delay(1000);          // 增加此行,減少寫入失敗
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}

/* ==================================================== */

有幾個地方需要注意一下:
  1. const int chipSelect = 4;
    這個範例裡,我們指定Pin 4為CS Pin。在查詢官網的相關訊息發現,因為我們是引用SD Library,即使沒有使用到硬體的SS/CS Pin,也需要將SS/CS Pin保留為輸出模式(以UNO為例,就是Pin 10),否則SD Library無法正常執行。所以在setup()裡我加上了一行pinMode(10,OUTPUT) ,但實驗發現,此行沒加也可以正常執行。
  2. 在寫入到SD卡的程式裡,我有加上讓它延遲一秒再寫入。因為實驗發現,沒有加上這行,寫入失敗的機率好像蠻高的。

2 則留言:


  1. // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
    }


    改成 while (!SD.begin(chipSelect)) ;
    就可以

    回覆刪除