久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

還在苦惱單片機(jī)通訊嗎?SPI雙機(jī)通訊帶你飛,!

 xpxys99 2017-10-13

由于項(xiàng)目的需要,,需要使用兩個(gè)STM32的單片機(jī)進(jìn)行雙機(jī)通訊。以前使用SPI都是使用spi外掛類(lèi)似FLASH或者顯示屏之類(lèi)的片子,。不需要從機(jī)進(jìn)行反數(shù)據(jù),。本來(lái)以為會(huì)很簡(jiǎn)單。沒(méi)想到在實(shí)際調(diào)試中卻發(fā)現(xiàn)了一些問(wèn)題,,耽擱了兩天才調(diào)試完成?,F(xiàn)在談?wù)勎业囊恍┙?jīng)過(guò)。也為有類(lèi)似問(wèn)題的同學(xué)提供一些參考,。

還在苦惱單片機(jī)通訊嗎,?SPI雙機(jī)通訊帶你飛!

我使用的是stm32f103單片機(jī)的SPI1。PA5,,PA6,,PA7三個(gè)引腳的硬件spi。下面我把程序拆分粘貼上來(lái),。談?wù)勛约赫{(diào)試中遇到的問(wèn)題,,跟解決方案。

首先要說(shuō)明的一個(gè)就是硬件的接線(xiàn),。SPI接線(xiàn)不能跟串口一樣交叉,。這點(diǎn)一定要注意。

MISO---------MISO

MOSI---------MOSI

SCK------------SCK

主機(jī)片選IO可自己選----------從機(jī)NSS引腳PA4

首先在IO引腳這里的配置一定要注意,。有些人直接都配置成AF_PP,這樣在主機(jī)通訊的時(shí)候是沒(méi)有問(wèn)題的,,但是在從機(jī)也這樣配置就會(huì)出現(xiàn)錯(cuò)誤。因?yàn)閺臋C(jī)是不能發(fā)送時(shí)鐘信號(hào)的需要接受主機(jī)產(chǎn)生的時(shí)鐘,,所以需要配置成浮空輸入,。具體程序如下

主機(jī)*******************************************************************************

//**********************配置GPIO管腳*********************************

void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽復(fù)用

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;//sck mosi

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//miso

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//cs

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//cs

GPIO_Init(GPIOB,&GPIO_InitStructure);

}

從機(jī)**********************************************************************************

//**********************配置GPIO管腳*********************************

void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;//sck mosi

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//miso

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//cs

GPIO_Init(GPIOA,&GPIO_InitStructure);

}

配置完IO接下來(lái)就要配置spi的初始化函數(shù)了。這里我在網(wǎng)上看到有人說(shuō)CPOL,CPHA的配置不能完全一樣,。說(shuō)會(huì)產(chǎn)生數(shù)據(jù)位的錯(cuò)誤,。但是官方的數(shù)據(jù)手冊(cè)說(shuō)是應(yīng)該配置成一樣的。通過(guò)我自己試驗(yàn)發(fā)現(xiàn)配置成一樣的并沒(méi)有發(fā)生數(shù)據(jù)位錯(cuò)誤的現(xiàn)象,。也許是單片機(jī)的原因吧,。反正我是配置成一樣的 。

主機(jī)***************************************************************************************

//**********************SPI初始化函數(shù)*********************************

void SPI_Configuration(void)

{

SPI_InitTypeDef SPI_InitStructure;

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

SPI_Cmd(SPI1, ENABLE);

}

從機(jī)**********************************************************************************************

//**********************SPI初始化函數(shù)*********************************

void SPI_Configuration(void)

{

SPI_InitTypeDef SPI_InitStructure;

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

SPI_Cmd(SPI1, ENABLE);

}

因?yàn)閺臋C(jī)的片選需要用主機(jī)進(jìn)行控制,。(實(shí)際上我是6片單片機(jī)進(jìn)行的SPI通訊,。)所以 SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; 這里從機(jī)一定要配置成hard硬件片選模式。只有這樣才能用主機(jī)的IO才可以控制從機(jī)

接下來(lái)其實(shí)就是最關(guān)鍵的地方了也是我出現(xiàn)了很多問(wèn)題的地方,。我先說(shuō)我最開(kāi)始直接用官方的庫(kù)函數(shù)出現(xiàn)的問(wèn)題,。主機(jī)從機(jī)的代碼這里是一樣的。我先發(fā)一個(gè)有問(wèn)題的,。

u8 SPI_Send_Byte(u8 byte)

{

while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); //判斷是否忙,,不忙的時(shí)候才發(fā)送數(shù)據(jù)

SPI_I2S_SendData(SPI1, byte); //發(fā)送數(shù)據(jù)

while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET); //判斷接收標(biāo)志

return SPI_I2S_ReceiveData(SPI1); //返回接收數(shù)據(jù)

}

這里使用這個(gè)函數(shù)用主機(jī)給從機(jī)發(fā)送數(shù)據(jù)的時(shí)候是完全沒(méi)有問(wèn)題的。數(shù)據(jù)可以很穩(wěn)定的發(fā)送和接收,。但是當(dāng)從機(jī)給主機(jī)發(fā)送的時(shí)候就會(huì)發(fā)生數(shù)據(jù)錯(cuò)亂的問(wèn)題,。所以從機(jī)反數(shù)據(jù)的時(shí)候我浪費(fèi)了很長(zhǎng)的時(shí)間去測(cè)試。包括使用示波器觀(guān)察,。因?yàn)閟pi是全雙工通信的。所以無(wú)論你怎樣工作數(shù)據(jù)收發(fā)都是同步進(jìn)行的,。而芯片內(nèi)部寄存器實(shí)際上只有一個(gè)來(lái)存儲(chǔ)這些數(shù)據(jù),。如果沒(méi)有及時(shí)的清空就會(huì)對(duì)數(shù)據(jù)產(chǎn)生影響。所以用這個(gè)函數(shù)就會(huì)發(fā)生紊亂。

那么要解決這個(gè)函數(shù)的問(wèn)題,,實(shí)際上就要把數(shù)據(jù)分開(kāi)發(fā)送,,就是一個(gè)字節(jié)一個(gè)字節(jié)的發(fā)送。發(fā)一個(gè)的同時(shí)接受一個(gè),。一發(fā)一收永遠(yuǎn)同步進(jìn)行,。因此我這里套用了一個(gè)別人的代碼。不過(guò)當(dāng)時(shí)這個(gè)代碼還是有問(wèn)題的,。一會(huì)再說(shuō),。先發(fā)一個(gè)最原始的代碼。

網(wǎng)上的原始代碼*************************************************************************************************

u8 SPI_Send_Byte(u8 byte)

{

while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); //判斷是否忙,,不忙的時(shí)候才發(fā)送數(shù)據(jù)

SPI_I2S_SendData(SPI1, byte); //發(fā)送數(shù)據(jù)

while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET); //判斷接收標(biāo)志

return SPI_I2S_ReceiveData(SPI1); //返回接收數(shù)據(jù)

}

u8 SPI1_ReadWriteByte(u8 TxData) //這個(gè)代碼是抄的原子大哥的,,我就不BB了

{

u16 retry=0;

u8 data;

while((SPI1->SR&1<1)==0)>

{

retry++;

if(retry>0XFFFE)return 0;

}

SPI1->DR=TxData; //發(fā)送一個(gè)byte

retry=0;

while((SPI1->SR&1<0)==0)>

{

retry++;

if(retry>0XFFFE)return 0;

}

data=SPI1->DR;

return SPI1->DR; //返回收到的數(shù)據(jù)

}

這段代碼表面看起來(lái)天衣無(wú)縫。并且使用主機(jī)發(fā)送的時(shí)候也是沒(méi)有問(wèn)題的,。當(dāng)我用從機(jī)返回?cái)?shù)據(jù)的時(shí)候我還是出現(xiàn)了之前數(shù)據(jù)錯(cuò)誤的問(wèn)題,。這下我糾結(jié)了。理論上是不應(yīng)該有問(wèn)題,。因此還是只能從程序上找問(wèn)題,。其實(shí)這個(gè)問(wèn)題就是最后一句話(huà)

return SPI1->DR; //返回收到的數(shù)據(jù)

因?yàn)閺臋C(jī)需要及時(shí)的把數(shù)據(jù)發(fā)送出去,如果還是返回SPI1->DR; 這個(gè)寄存器的數(shù)據(jù)其實(shí)已經(jīng)不是剛剛的數(shù)據(jù)了,,因?yàn)橹挥幸粋€(gè)寄存器,,而且全雙工一直在工作。這時(shí)的寄存器已經(jīng)是一個(gè)不穩(wěn)定狀態(tài)了,,數(shù)據(jù)當(dāng)然會(huì)發(fā)生紊亂,。所以這里需要直接返回的是這個(gè)變量的值。return SPI1->DR; 改成return data; 這樣就可以了,,因?yàn)樽兞康闹凳遣粫?huì)被刷新的,。最后實(shí)際測(cè)試也是完全正確的。從機(jī)也可以很穩(wěn)定的發(fā)送數(shù)據(jù),。

下面我發(fā)送一下我的主函數(shù),。測(cè)試程序。

主機(jī)***************************************************************************************

#include 'pbdata.h'

u8 a;

u8 b;

int main(void)

{

RCC_Configuration();

GPIO_Configuration();

SPI_Configuration();

USART_Configration();

NVIC_Configuration(); //中斷優(yōu)先級(jí)配置

// GPIO_ResetBits(GPIOB,GPIO_Pin_5);//從機(jī)開(kāi)始工作

// GPIO_SetBits(GPIOB,GPIO_Pin_5);//從機(jī)停止工作

while(1)

{

if(a==1)

{

GPIO_ResetBits(GPIOB,GPIO_Pin_5);//從機(jī)開(kāi)始工作

if(b==1)

{

// while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET); //判斷是否忙,,不忙的時(shí)候才發(fā)送數(shù)據(jù)

// // SPI1->DR=spisend1;//發(fā)送

// SPI_I2S_SendData(SPI1, spisend1); //發(fā)送數(shù)據(jù)

// while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET); //判斷接收標(biāo)志

// // spivalue1=SPI1->DR;//接收

// spivalue1=SPI_I2S_ReceiveData(SPI1);

u8 a=8;

while(a--)

{

spivalue1=SPI1_ReadWriteByte( spisend1);

}

}

}

if(a==0)

{

GPIO_SetBits(GPIOB,GPIO_Pin_5);//從機(jī)停止工作

}

delay_ms(2);

}

}

這里的a,,b是為了在線(xiàn)調(diào)試的時(shí)候?qū)ζx和收發(fā)開(kāi)關(guān)進(jìn)行控制。

從機(jī)***********************************************************************************************

#include 'pbdata.h'

u8 a;

int main(void)

{

RCC_Configuration();

GPIO_Configuration();

SPI_Configuration();

USART_Configration();

NVIC_Configuration(); //中斷優(yōu)先級(jí)配置

while(1)

{ u8 a=8;

if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)==0)

{

while(a--)

{

spivalue2= SPI1_ReadWriteByte(spisend2); //這個(gè)代碼是抄的原子大哥的,,我就不BB了

}

}

}

}

while(a--)這個(gè)是因?yàn)槲野l(fā)送的數(shù)據(jù)是8幀的,。所以分8次發(fā)送。

spisend和spivalue是兩個(gè)全局變量,。在線(xiàn)調(diào)試的時(shí)候直接觀(guān)察自己收發(fā)的數(shù)據(jù),。

spi一般用作片間通訊較多,。很少使用板間通訊。因此我也在擔(dān)心不穩(wěn)定的問(wèn)題,。所以我特地親自只做了3根長(zhǎng)度2米5左右的線(xiàn)進(jìn)行了測(cè)試,。沒(méi)有添加上拉電阻等原件。實(shí)際測(cè)試發(fā)現(xiàn)數(shù)據(jù)還是很穩(wěn)定的,。因此可以判定在這個(gè)距離以?xún)?nèi)是沒(méi)有必要去擔(dān)心的,。另外提醒大家在做這個(gè)實(shí)驗(yàn)的時(shí)候一定要記得兩個(gè)電路板要共地不要忽略了這個(gè)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多