一、SPI協(xié)議簡介
? ? 一般主從方式工作,這種模式通常有一個主設備和一個或多個從設備,通常采用的是4根線,它們是MISO(主機輸入從機輸出)、MOSI(主機輸出,針對主機來說)、SCLK(時鐘,主機產(chǎn)生)、CS(片選,一般由主機發(fā)送或者直接使能,通常為低電平有效)
●SPI接口介紹
SCK:時鐘信號,由主設備產(chǎn)生,所以主設備SCK信號為推挽輸出模式,從設備的SCK信號為浮空輸入模式。
CS:使能信號,由主設備控制從設備,,所以主設備CS信號為推挽輸出模式,從設備的CS信號為浮空輸入模式。
MOSI:主設備數(shù)據(jù)輸出,從設備數(shù)據(jù)輸入,所以主設備MOSI信號為推挽輸出模式,從設備的MOSI信號為浮空輸入模式。
MISO:主設備數(shù)據(jù)輸入,從設備數(shù)據(jù)輸出,所以主設備MISO信號為浮空輸入模式,從設備的MISO信號為推挽輸出模式。
二、四種模式(本次模擬采用的模式0)
模式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ù))
三、雙機通信實現(xiàn)
1、GPIO引腳
PC8為CS引腳? ? ? ? PC10為CLK引腳? ? ? ? PC11為MISO引腳? ? ? ? PC12為MOSI引腳
2、時序
首先主機將片選拉低(使能片選),在時鐘為低電平時向從機發(fā)送數(shù)據(jù),從機通過檢測MOSI線上的高低電平實現(xiàn)數(shù)據(jù)的接收。在時鐘為高電平時主機檢測MISO線上的高低電平來實現(xiàn)數(shù)據(jù)的接收。
主機在時鐘信號為低電平時發(fā)送單字節(jié)的最高位,然后將該字節(jié)左移一位,然后將時鐘信號拉高,此時從機檢測到時鐘信號為高電平(時鐘上升沿),從而檢測MOSI線上的高低電平并將得到的高低電平放到變量中。同時從機向主機發(fā)送數(shù)據(jù),即改變MISO線上的高低電平。此過程重復8次,即可完成發(fā)送和接收一個字節(jié)的數(shù)據(jù)。
四、代碼如下
1、主設備GPIO的配置
void SPI_GPIO_Init(void){
GPIO_InitTypeDef GPIO_InitStructure; //定義結構體類型的變量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能GPIOC的端口時種
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_10|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50Mhz
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_8); //CS拉高
GPIO_ResetBits(GPIOC,GPIO_Pin_10);//CLK拉低
GPIO_ResetBits(GPIOC,GPIO_Pin_11);
}
2、主設備向從設備寫以及讀
/*
*********************************************************************************************************
* 函 數(shù) 名: SPI_WRByte
* 形 參: spi; wdat:寫入的數(shù)據(jù)
* 返 回 值: spi讀一個字節(jié)
* 功能說明: 主機spi同時讀寫一個字節(jié)的時序 MSB
*********************************************************************************************************
*/
u8 Master_SPI_WRByte(u8 wdat)
{
u8 i=0,rdat=0;
SPI_CS_LOW;
for(i=0;i<8;i++)
{
if(wdat&0x80)
SPI_MOSI_HIGH;
else
SPI_MOSI_LOW;
wdat<<=1;
delay_us(3);
SPI_CLK_HIGH;
delay_us(2);
rdat<<=1;
if(SPI_MISO_READ)
rdat |= 0x01;
delay_us(1);
SPI_CLK_LOW;
}
SPI_CS_HIGH;
return rdat;
}
3、從設備GPIO設置
void SPI_GPIO_Init(void){
GPIO_InitTypeDef GPIO_InitStructure; //定義結構體類型的變量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能GPIOC的端口時種
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50Mhz
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_10|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_ResetBits(GPIOC,GPIO_Pin_11);
}
4、從設備讀寫函數(shù)
u8 Slave_SPI_RWByte(u8 wdat){
u8 i=0,dat=0;
if(!SPI_CS_READ){ //檢測到片選拉低
for(i=0;i<8;i++)
{
while(!SPI_CLK_READ); //檢測到時鐘上升沿的到來
if(wdat&0x80)SPI_MISO_HIGH; //MSB
else SPI_MISO_LOW;
wdat<<=1;
dat<<=1;
if(SPI_MOSI_READ)dat |= 0x01;
while(SPI_CLK_READ);
}
}
return dat;
}
5、頭文件
#define SELECT 1 //0表示主機 其它表示從機
#if SELECT==0
//主機
//CS引腳
#define SPI_CS_HIGH PCout(8)=1
#define SPI_CS_LOW PCout(8)=0
//CLK引腳
#define SPI_CLK_HIGH PCout(10)=1
#define SPI_CLK_LOW PCout(10)=0
//MISO引腳
#define SPI_MISO_READ PCin(11)
//MOSI引腳
#define SPI_MOSI_HIGH PCout(12)=1
#define SPI_MOSI_LOW PCout(12)=0
void SPI_GPIO_Init(void);
u8 Master_SPI_WRByte(u8 wdat);
#else
//從機
//CS引腳
#define SPI_CS_READ PCin(8)
//CLK引腳
#define SPI_CLK_READ PCin(10)
//MISO引腳
#define SPI_MISO_HIGH PCout(11)=1
#define SPI_MISO_LOW PCout(11)=0
//MOSI引腳
#define SPI_MOSI_READ PCin(12)
void SPI_GPIO_Init(void);
u8 Slave_SPI_RWByte(u8 wdat);
#endif
6、主函數(shù)
int main(void)
{
u8 key;
delay_init(); //延時函數(shù)初始化
led_init(); //初始化與LED連接的硬件接口
key_init();
SPI_GPIO_Init();
while(1)
{
#if SELECT==0
key=key_scan(0);
switch(key){
case key_up_value:{
if(Master_SPI_WRByte(0x50)==0x60)LED1=!LED1;
break;
};
case key_down_value:{
break;
};
case key_left_value:{
break;
};
case key_right_value:{
break;
};
}
#else
Slave_SPI_RWByte(0x60);
#endif
五、實驗說明文章來源:http://www.zghlxwxcb.cn/news/detail-404014.html
本實驗通過主機向從機發(fā)送0x50命令來控制從機LED1亮滅。其他應用層的使用讀者可自行完成。
?文章來源地址http://www.zghlxwxcb.cn/news/detail-404014.html
到了這里,關于stm32 GPIO模擬SPI接口實現(xiàn)雙機通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!