环境
芯片:STM32F103ZET6
库:来自HAL的STM32F1XX.H
原理图

Driver_sip.h
#ifndef __DRIVER_SPI
#define __DRIVER_SPI
#include "stm32f10x.h"// 片选信号翻转
#define CS_HIGH (GPIOC->ODR |= GPIO_ODR_ODR13)
#define CS_LOW (GPIOC->ODR &= ~GPIO_ODR_ODR13)// 主设备发送信号
#define MOSI_HIGH (GPIOA->ODR |= GPIO_ODR_ODR7)
#define MOSI_LOW (GPIOA->ODR &= ~GPIO_ODR_ODR7)// 时钟翻转
#define SCK_HIGH (GPIOA->ODR |= GPIO_ODR_ODR5)
#define SCK_LOW (GPIOA->ODR &= ~GPIO_ODR_ODR5)// 主设备读取信号
#define MISO_READ (GPIOA->IDR & GPIO_IDR_IDR6)void Driver_SPI_Init(void);void Driver_SPI_Start(void);
void Driver_SPI_Stop(void);/*** 使用SPI通信交换主从设备数据* uint8_t byte: 发送的数据 包含指令* return: 接收的数据 包含指令或ID */
uint8_t Driver_SPI_SwapByte(uint8_t byte);#endif
Driver_sip.c
#include "Driver_spi.h"void Driver_SPI_Init(void)
{/* 1. 打开时钟 PA PC */RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;/* 2. 配置引脚模式 */// 2.1 输出线统一使用通用推挽输出 0011 CS PC13 MOSI PA7 SCK PA5GPIOA->CRL &= ~(GPIO_CRL_CNF5 | GPIO_CRL_CNF7);GPIOA->CRL |= (GPIO_CRL_MODE5 | GPIO_CRL_MODE7);GPIOC->CRH &= ~(GPIO_CRH_CNF13);GPIOC->CRH |= (GPIO_CRH_MODE13);// 2.2 输入线统一接收数据 浮空输入 0100 MISO PA6GPIOA->CRL &= ~(GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6);GPIOA->CRL |= GPIO_CRL_CNF6_0;/* 3. 修改引脚的初始值 */// 3.1 默认不片选CS_HIGH;// 3.2 选择SPI模式0 初始空闲时钟信号为0SCK_LOW;
}void Driver_SPI_Start(void)
{CS_LOW;
}
void Driver_SPI_Stop(void)
{CS_HIGH;
}// 一定要在SPI_START之后调用
uint8_t Driver_SPI_SwapByte(uint8_t byte)
{uint8_t rbyte = 0;for (uint8_t i = 0; i < 8; i++){// 1. 准备要发送的数据if (byte & 0x80){MOSI_HIGH;}else{MOSI_LOW;}byte <<= 1;// 2. 上升沿发送数据SCK_HIGH;// 3. 同时需要在高电平的时候读取从设备发送的数据rbyte <<= 1;if (MISO_READ){rbyte |= 0x01;}// 4. 下降沿结束当前一次收发SCK_LOW;}return rbyte;
}