SPI外設(shè)簡介
1.STM32內(nèi)部集成了硬件SPI收發(fā)電路,可以由硬件自動執(zhí)行時鐘生成、數(shù)據(jù)收發(fā)等功能,減輕CPU的負擔(dān)
2.可配置8位/16位數(shù)據(jù)幀、高位先行/低位先行
3.時鐘頻率: fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)
4.支持多主機模型、主或從操作
5.可精簡為半雙工/單工通信
6.支持DMA
7.兼容I2S協(xié)議
STM32F103C8T6 硬件SPI資源:SPI1(APB2外設(shè),72MHZ)、SPI2(APB1外設(shè),32MHZ)
SPI框圖
LSBFIRST控制位:配置低位或者高位先行
接收緩沖區(qū):RDR -----發(fā)送緩沖區(qū):TDR {二者配合實現(xiàn)無延遲傳輸}
BR[2:0]:時鐘分頻
TXE:發(fā)送寄存器空
RXNE:接收寄存器非空
NSS:實現(xiàn)多主機
SPI基本結(jié)構(gòu)
主模式全雙工連續(xù)傳輸
非連續(xù)傳輸
文章來源:http://www.zghlxwxcb.cn/news/detail-859546.html
軟件/硬件波形對比
文章來源地址http://www.zghlxwxcb.cn/news/detail-859546.html
STM32硬件SPI代碼
STM32外設(shè)SPI庫函數(shù)詳解
void SPI_I2S_DeInit(SPI_TypeDef* SPIx);
//恢復(fù)缺省配置
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
//SPI初始化
void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct);
//I2S初始化
void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct);
//SPI結(jié)構(gòu)體變量初始化
void I2S_StructInit(I2S_InitTypeDef* I2S_InitStruct);
//I2S結(jié)構(gòu)體變量初始化
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
//SPI外設(shè)Cmd使能
void I2S_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
//I2SCmd外設(shè)使能
void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);
//中斷使能
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
//使能或者失能SPIx/I2Sx的DMA接口
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
//寫DR數(shù)據(jù)寄存器,發(fā)送字節(jié)
/*注釋:數(shù)據(jù)的發(fā)送和接收可以是8位或者16位的。為保證正確的操作,需要在啟用SPI之前就確定好數(shù)據(jù)幀格式*/
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
//讀DR數(shù)據(jù)寄存器,接收字節(jié)
/*注釋:數(shù)據(jù)的發(fā)送和接收可以是8位或者16位的。為保證正確的操作,需要在啟用SPI之前就確定好數(shù)據(jù)幀格式*/
void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* SPIx, uint16_t SPI_NSSInternalSoft);
//通過軟件內(nèi)部配置選定SPI的NSS引腳
void SPI_SSOutputCmd(SPI_TypeDef* SPIx, FunctionalState NewState);
//使能或者失能SS輸出
void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize);
//為所選SPI配置數(shù)據(jù)幀大小,8/16位數(shù)據(jù)幀配置
void SPI_TransmitCRC(SPI_TypeDef* SPIx);
//發(fā)送SPIx的CRC校驗值
void SPI_CalculateCRC(SPI_TypeDef* SPIx, FunctionalState NewState);
//使能或失能硬件CRC校驗
/*只有在禁止SPI時(SPE=0),才能寫該位,否則出錯;該位只能在全雙工模式下使用;I2S模式下不使用*/
uint16_t SPI_GetCRC(SPI_TypeDef* SPIx, uint8_t SPI_CRC);
//返回指定SPI的發(fā)送或接收CRC寄存器值
/*當(dāng)BSY標(biāo)志為’1’時讀該寄存器,將可能讀到不正確的數(shù)值; 在I2S模式下不使用*/
uint16_t SPI_GetCRCPolynomial(SPI_TypeDef* SPIx);
//返回指定SPI的CRC多項式寄存器值
/*該寄存器包含了CRC計算時用到的多項式;在I2S模式下不使用*/
void SPI_BiDirectionalLineConfig(SPI_TypeDef* SPIx, uint16_t SPI_Direction);
//為指定的SPI選擇雙向模式下的數(shù)據(jù)傳輸方向
/*雙向模式下的輸出使能,決定在“單線雙向”模式下數(shù)據(jù)的輸出方向,這個“單線”數(shù)據(jù)線在主設(shè)備端為MOSI引腳,在從設(shè)備端為MISO引腳,在I2S模式下不使用*/
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
//檢查指定的SPI/I2S標(biāo)志是否設(shè)置
void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
//清除指定標(biāo)志位
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
//檢查指定的SPI/I2S中斷是否發(fā)生
void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
//清除中斷標(biāo)志位
STM32硬件SPI.c配置
#include "stm32f10x.h" // Device header
/**
* 函 數(shù):SPI寫SS引腳電平,SS仍由軟件模擬
* 參 數(shù):BitValue 協(xié)議層傳入的當(dāng)前需要寫入SS的電平,范圍0~1
* 返 回 值:無
* 注意事項:此函數(shù)需要用戶實現(xiàn)內(nèi)容,當(dāng)BitValue為0時,需要置SS為低電平,當(dāng)BitValue為1時,需要置SS為高電平
*/
void MySPI_W_SS(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_12, (BitAction)BitValue); //根據(jù)BitValue,設(shè)置SS引腳的電平
}
/**
* 函 數(shù):SPI2初始化
* 參 數(shù):無
* 返 回 值:無
*/
void MySPI_Init(void)
{
/*************開啟時鐘********************/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //開啟GPIOA的時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); //開啟SPI1的時鐘
/************GPIO初始化*******************/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //將PB12引腳初始化為推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //將PB13和PB15引腳初始化為復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //將PB14引腳初始化為上拉輸入
/***************SPI初始化*****************/
SPI_InitTypeDef SPI_InitStructure; //定義結(jié)構(gòu)體變量
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //模式,選擇為SPI主模式
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //方向,選擇2線全雙工
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //數(shù)據(jù)寬度,選擇為8位
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //先行位,選擇高位先行
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; //波特率分頻,選擇128分頻
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //SPI極性,選擇低極性
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //SPI相位,選擇第一個時鐘邊沿采樣,極性和相位決定選擇SPI模式0
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS,選擇由軟件控制
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC多項式,暫時用不到,給默認值7
SPI_Init(SPI2, &SPI_InitStructure); //將結(jié)構(gòu)體變量交給SPI_Init,配置SPI2
/***************SPI使能*******************/
SPI_Cmd(SPI2, ENABLE); //使能SPI2,開始運行
/*設(shè)置默認高電平-----不選中從機*/
MySPI_W_SS(1); //SS默認高電平
}
/**
* 函 數(shù):SPI起始
* 參 數(shù):無
* 返 回 值:無
*/
void MySPI_Start(void)
{
MySPI_W_SS(0); //拉低SS,開始時序
}
/**
* 函 數(shù):SPI終止
* 參 數(shù):無
* 返 回 值:無
*/
void MySPI_Stop(void)
{
MySPI_W_SS(1); //拉高SS,終止時序
}
/**
* 函 數(shù):SPI交換傳輸一個字節(jié),使用SPI模式0
* 參 數(shù):ByteSend 要發(fā)送的一個字節(jié)
* 返 回 值:接收的一個字節(jié)
*/
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) != SET); //等待發(fā)送數(shù)據(jù)寄存器空
SPI_I2S_SendData(SPI2, ByteSend); //寫入數(shù)據(jù)到發(fā)送數(shù)據(jù)寄存器,開始產(chǎn)生時序
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) != SET); //等待接收數(shù)據(jù)寄存器非空
return SPI_I2S_ReceiveData(SPI2); //讀取接收到的數(shù)據(jù)并返回
}
STM32硬件SPI.h配置
#ifndef __MYSPI_H
#define __MYSPI_H
void MySPI_Init(void);
void MySPI_Start(void);
void MySPI_Stop(void);
uint8_t MySPI_SwapByte(uint8_t ByteSend);
#endif
到了這里,關(guān)于STM32硬件SPI通信詳解-------附代碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!