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