1.1SPI協(xié)議簡(jiǎn)述
SPI,是英語Serial Peripheral interface的縮寫,顧名思義就是串行外圍設(shè)備接口。由Motorola首創(chuàng)。SPI接口主要應(yīng)用在 EEPROM,F(xiàn)LASH,實(shí)時(shí)時(shí)鐘,AD轉(zhuǎn)換器,還有數(shù)字信號(hào)處理器和數(shù)字信號(hào)解碼器之間。SPI,是一種高速的,全雙工,同步的通信總線。
優(yōu)缺點(diǎn):
- 1.協(xié)議簡(jiǎn)單,相對(duì)數(shù)據(jù)速率高。
- 2.占用的Pin口較多
- 3.沒有指定的流控制,沒有應(yīng)答機(jī)制確認(rèn)是否接收到數(shù)據(jù)。
SPI的通信原理很簡(jiǎn)單,它以主從方式工作,這種模式通常有一個(gè)主設(shè)備和一個(gè)或多個(gè)從設(shè)備,需要至少4根線,事實(shí)上3根也可以(單向傳輸時(shí))。也是所有基于SPI的設(shè)備共有的,它們是SDI,SDO,SCK,CS。
- SDO – 主設(shè)備數(shù)據(jù)輸出,從設(shè)備數(shù)據(jù)輸入
- SDI – 主設(shè)備數(shù)據(jù)輸入,從設(shè)備數(shù)據(jù)輸出
- SCK – 時(shí)鐘信號(hào),由主設(shè)備產(chǎn)生
- CS – 從設(shè)備使能信號(hào),由主設(shè)備控制
CS: 其中CS是控制芯片是否被選中的,也就是說只有片選信號(hào)為預(yù)先規(guī)定的使能信號(hào)時(shí)(高電位或低電位),對(duì)此芯片的操作才有效,這就允許在同一總線上連接多個(gè)SPI設(shè)備成為可能。
SCK:SCK為時(shí)鐘信號(hào)線,主要控制時(shí)序。相當(dāng)于整個(gè)SPI協(xié)議是以SCK為準(zhǔn)進(jìn)行的。因此SCK的控制在每次發(fā)送中只能在主機(jī)的控制下進(jìn)行,從機(jī)不可控制。
SDI/SDO: 通訊是通過數(shù)據(jù)交換完成的,這里先要知道SPI是串行通訊協(xié)議,也就是說數(shù)據(jù)是一位一位的傳輸?shù)摹DO為主機(jī)發(fā)送,從機(jī)接收;SDI為主機(jī)接受,從機(jī)發(fā)送。
參考網(wǎng)站(請(qǐng)自行替換.):dlnware點(diǎn)com/theory/SPI-Bus
1.2SPI的四種模式
這四種模式分別為:
模式 CPOL&CPHA
MODE0 CPOL=0;CPHA=0
MODE1 CPOL=0;CPHA=1
MODE2 CPOL=1;CPHA=0
MODE3 CPOL=1;CPHA=1
參考網(wǎng)站(請(qǐng)自行替換.):dlnware點(diǎn)com/theory/SPI-Transfer-Modes
在這四種模式中,我們常用MODE0和MODE2。因?yàn)樗阌诓僮。我便是使用的MODE2模式。這四種模式的區(qū)別在參考網(wǎng)站中有詳細(xì)的描述,這里便不再贅述。
在MODE2模式下。時(shí)鐘在空閑時(shí)始終置1,每產(chǎn)生一次下降沿便會(huì)發(fā)送1 bit 數(shù)據(jù)。大家可能已經(jīng)想到,SPI協(xié)議可以在八位沒有發(fā)出送完的情況下停止發(fā)送。
這里我跑了下示波器。
BMP0.jpg (376.05 KB, 下載次數(shù): 66)
下載附件
2019-3-19 21:26 上傳
從圖中清晰可見8個(gè)下降沿,時(shí)鐘在空閑時(shí)始終置1。
其余的三個(gè)模式以此類推。 2.1軟件模擬 我使用的單片機(jī)為STC89C52,內(nèi)部沒有SPI的資源,因此需要自己進(jìn)行軟件模擬。
利用串口中斷,首先利用電腦A得串口助手發(fā)送的數(shù)據(jù)存入SBUF,再將SBUF的值通過SPI的SDO發(fā)送給從機(jī)的SDI接收,并存入從機(jī)的SBUF,顯示在電腦B的串口助手上。
目的:電腦A發(fā)送數(shù)據(jù),如:AB,電腦B可接收到AB。
如圖:
無標(biāo)題.png (5.71 KB, 下載次數(shù): 89)
下載附件
2019-3-19 21:28 上傳
PS:在此項(xiàng)目中CS(片選)可以不用。
2.2代碼
- # include <reg52.h>//頭文件
- # include <intrins.h>//頭文件
- # define uchar unsigned char
- # define uint unsigned int
- sbit SCK = P1^0;//位定義時(shí)鐘
- //sbit CS = P1^1;//位定義片選(使能) 此項(xiàng)目可以不使用
- sbit SDI = P1^2;//位定義Input
- sbit SDO = P1^3;//位定義Output
- /*-----函數(shù)聲明-----*/
- void delay5us();
- void SpiSend(uchar dat1);
- uchar SpiReceive();
- void UARTInit();
- /*-----主函數(shù)-----*/
- void main()
- {
- UARTInit();
- while(1)
- {
- SBUF = SpiReceive();// 循環(huán)接收數(shù)據(jù)
- }
- ;//空語句
- }
-
- /*-----5微秒延時(shí)函數(shù)-----*/
- void delay5us()
- {
- _nop_();
- }
- /*-----CPHA=0;CPOL=1 模式2-----*/
- /*-----SPI發(fā)送函數(shù)-----*/
- /*-----上升沿發(fā)送-----*/
- void SpiSend(uchar dat1)
- {
- uchar i;
- for (i=0; i<8; ++i)//8bit,一位一位寫
- {
- SCK = 0;
- if (dat1 & 0x80)//判斷當(dāng)前最高位為1還是0
- {
- SDO = 1;
- }
- else
- {
- SDO = 0;
- }
- SCK = 1;//上升沿發(fā)送數(shù)據(jù)
- dat1 <<= 1;
- delay5us();
- }
- }
- /*-----SPI接收函數(shù)-----*/
- /*-----下降沿接收-----*/
- uchar SpiReceive()
- {
- uchar i, dat0;
- dat0 = 0x00;//dat0初始化
- for (i=0; i<8; ++i)//8bit,一位一位讀
- {
- dat0<<=1;
- while(SCK == 1);
- while(SCK == 0);//下降沿讀取數(shù)據(jù)
- dat0 |= SDI;
- }
- return (dat0);//收到數(shù)據(jù)(返回值)dat0
- }
- /*-----串口(中斷)初始化-----*/
- void UARTInit()
- {
- EA = 1;//開啟總中斷
- ES = 1;//打開串口中斷
- SM0 = 0;SM1 = 1;//串口工作方式1,8位UART波特率可變
- REN = 1;//串口允許接收
- TR1 = 1;//啟動(dòng)定時(shí)器1
- TMOD |= 0X20;//定時(shí)器1,工作模式2 8位自動(dòng)重裝
- TH1 =0XFD;
- TL1 =0XFD;//設(shè)置波特率9600
- }
- /*-----串口中斷服務(wù)函數(shù)-----*/
- void UART() interrupt 4
- {
- if (RI)//判斷是否接收完成
- {
- RI = 0;//軟件清零
- SpiSend(SBUF);// 轉(zhuǎn)發(fā)接收到的數(shù)據(jù)
- }
- if (TI)//判斷是否發(fā)送完成
- {
- TI = 0;//軟件清零
- }
- }
復(fù)制代碼
PS:SDI和SDO需交叉連接。
3.總結(jié)
- 在發(fā)送數(shù)據(jù)時(shí),時(shí)鐘僅由發(fā)送端(主機(jī))控制;
- SPI四種模式,只需將主從機(jī)同步一種模式即可;
- SCK,SDI,SDO,CS四個(gè)引腳由自己定義即可。
|