【51单片机快速入门指南】5:软件SPI
目錄
- 硬知識
- SPI協議簡介
- SPI接口介紹
- SPI接口連接圖
- SPI數據傳輸方向
- SPI傳輸模式
- 軟件SPI程序源碼
- Soft_SPI.c
- Soft_SPI.h
普中51-單核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
上位機:Vofa+ 1.3.10
???????源于軟件模擬SPI接口程序代碼(4種模式)—— 內陸的咸水魚,有改動。
硬知識
SPI協議簡介
???????SPI的通信原理很簡單,一般主從方式工作,這種模式通常有一個主設備和一個或多個從設備,通常采用的是4根線,它們是MISO(數據輸入,針對主機來說)、MOSI(數據輸出,針對主機來說)、SCLK(時鐘,主機產生)、CS/SS(片選,一般由主機發送或者直接使能,通常為低電平有效)
SPI接口介紹
???????SCK:時鐘信號,由主設備產生,所以主設備SCK信號為輸出模式,從設備的SCK信號為輸入模式。
???????CS:片選信號,由主設備控制從設備,,所以主設備CS信號為輸出模式,從設備的CS信號為輸入模式。
???????MOSI:主設備數據輸出,從設備數據輸入,所以主設備MOSI信號為輸出模式,從設備的MOSI信號為輸入模式。
???????MISO:主設備數據輸入,從設備數據輸出,所以主設備MISO信號為輸入模式,從設備的MISO信號為輸出模式。
SPI接口連接圖
???????注意:MOSI和MISO不能交叉連接(可以把主從機理解為一個整體系統,MOSI為系統主機發送從機接收的數據線,MISO為主機接收從機發送的數據線)
SPI數據傳輸方向
???????SPI作為全雙工的的串行通信協議,數據傳輸時高位在前,低位在后。主機和從機公用由主機產生的SCK信號,所以在每個時鐘周期內主機和從機有1bit的數據交換(因為MOSI和MISO數據線上的數據都是在時鐘的邊沿處被采樣)。如下圖:
???????SPI協議規定數據采樣是在SCK的上升沿或下降沿時刻(由SPI模式決定,下面會說到),觀察上圖,在SCK的邊沿處(上升沿或下降沿),主機會在MISO數據線上采樣(接收來從機的數據),從機會在MOSI數據線上采樣(接收來自主機的數據),所以每個時鐘周期中會有一bit的數據交換。
SPI傳輸模式
???????SPI總線傳輸一共有4種模式,這4種模式分別由時鐘極性(CPOL)和時鐘相位(CPHA)來定義。
???????CPOL:規定了SCK時鐘信號空閑狀態的電平
???????CPHA:規定了數據是在SCK時鐘的上升沿還是下降沿被采樣
???????模式0:CPOL=0,CPHA =0 SCK空閑為低電平,數據在SCK的上升沿被采樣(提取數據)
???????模式1:CPOL=0,CPHA =1 SCK空閑為低電平,數據在SCK的下降沿被采樣(提取數據)
???????模式2:CPOL=1,CPHA =0 SCK空閑為高電平,數據在SCK的下降沿被采樣(提取數據)
???????模式3:CPOL=1,CPHA =1 SCK空閑為高電平,數據在SCK的上升沿被采樣(提取數據)
???????以模式0為例:SCK空閑為低電平,數據在SCK的上升沿被采樣(提取數據),在SCK的下降沿切換數據線的數據。
?在時鐘的第1個上升沿(游標1處)(采樣點)
???????MOSI上數據為1,則在此邊沿從機采樣(提取)數據為1,采樣點在MOSI數據線的中間。
???????MISO上數據為0,則在此邊沿主機采樣(提取)數據為0,采樣點在MISO數據線的中間。
?在時鐘的第1個下降沿(游標2處)(切換點)
???????MOSI上數據由1切換為0,,數據在時鐘下降沿時切換數據。
???????MISO上數據由0切換為1,,數據在時鐘下降沿時切換數據。
?在時鐘的第2~8個上升沿(采樣點),主機在MISO上采樣數據,從機在MOSI上采樣數據。
?在時鐘的第2~8個下降沿(切換點),主機在MISO上切換數據,從機在MOSI上切換數據
以下內容摘自SPI總線協議及SPI時序圖詳解 —— Ady Lee
這里主要詳解模式0(CPOL=0,CPHA=0)的時序:
???????我們來關注SCK的第一個時鐘周期,在時鐘的前沿采樣數據(上升沿,第一個時鐘沿),在時鐘的后沿輸出數據(下降沿,第二個時鐘沿)。
???????首先來看主器件,主器件的輸出口(MOSI)輸出的數據bit1,在時鐘的前沿被從器件采樣,那主器件是在何時刻輸出bit1的呢?bit1的輸出時刻實際上在SCK信號有效以前,比 SCK的上升沿還要早半個時鐘周期。bit1的輸出時刻與SSEL信號沒有關系。
???????再來看從器件,主器件的輸入口MISO同樣是在時鐘的前沿采樣從器件輸出的bit1的,那從器件又是在何時刻輸出bit1的呢?從器件是在SSEL信號有效后,立即輸出bit1,盡管此時SCK信號還沒有起效。
???????關于上面的主器件和從器件輸出bit1位的時刻,可以從以下兩圖中得到驗證。
???????注意上圖中,CS信號有效后(低電平有效,注意CS下降沿后發生的情況),故意用延時程序延時了一段時間,之后再向數據寄存器寫入了要發送的數據,來觀察主器件輸出bit1的情況(MOSI)。
???????可以看出,bit1(值為1)是在SCK信號有效之前的半個時鐘周期的時刻開始輸出的(與CS信號無關),到了SCK的第一個時鐘周期的上升沿正好被從器件采樣。
上圖中,注意看CS和MISO信號。我們可以看出,CS信號有效后,從器件立刻輸出了bit1(值為1)。
???????通常我們進行的spi操作都是16位的。下圖記錄了第一個字節和第二個字節間的相互銜接的過程。
???????第一個字節的最后一位在SCK的上升沿被采樣,隨后的SCK下降沿,從器件就輸出了第二個字節的第一位。
軟件SPI程序源碼
Soft_SPI.c
#include "Soft_SPI.h"void SPI_Delay() //每步的間隔 用于等待電平穩定和控制通訊速率 {}//MOSI拉高 移植時需修改 void MOSI_H() {SOFT_SPI_MOSI = 1; }//MOSI拉低 移植時需修改 void MOSI_L() {SOFT_SPI_MOSI = 0; }//MISO拉高 移植時需修改 void MISO_H() {SOFT_SPI_MISO = 1; }//MISO拉低 移植時需修改 void MISO_L() {SOFT_SPI_MISO = 0; }//SCK拉高 移植時需修改 void SPI_SCK_H() {SOFT_SPI_SCK = 1; }//SCK拉低 移植時需修改 void SPI_SCK_L() {SOFT_SPI_SCK = 0; }//讀取MISO電平 移植時需修改 uint8_t MISO_Read() {SOFT_SPI_MISO = 1;SPI_Delay();return SOFT_SPI_MISO; }//空閑時時鐘極性(CPOL) 0為低電平 1為高電平 //數據有效時鐘緣相位(CPHA) 0為奇數緣 1為偶數緣/* CPOL = 0, CPHA = 0, MSB first */ uint8_t SOFT_SPI_RW_MODE0(uint8_t write_dat) {uint8_t i, read_dat = 0;SPI_SCK_L();for( i = 0; i < 8; i++ ){read_dat <<= 1; read_dat |= MISO_Read();if(write_dat & 0x80)MOSI_H(); else MOSI_L(); write_dat <<= 1;SPI_Delay();SPI_SCK_H(); SPI_Delay();SPI_SCK_L(); }return read_dat; }/* CPOL=0,CPHA=1, MSB first */ uint8_t SOFT_SPI_RW_MODE1(uint8_t write_dat) {uint8_t i, read_dat = 0;SPI_SCK_L();for(i = 0; i < 8; i++) //循環8次{if(write_dat & 0x80)MOSI_H(); //若最到位為高,則輸出高else MOSI_L(); //若最到位為低,則輸出低write_dat <<= 1; //低一位移位到最高位SPI_Delay();SPI_SCK_H(); //拉高時鐘SPI_Delay();read_dat <<= 1; //數據左移read_dat |= MISO_Read();SPI_SCK_L(); //拉低時鐘}return read_dat; //返回數據 }/* CPOL=1,CPHA=0, MSB first */ uint8_t SOFT_SPI_RW_MODE2(uint8_t write_dat) {uint8_t i, read_dat = 0;SPI_SCK_H();for(i = 0; i < 8; i++) // 循環8次{read_dat <<= 1; //數據左移read_dat |= MISO_Read(); if(write_dat & 0x80)MOSI_H(); //若最到位為高,則輸出高else MOSI_L(); //若最到位為低,則輸出低write_dat <<= 1; //低一位移位到最高位SPI_Delay();SPI_SCK_L(); //拉低時鐘SPI_Delay();SPI_SCK_H(); //拉高時鐘}return read_dat; //返回數據 }/* CPOL = 1, CPHA = 1, MSB first */ uint8_t SOFT_SPI_RW_MODE3(uint8_t write_dat) {uint8_t i, read_dat = 0;SPI_SCK_H();for( i = 0; i < 8; i++ ){if(write_dat & 0x80)MOSI_H(); else MOSI_L(); write_dat <<= 1;SPI_Delay(); SPI_SCK_L(); SPI_Delay();read_dat <<= 1; read_dat |= MISO_Read(); SPI_SCK_H(); }return read_dat; }Soft_SPI.h
#ifndef SOFT_SPI_H_ #define SOFT_SPI_H_#include <STC89C5xRC.H> #include "stdint.h"sbit SOFT_SPI_SCK = P3^2; sbit SOFT_SPI_MOSI = P1^0; sbit SOFT_SPI_MISO = P1^0;//MOSI拉高 移植時需修改 void MOSI_H(); //MOSI拉低 移植時需修改 void MOSI_L(); //MISO拉高 移植時需修改 void MISO_H(); //MISO拉低 移植時需修改 void MISO_L(); //SCK拉高 移植時需修改 void SPI_SCK_H(); //SCK拉低 移植時需修改 void SPI_SCK_L(); //讀取MISO電平 移植時需修改 uint8_t MISO_Read();void SPI_Delay(); //每步的間隔 用于等待電平穩定和控制通訊速率uint8_t SOFT_SPI_RW_MODE0(uint8_t write_dat); uint8_t SOFT_SPI_RW_MODE1(uint8_t write_dat); uint8_t SOFT_SPI_RW_MODE2(uint8_t write_dat); uint8_t SOFT_SPI_RW_MODE3(uint8_t write_dat);#endif總結
以上是生活随笔為你收集整理的【51单片机快速入门指南】5:软件SPI的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【20120517】【早晨】
- 下一篇: 毕业设计外文文献下载方法