目錄
前言
一、理論部分? ???
SPI簡介??
SPI特征
SPI物理層
SPI協(xié)議層
SPI配置過程
SPI數(shù)據(jù)發(fā)送與接收過程
二、代碼部分
主機代碼
從機代碼
前言
這是一篇學(xué)習(xí)筆記,記錄自己學(xué)習(xí)SPI通信。方便之后運用的時候回顧。參考《STM32中文參考手冊》
一、理論部分? ???
SPI簡介??
SPI特征
SPI物理層
?SPI通信設(shè)備連接圖
SPI框圖
SPI協(xié)議層

SPI配置過程
?SPI主模式配置
1. 通過SPI_CR1寄存器的BR[2:0]位定義串行時鐘波特率。
2. 選擇CPOL和CPHA位,定義數(shù)據(jù)傳輸和串行時鐘間的相位關(guān)系。
3. 設(shè)置DFF位來定義8位或16位數(shù)據(jù)幀格式。
4. 配置SPI_CR1寄存器的LSBFIRST位定義幀格式。
5. 如果需要NSS引腳工作在輸入模式,硬件模式下,在整個數(shù)據(jù)幀傳輸期間應(yīng)把NSS腳連接到高電平;在軟件模式下,需設(shè)置SPI_CR1寄存器的SSM位和SSI位。如果NSS引腳工作在輸出模式,則只需設(shè)置SSOE位。
6. 必須設(shè)置MSTR位和SPE位(只當(dāng)NSS腳被連到高電平,這些位才能保持置位)。 在這個配置中,MOSI引腳是數(shù)據(jù)輸出,而MISO引腳是數(shù)據(jù)輸入。
SPI從模式配置
SPI數(shù)據(jù)發(fā)送與接收過程
主模式通訊過程
從模式通訊過程
?
?
二、代碼部分
? ? 我的想法是在串口助手上發(fā)送給主機什么,主機就發(fā)什么給從機。之后從機把接收的數(shù)據(jù)再返回給主機,最終再串口助手上打印出來。驗證SPI的全雙工通訊。主機和從機都采用中斷的方式發(fā)送和接收。
主機代碼
SPI配置代碼文章來源:http://www.zghlxwxcb.cn/news/detail-647319.html
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
/* SPI的IO口和SPI外設(shè)打開時鐘 */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PB12推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* SPI的IO口設(shè)置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //設(shè)置SPI單向或者雙向的數(shù)據(jù)模式:SPI設(shè)置為雙線雙向全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //設(shè)置SPI工作模式:設(shè)置為主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //設(shè)置SPI的數(shù)據(jù)大小:SPI發(fā)送接收8位幀結(jié)構(gòu)
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步時鐘的空閑狀態(tài)為高電平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步時鐘的第二個跳變沿(上升或下降)數(shù)據(jù)被采樣
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信號由硬件(NSS管腳)還是軟件(使用SSI位)管理:內(nèi)部NSS信號有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定義波特率預(yù)分頻的值:
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定數(shù)據(jù)傳輸從MSB位還是LSB位開始:數(shù)據(jù)傳輸從MSB位開始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值計算的多項式
SPI_Init(SPI2, &SPI_InitStructure); //根據(jù)SPI_InitStruct中指定的參數(shù)初始化外設(shè)SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外設(shè)
}
串口中斷部分文章來源地址http://www.zghlxwxcb.cn/news/detail-647319.html
void USART1_IRQHandler(void) //串口1中斷服務(wù)程序
{
u16 r,i;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
r =USART_ReceiveData(USART1);//(USART1->DR); //讀取接收到的數(shù)據(jù)
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待發(fā)送區(qū)空
SPI_I2S_SendData(SPI2, r);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //等待接收完一個byte
i = SPI_I2S_ReceiveData(SPI2);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
USART_senddate(USART1,i) ;
}
}
從機代碼
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* SPI的IO口和SPI外設(shè)打開時鐘 */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PB12推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //下拉輸入
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* SPI的IO口設(shè)置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //設(shè)置SPI單向或者雙向的數(shù)據(jù)模式:SPI設(shè)置為雙線雙向全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //設(shè)置SPI工作模式:設(shè)置為主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //設(shè)置SPI的數(shù)據(jù)大小:SPI發(fā)送接收8位幀結(jié)構(gòu)
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步時鐘的空閑狀態(tài)為高電平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步時鐘的第二個跳變沿(上升或下降)數(shù)據(jù)被采樣
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; //NSS信號由硬件(NSS管腳)還是軟件(使用SSI位)管理:內(nèi)部NSS信號有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定義波特率預(yù)分頻的值:波特率預(yù)分頻值為256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定數(shù)據(jù)傳輸從MSB位還是LSB位開始:數(shù)據(jù)傳輸從MSB位開始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值計算的多項式
SPI_Init(SPI2, &SPI_InitStructure); //根據(jù)SPI_InitStruct中指定的參數(shù)初始化外設(shè)SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外設(shè)
SPI_I2S_ITConfig(SPI2,SPI_I2S_IT_RXNE,ENABLE);//開啟相關(guān)中斷
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;//SPI2中斷通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//搶占優(yōu)先級0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2; //子優(yōu)先級2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器、
}
u16 i;
void SPI2_IRQHandler(void)
{
//接收數(shù)據(jù)
if(SPI_I2S_GetITStatus(SPI2,SPI_I2S_IT_RXNE) != RESET)
{
i = SPI_I2S_ReceiveData(SPI2);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI2,i);
USART_senddate(USART1, i);
}
}
到了這里,關(guān)于STM32使用SPI協(xié)議主從通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!