软件模拟SPI接口程序代码(4种模式)
軟件模擬SPI接口程序代碼(4種模式)
?
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ù)
?
通過(guò)模擬SPI程序來(lái)加深理解
使用STM32L4R5ZI MCU進(jìn)行的測(cè)試
初始化代碼:
/**SPI1 GPIO Configuration PA5 ------> SPI1_SCKPA6 ------> SPI1_MISOPA7 ------> SPI1_MOSI */ #define SPI_SCK_PIN GPIO_PIN_5 #define SPI_SCK_GPIO_PORT GPIOA #define SPI_MOSI_PIN GPIO_PIN_7 #define SPI_MOSI_GPIO_PORT GPIOA #define SPI_MISO_PIN GPIO_PIN_6 #define SPI_MISO_GPIO_PORT GPIOA #define SPI_NSS_PIN GPIO_PIN_14 #define SPI_NSS_GPIO_PORT GPIOD#define SPI_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() #define SPI_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() #define SPI_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() #define SPI_NSS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()#define MOSI_H HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_SET) #define MOSI_L HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_RESET) #define SCK_H HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_SET) #define SCK_L HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_RESET) #define MISO HAL_GPIO_ReadPin(SPI_MISO_GPIO_PORT, SPI_MISO_PIN) #define NSS_H HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_SET) #define NSS_L HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_RESET) ·void SPI_Init(void) { /*##-1- Enable peripherals and GPIO Clocks #########################*//* Enable GPIO TX/RX clock */SPI_SCK_GPIO_CLK_ENABLE();SPI_MISO_GPIO_CLK_ENABLE();SPI_MOSI_GPIO_CLK_ENABLE();SPI_NSS_GPIO_CLK_ENABLE();/*##-2- Configure peripheral GPIO #######################*//* SPI SCK GPIO pin configuration */GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = SPI_SCK_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//GPIO_InitStruct.Pull = GPIO_PULLDOWN;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(SPI_SCK_GPIO_PORT, &GPIO_InitStruct);HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_SET);/* SPI MISO GPIO pin configuration */GPIO_InitStruct.Pin = SPI_MISO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;HAL_GPIO_Init(SPI_MISO_GPIO_PORT, &GPIO_InitStruct);/* SPI MOSI GPIO pin configuration */GPIO_InitStruct.Pin = SPI_MOSI_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;HAL_GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStruct);HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_SET);GPIO_InitStruct.Pin = SPI_NSS_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;HAL_GPIO_Init(SPI_NSS_GPIO_PORT, &GPIO_InitStruct);HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_SET);}?模擬SPI4種工作模式:
/* CPOL = 0, CPHA = 0, MSB first */ uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat ) {uint8_t i, read_dat;for( i = 0; i < 8; i++ ){if( write_dat & 0x80 )MOSI_H; else MOSI_L; write_dat <<= 1;delay_us(1); SCK_H; read_dat <<= 1; if( MISO ) read_dat++; delay_us(1);SCK_L; __nop();}return read_dat; }/* CPOL=0,CPHA=1, MSB first */ uint8_t SOFT_SPI_RW_MODE1(uint8_t byte) {uint8_t i,Temp=0;for(i=0;i<8;i++) // 循環(huán)8次{SCK_H; //拉高時(shí)鐘if(byte&0x80){MOSI_H; //若最到位為高,則輸出高}else {MOSI_L; //若最到位為低,則輸出低}byte <<= 1; // 低一位移位到最高位delay_us(1);SCK_L; //拉低時(shí)鐘Temp <<= 1; //數(shù)據(jù)左移if(MISO)Temp++; //若從從機(jī)接收到高電平,數(shù)據(jù)自加一delay_us(1);}return (Temp); //返回?cái)?shù)據(jù) }/* CPOL=1,CPHA=0, MSB first */ uint8_t SOFT_SPI_RW_MODE2(uint8_t byte) {uint8_t i,Temp=0;for(i=0;i<8;i++) // 循環(huán)8次{if(byte&0x80){MOSI_H; //若最到位為高,則輸出高}else {MOSI_L; //若最到位為低,則輸出低}byte <<= 1; // 低一位移位到最高位delay_us(1);SCK_L; //拉低時(shí)鐘Temp <<= 1; //數(shù)據(jù)左移if(MISO)Temp++; //若從從機(jī)接收到高電平,數(shù)據(jù)自加一delay_us(1);SCK_H; //拉高時(shí)鐘}return (Temp); //返回?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;for( i = 0; i < 8; i++ ){SCK_L; if( write_dat & 0x80 )MOSI_H; else MOSI_L; write_dat <<= 1;delay_us(1); SCK_H; read_dat <<= 1; if( MISO ) read_dat++; delay_us(1);__nop();}return read_dat; }?
總結(jié)
以上是生活随笔為你收集整理的软件模拟SPI接口程序代码(4种模式)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Google Play 上架总结(二)G
- 下一篇: 【谈谈】动态规划——求最长公共子序列