1. 硬件连接
首先,你需要确保SPI接口的引脚连接正确。STM32F103的SPI接口有多个引脚,包括:
-
MOSI(Master Out Slave In):主设备数据输出引脚
-
MISO(Master In Slave Out):主设备数据输入引脚
-
SCK(Serial Clock):时钟信号引脚
-
NSS(Chip Select):片选信号引脚
这些引脚的具体位置可以在STM32F103的引脚定义表中找到。例如:
-
SPI1:
-
MOSI:PA7 或 PB5
-
MISO:PA6 或 PB4
-
SCK:PA5 或 PB3
-
NSS:PA4 或 PB2
-
-
SPI2:
-
MOSI:PB15
-
MISO:PB14
-
SCK:PB13
-
NSS:PB12
-
2. 使能SPI时钟
在配置SPI之前,需要先使能SPI接口的时钟。STM32F103有多个SPI接口(SPI1和SPI2),它们的时钟使能方式不同:
-
SPI1:
c复制
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
-
SPI2:
c复制
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
3. 配置SPI参数
SPI接口的参数包括主从模式、时钟速率、数据格式等。这些参数可以通过配置SPI初始化结构体SPI_InitTypeDef
来设置。以下是一个典型的配置示例:
c复制
SPI_InitTypeDef SPI_InitStructure;
// 选择SPI接口
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 全双工模式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 主设备模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 数据大小为8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // 时钟极性:高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // 时钟相位:第二个边沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 软件管理NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; // 时钟分频因子
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 数据传输从MSB开始
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC多项式
// 初始化SPI
SPI_Init(SPI1, &SPI_InitStructure);
4. 使能SPI
配置完参数后,需要使能SPI接口:
c复制
SPI_Cmd(SPI1, ENABLE);
5. 数据传输
SPI接口的数据传输可以通过以下函数实现:
-
发送数据:
c复制
SPI_I2S_SendData(SPI1, data); // 发送数据
-
接收数据:
c复制
data = SPI_I2S_ReceiveData(SPI1); // 接收数据
6. 检查忙标志
在发送或接收数据时,需要检查SPI接口是否忙:
c复制
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET); // 等待忙标志位清零
7. 检查发送完成标志
发送数据后,需要检查发送完成标志:
c复制
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送完成
8. 检查接收完成标志
接收数据后,需要检查接收完成标志:
c复制
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); // 等待接收完成
完整代码示例
以下是一个完整的SPI配置和数据传输示例代码:
c复制
#include "stm32f10x.h"
void SPI_Config(void) {
// 使能SPI时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
// 配置SPI参数
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_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
// 使能SPI
SPI_Cmd(SPI1, ENABLE);
}
void SPI_SendReceive(uint8_t data, uint8_t *recv_data) {
// 发送数据
SPI_I2S_SendData(SPI1, data);
// 等待发送完成
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
// 等待接收完成
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
// 读取接收数据
*recv_data = SPI_I2S_ReceiveData(SPI1);
}
int main(void) {
// 配置SPI
SPI_Config();
uint8_t send_data = 0x55;
uint8_t recv_data;
// 发送和接收数据
SPI_SendReceive(send_data, &recv_data);
// 打印接收数据
while (1);
}
注意事项
-
时钟配置:SPI的时钟速率取决于系统时钟和分频因子,确保配置的时钟速率符合你的需求。
-
引脚配置:确保SPI引脚的模式配置正确(推挽、浮空等)。
-
NSS管理:可以选择硬件NSS或软件NSS,硬件NSS需要外部电路支持。
-
中断和DMA:对于更复杂的应用,可以使用SPI中断或DMA来提高效率。