SPI 模式 0 的时钟极性(CPOL)为 0,时钟相位(CPHA)为 0。CPOL = 0 意味着时钟信号空闲时为低电平,CPHA = 0 表示在时钟信号的第一个跳变沿(上升沿)进行数据采样。
#include "stm32f10x.h"
// 定义SPI引脚
#define SPI_SCK_PIN GPIO_Pin_5
#define SPI_MISO_PIN GPIO_Pin_6
#define SPI_MOSI_PIN GPIO_Pin_7
#define SPI_CS_PIN GPIO_Pin_4
#define SPI_GPIO_PORT GPIOA
// 初始化SPI引脚
void SoftwareSPI_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置SCK和MOSI为推挽输出
GPIO_InitStructure.GPIO_Pin = SPI_SCK_PIN | SPI_MOSI_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStructure);
// 配置MISO为浮空输入
GPIO_InitStructure.GPIO_Pin = SPI_MISO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStructure);
// 配置CS为推挽输出
GPIO_InitStructure.GPIO_Pin = SPI_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStructure);
// 使能CS
GPIO_SetBits(SPI_GPIO_PORT, SPI_CS_PIN);
// 空闲时SCK为低电平
GPIO_ResetBits(SPI_GPIO_PORT, SPI_SCK_PIN);
}
// 发送一个字节数据
uint8_t SoftwareSPI_SendByte(uint8_t byte) {
uint8_t i;
uint8_t receivedByte = 0;
for (i = 0; i < 8; i++) {
// 设置MOSI引脚状态
if (byte & 0x80) {
GPIO_SetBits(SPI_GPIO_PORT, SPI_MOSI_PIN);
} else {
GPIO_ResetBits(SPI_GPIO_PORT, SPI_MOSI_PIN);
}
// 拉高时钟信号,产生上升沿
GPIO_SetBits(SPI_GPIO_PORT, SPI_SCK_PIN);
// 读取MISO引脚状态(上升沿采样)
receivedByte <<= 1;
if (GPIO_ReadInputDataBit(SPI_GPIO_PORT, SPI_MISO_PIN)) {
receivedByte |= 0x01;
}
// 拉低时钟信号
GPIO_ResetBits(SPI_GPIO_PORT, SPI_SCK_PIN);
// 移动到下一位
byte <<= 1;
}
return receivedByte;
}
// 主函数示例
int main(void) {
SoftwareSPI_Init();
// 使能CS
GPIO_ResetBits(SPI_GPIO_PORT, SPI_CS_PIN);
// 发送一个字节数据
uint8_t sentByte = 0xAA;
uint8_t receivedByte = SoftwareSPI_SendByte(sentByte);
// 禁用CS
GPIO_SetBits(SPI_GPIO_PORT, SPI_CS_PIN);
while (1) {
// 主循环
}
}