SPI的基本框图:
总线框图:
主设备与从设备之间的通信:
SCLK:由主机提供的时钟信号
NSS:也称CS,片选信号
MOSI:主设备输出,从设备输入
MISO:主设备输入,从设备输出
内部结构:
SPI.H :
#ifndef __SPI_H
#define __SPI_H
#include "sys.h"
#define SPI_SPEED_2 0
#define SPI_SPEED_4 1
#define SPI_SPEED_8 2
#define SPI_SPEED_16 3
#define SPI_SPEED_32 4
#define SPI_SPEED_64 5
#define SPI_SPEED_128 6
#define SPI_SPEED_256 7
void SPI1_Init(void); //初始化SPI口
void SPI1_SetSpeed(u8 SpeedSet); //设置SPI速度
u8 SPI1_ReadWriteByte(u8 TxData);//SPI总线读写一个字节
#endif
SPI.C :
#include "spi.h"
void SPI1_Init(void)
{
RCC->APB2ENR |= 1<<12; //SPI ENABLE
RCC->APB2ENR |= 1<<2; //GPIOA ENABLE
GPIOA->CRL &= 0XFFFFF000;
GPIOA->CRL |= 0X00000BBB; //PA 0 1 2
GPIOA->ODR |= 7<<0;
SPI1->CR1 &= 0<<15;//双线双向
SPI1->CR1 &= 0<<10;//全双工
SPI1->CR1 &= 0<<13;//禁止CRC计算
SPI1->CR1 &= 0<<11;//8位数据帧格式
SPI1->CR1 |= 1<<9; //软件从设备管理
SPI1->CR1 &= 0<<7; //MSB 先行
SPI1->CR1 |= 1<<6; //开启SPI设备
SPI1->CR1 &= ~(7<<3);//二分频
SPI1->CR1 |= 1<<2; //配置为SPI主机
SPI1->CR1 |= 1<<1; //空闲状态SCK保持高电平
SPI1->CR1 |= 1<<0; //数据采样从第一个时钟边沿开始
}
u8 SPI1_ReadWriteByte(u8 TxData)
{
u16 retry = 0;
//SR位1:TXE发送缓冲标志位,为0表示发送缓冲非空,为1表示发送缓冲为空
while((SPI1->SR&1<<1)==0) //等待发送区空
{
retry++;
if(retry>0XFFFE)
return 0;
}
SPI1->DR = TxData; //发送一个byte
retry = 0;
while((SPI1->SR&0<<1)==0)//等待发送完一个byte
{
retry++;
if(retry>0XFFFE)return 0;
}
return SPI1->DR;
}
void SPI1_SetSpeed(u8 SpeedSet) //分频比为256 降频
{
SpeedSet &= 0X07; //限制范围
SPI1->CR1 &= 0XFFC7;
SPI1->CR1 |= SpeedSet<<3;//111: fPCLK/256
SPI1->CR1 |= 1<<6;
}
SPI接口时钟配置心得:在主设备这边配置SPI接口时钟的时候一定要弄清楚从设备的时钟要求,因为主设备这边的时钟极性和相位都是以从设备为基准的。因此在时钟极性的配置上一定要搞清楚从设备是在时钟的上升沿还是下降沿接收数据,是在时钟的下降沿还是上升沿输出数据。
参考自:https://blog.csdn.net/ce123_zhouwei/article/details/6897293