SPI(Serial Peripheral Interface),串行外围设备接口。SPI是一种高速的、全双工、同步的通信总线。
SPI接口一般使用4条线通信:
MISO 主设备数据输入,从设备数据输出
MOSI 主设备数据输出,从设备数据输入
SCLK 时钟信号,有主设备产生
CS 从设备片选信号,有主设备控制
SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置。SPI_CR寄存器的CPOL(时钟极性)位,控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。CPOL=0,串行同步时钟的空闲状态为低电平;CPOL=1,串行同步时钟的空闲状态为高电平。SPI_CR寄存器的CPHA(时钟相位)位,能配置用于选择两种不同的传输协议之一进行数据传输。CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。
1.SPI主模式配置步骤
①使能SPI时钟,配置PA口
APB2外设时钟使能寄存器(RCC_APB2ENR)
APB1外设复位寄存器 (RCC_APB1RSTR)
Eg:RCC->APB2ENR|=1<<2; //PORTA时钟使能
RCC->APB2ENR|=1<<12; //SPI1时钟使能
//这里只针对SPI口初始化
GPIOA->CRL&=0X000FFFFF;
GPIOA->CRL|=0XBBB00000;//PA5.6.7复用
GPIOA->ODR|=0X7<<5; //PA5.6.7上拉
②开全双工模式并软件管理NSS
SPI控制寄存器1(SPI_CR1)(I2S模式下不使用)
Eg:SPI1->CR1|=0<<10;//全双工模式
SPI1->CR1|=1<<9; //软件nss管理
SPI1->CR1|=1<<8;
③设置SPI为主机并设置数据帧格式
Eg:SPI1->CR1|=1<<2; //SPI主机
SPI1->CR1|=0<<11;//8bit数据格式
④设置时钟极性和相位极性
Eg:SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1
⑤传输速率和LSBFIRST帧格式设置
Eg:SPI1->CR1|=7<<3; //Fsck=Fcpu/256
SPI1->CR1|=0<<7; //MSBfirst
⑥使能SPI
Eg:SPI1->CR1|=1<<6; //SPI设备使能
2.SPI
1 //SPI口初始化 2 //这里针是对SPI1的初始化 3 void SPI1_Init(void) 4 { 5 RCC->APB2ENR|=1<<2; //PORTA时钟使能 6 RCC->APB2ENR|=1<<12; //SPI1时钟使能 7 8 //这里只针对SPI口初始化 9 GPIOA->CRL&=0X000FFFFF; 10 GPIOA->CRL|=0XBBB00000;//PA5.6.7复用 11 GPIOA->ODR|=0X7<<5; //PA5.6.7上拉 12 13 SPI1->CR1|=0<<10;//全双工模式 14 SPI1->CR1|=1<<9; //软件nss管理 15 SPI1->CR1|=1<<8; 16 17 SPI1->CR1|=1<<2; //SPI主机 18 SPI1->CR1|=0<<11;//8bit数据格式 19 SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1 20 SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1 21 SPI1->CR1|=7<<3; //Fsck=Fcpu/256 22 SPI1->CR1|=0<<7; //MSBfirst 23 SPI1->CR1|=1<<6; //SPI设备使能 24 SPI1_ReadWriteByte(0xff);//启动传输(主要作用:维持MOSI为高) 25 } 26 //SPI1 速度设置函数 27 //SpeedSet:0~7 28 //SPI速度=fAPB2/2^(SpeedSet+1) 29 //APB2时钟一般为72Mhz 30 void SPI1_SetSpeed(u8 SpeedSet) 31 { 32 SpeedSet&=0X07; //限制范围 33 SPI1->CR1&=0XFFC7; 34 SPI1->CR1|=SpeedSet<<3; //设置SPI1速度 35 SPI1->CR1|=1<<6; //SPI设备使能 36 } 37 //SPI1 读写一个字节 38 //TxData:要写入的字节 39 //返回值:读取到的字节 40 u8 SPI1_ReadWriteByte(u8 TxData) 41 { 42 u16 retry=0; 43 while((SPI1->SR&1<<1)==0)//等待发送区空 44 { 45 retry++; 46 if(retry>0XFFFE)return 0; 47 } 48 SPI1->DR=TxData; //发送一个byte 49 retry=0; 50 while((SPI1->SR&1<<0)==0) //等待接收完一个byte 51 { 52 retry++; 53 if(retry>0XFFFE)return 0; 54 } 55 return SPI1->DR; //返回收到的数据 56 }
spi.c
1 // SPI总线速度设置 2 #define SPI_SPEED_2 0 3 #define SPI_SPEED_4 1 4 #define SPI_SPEED_8 2 5 #define SPI_SPEED_16 3 6 #define SPI_SPEED_32 4 7 #define SPI_SPEED_64 5 8 #define SPI_SPEED_128 6 9 #define SPI_SPEED_256 7 10 11 void SPI1_Init(void); //初始化SPI口 12 void SPI1_SetSpeed(u8 SpeedSet); //设置SPI速度 13 u8 SPI1_ReadWriteByte(u8 TxData);//SPI总线读写一个字节 14 15 #endif
spi.h