利用C51單片機模擬SPI進行雙機通訊

SPI協議簡述

  SPI,是英語Serial Peripheral interface的縮寫,顧名思義就是串行外圍設備接口。由Motorola獨創。SPI接口主要應用在 EEPROM,FLASH,實時時鐘,AD轉換器,還有數字信號處理器和數字信號解碼器之間。SPI,是一種高速的,全雙工,同步的通訊總線。函數

優缺點:

  • 協議簡單,相對數據速率高。
  • 佔用的Pin口較多
  • 沒有指定的流控制,沒有應答機制確認是否接收到數據。

SPI的通訊原理很簡單,它以主從方式工做,這種模式一般有一個主設備和一個或多個從設備,須要至少4根線,事實上3根也能夠(單向傳輸時)。也是全部基於SPI的設備共有的,它們是SDI,SDO,SCK,CS。網站

  • SDO – 主設備數據輸出,從設備數據輸入
  • SDI – 主設備數據輸入,從設備數據輸出
  • SCK – 時鐘信號,由主設備產生
  • CS – 從設備使能信號,由主設備控制

CS: 其中CS是控制芯片是否被選中的,也就是說只有片選信號爲預先規定的使能信號時(高電位或低電位),對此芯片的操做纔有效,這就容許在同一總線上鏈接多個SPI設備成爲可能。ui

SCK:SCK爲時鐘信號線,主要控制時序。至關於整個SPI協議是以SCK爲準進行的。所以SCK的控制在每次發送中只能在主機的控制下進行,從機不可控制。url

SDI/SDO: 通信是經過數據交換完成的,這裏先要知道SPI是串行通信協議,也就是說數據是一位一位的傳輸的。SDO爲主機發送,從機接收;SDI爲主機接受,從機發送。spa

參考網站:http://dlnware.com/theory/SPI-Bus.net

SPI的四種模式

 

這四種模式分別爲:
模式  CPOL CPHA
MODE0 0 0
MODE1 0 1
MODE2 1 0
MODE3 1 1

 

參考網站:http://dlnware.com/theory/SPI-Transfer-Modescode

 

在這四種模式中,咱們經常使用MODE0和MODE2。由於它便於操做。我即是使用的MODE2模式。這四種模式的區別在參考網站中有詳細的描述,這裏便再也不贅述。
  
在MODE2模式下。時鐘在空閒時始終置1,每產生一次降低沿便會發送1 bit 數據。你們可能已經想到,SPI協議能夠在八位沒有發出送完的狀況下中止發送。
  
這裏我跑了下示波器。
  
  從圖中清晰可見8個降低沿,時鐘在空閒時始終置1。
  
  其他的三個模式以此類推。blog

軟件模擬

  我使用的單片機爲STC89C52,內部沒有SPI的資源,所以須要本身進行軟件模擬。
  利用串口中斷,首先利用電腦A得串口助手發送的數據存入SBUF,再將SBUF的值經過SPI的SDO發送給從機的SDI接收,並存入從機的SBUF,顯示在電腦B的串口助手上。
  目的:電腦A發送數據,如:AB,電腦B可接收到AB。
  
  如圖:
  
 PS:在此項目中CS(片選)能夠不用。接口

代碼ip

# include <reg52.h>//頭文件
# include <intrins.h>//頭文件
 # define uchar unsigned char # define uint unsigned int sbit SCK = P1^0;//位定義時鐘 //sbit CS = P1^1;//位定義片選(使能) 此項目能夠不使用
sbit SDI = P1^2;//位定義Input
sbit SDO = P1^3;//位定義Output

/*-----函數聲明-----*/
void delay5us(); void SpiSend(uchar dat1); uchar SpiReceive(); void UARTInit(); /*-----主函數-----*/
void main() { UARTInit(); while(1) { SBUF = SpiReceive();// 循環接收數據
 } ;//空語句 
} /*-----5微秒延時函數-----*/
void delay5us() { _nop_(); } /*-----CPHA=0;CPOL=1 模式2-----*/
/*-----SPI發送函數-----*/
/*-----上升沿發送-----*/
void SpiSend(uchar dat1) { uchar i; for (i=0; i<8; ++i)//8bit,一位一位寫
 { SCK = 0; if (dat1 & 0x80)//判斷當前最高位爲1仍是0
 { SDO = 1; } else { SDO = 0; } SCK = 1;//上升沿發送數據
        dat1 <<= 1; delay5us(); } } /*-----SPI接收函數-----*/
/*-----降低沿接收-----*/ uchar SpiReceive() { uchar i, dat0; dat0 = 0x00;//dat0初始化 
    for (i=0; i<8; ++i)//8bit,一位一位讀
 { dat0 <<= 1; while(SCK == 1); while(SCK == 0);//等待降低沿,降低沿讀取數據 
        dat0 |= SDI; } return (dat0);//收到數據(返回值)dat0
} /*-----串口(中斷)初始化-----*/
void UARTInit() { EA = 1;//開啓總中斷
    ES = 1;//打開串口中斷
    SM0 = 0;SM1 = 1;//串口工做方式1,8位UART波特率可變
    REN = 1;//串口容許接收
    TR1 = 1;//啓動定時器1
    TMOD |= 0X20;//定時器1,工做模式2 8位自動重裝
    TH1 =0XFD; TL1 =0XFD;//設置波特率9600
} /*-----串口中斷服務函數-----*/
void UART() interrupt 4 { if (RI)//判斷是否接收完成
 { RI = 0;//軟件清零
        SpiSend(SBUF);     // 轉發接收到的數據
 } if (TI)//判斷是否發送完成
 { TI = 0;//軟件清零
 } }

 

PS:SDI和SDO需交叉鏈接。

總結

  1. 在發送數據時,時鐘僅由發送端(主機)控制;
  2. SPI四種模式,只需將主從機同步一種模式便可;
  3. SCK,SDI,SDO,CS四個引腳由本身定義便可。
相關文章
相關標籤/搜索