控制/MCU
SPI是一种高速的,全双工,同步的通信总线,原理和使用简单,占用引脚资源少,是一种常用的通信方式。STM32通常有2~3个SPI接口。
使用SPI控制器时,GPIO引脚的模式配置就要改为复用功能了,复用为SPI1功能。由于片选信号引脚没有连接到STM32中SPI1的NCC引脚上,所以片选信号引脚仍要设置为通用输出模式。
配置完GPIO口,接下来就要配置SPI1功能了。
SPI控制寄存器1(SPI_CR1)
双向通信数据模式使能位BIDIMODE(Bidirectional data mode enable)在位15,置0为选择双线单向通信数据模式,置1为选择单线双向通信数据模式。
双向通信模式下的输出使能位BIDIOE (Output enable in bidirectional mode)在位14,此位结合 BIDIMODE 位,用于选择双向通信模式下的传输方向,置0为禁止输出(只接收模式),置1为使能输出(只发送模式)。
数据帧格式位DFF (Data frame format)在位11,置0为发送/接收选择8位数据帧格式,置1为发送/接收选择16为数据帧格式。为确保正确操作,只应在禁止SPI时对此位执行操作。
软件从器件管理位SSM (Software slave management)在位9,当SSM置1时,NSS引脚输入替换为SSI位的值。
帧格式位LSBFIRST (Frame format)在位7,置0时先发送MSB,置1时先发送LSB。正在通信时不应更改此位。
SPI 使能位SPE (SPI enable)在位6,置0时关闭外设,置1时使能外设。
波特率控制位BR(Baud rate control)[2:0]在位3~5,000时为fPCLK/2,001时为fPCLK/4,010时为fPCLK/8,011时为fPCLK/16,100时为fPCLK/32,101时为fPCLK/64,110时为fPCLK/128,111时为fPCLK/256。正在通信时不应更改这些位。
主模式选择位MSTR (Master selection)在位2,置0时为从配置,置1时为主配置。正在通信时不应更改此位。
时钟极性位CPOL (Clock polarity)在位1,置0时,空闲状态时,SCK保持低电平;置1时,空闲状态时,SCK保持高电平。正在通信时不应更改此位。
时钟相位位CPHA (Clock phase)在位0,置0时从第一个时钟边沿开始采样数据,置1时从第二个时钟边沿开始采样数据。正在通信时不应更改此位。
//F_CS:PB14
//SPI1_SCK:PB3
//SPI1_MISO:PB4 - >输入
//SPI1_MOSI:PB5
void Spi1_Init()
{
//1. 开端口时钟
RCC- >AHB1ENR |= 1< < 1;
//2. 设置模式(复用:PB3/4/5)、通用输出:PB14
GPIOB- >MODER &= ~(0X3< < 28);
GPIOB- >MODER |= 1< < 28;
GPIOB- >MODER &= ~(0X3F< < 6);
GPIOB- >MODER |= 2< < 6 | 2< < 8 | 2< < 10;
//3. 设置输出类型、输出速度
GPIOB- >OTYPER &= ~(1< < 14 | 1< < 3 | 1< < 5); //推挽
GPIOB- >OSPEEDR &= ~(0X3< < 28 | 0X3F< < 6);
GPIOB- >OSPEEDR |= 1< < 28; //25mHZ
GPIOB- >OSPEEDR |= 2< < 6 | 2< < 8 | 2< < 10;
//4. 上下拉
GPIOB- >PUPDR &= ~(0X3F< < 6 | 0X3< < 28);
//5. 复用功能选择
GPIOB- >AFR[0] &= 0XFF000FFF;
GPIOB- >AFR[0] |= 0X00555000; //复用为SPI1
//6. 开spi1模块时钟
RCC- >APB2ENR |= 1< < 12;
//7. 传输方式(两线)、帧数据位数(8),校验(无)、设置先发位(高位)
SPI1- >CR1 = 0;
SPI1- >CR1 |= 0X3< < 8; //ssm=1,ssi=1,采用软件管理
//8. 波特率、模式(主)
SPI1- >CR1 |= 1< < 3; //波特率为:21M,最高可设置42M
SPI1- >CR1 |= 1< < 2;
//9. 极性、相位(模式0、模式3均可)
SPI1- >CR1 |= 3< < 0; //模式3
//使能SPI
SPI1- >CR1 |= 1< < 6;
}
SPI状态寄存器(SPI_SR)
发送缓冲区为空判断位TXE (Transmit buffer empty)在位1,置0时发送缓冲区非空,置1时发送缓冲区为空。
接收缓冲区非空判断位RXNE (Receive buffer not empty)在位0,置0时接收缓冲区为空,置1时接收缓冲区非空。
GPIO口和复用功能配置好后,就是数据的收发了,现在不再判断输入输出口的电平来收发数据。发送数据时通过判断状态寄存器的发送缓冲区是否为空,再把数据送到数据寄存器。接收数据时通过判断接收缓冲区是否有数据,再从数据寄存器读取数据。
//spi收发
//发数据,高位在前
u8 Spi1_RevSendByte(u8 dat)
{
//发送数据
while((SPI1- >SR & (1< < 1)) == 0);
SPI1- >DR = dat;
//接收数据
while((SPI1- >SR & (1< < 0)) == 0);
dat = SPI1- >DR;
return dat;
}
配置为SPI控制器读写W25Q64,只要更改以上两个函数就可以了。主函数仍为串口接收文件并保存。程序编译后烧入开发板,串口发送main.c文件并保存到W25Q64,从W25Q64读取并打印保存的内容,与main.c文件完全一致,SPI控制器读写W25Q64成功。
SPI控制器读写W25Q64与IO口模拟SPI读写W25Q64相比,使用SPI控制器时只需配置寄存器就可以由硬件自动产生时序,不需要STM32通过软件模拟构造,减少了对CPU资源的消耗。
全部0条评论
快来发表一下你的评论吧 !