环境
芯片:STM32F103ZET6
库:来自HAL的STM32F1XX.H
原理图
![](https://i-blog.csdnimg.cn/direct/a2eb8b496e6c4920a6997d80b258ff22.png)
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 PA5
GPIOA->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 PA6
GPIOA->CRL &= ~(GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6);
GPIOA->CRL |= GPIO_CRL_CNF6_0;
/* 3. 修改引脚的初始值 */
// 3.1 默认不片选
CS_HIGH;
// 3.2 选择SPI模式0 初始空闲时钟信号为0
SCK_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;
}