技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152
由于工作原因,中间省略了,关于ADC,DAC等的内容,后面补上.
今天咱们讲解前三个
这里,首先SPI是个,高速的,全双工,同步通信总线,这个怎么来说呢?
同步就说,有个独立的发送引脚,有个独立的接收引脚,然后
还有一个时钟引脚,这个是干嘛用的呢,时钟是来控制数据发送的.
因为是同步所以需要时钟,我们知道异步的话,是需要用波特率来约定的.
这样就有三个引脚了,那么这里还有一个引脚,是片选引脚.
这个片选引脚的意思是,通过这个片选引脚可以让,这里的虽然只要一个接受引脚,一个发送引脚,
但是呢,可以用来接多个设备,比如这个设备SPI的片选引脚,连接到另一个设备的片选引脚上面
这样就可以实现,连接多个设备.
这里这个MISO的意思是m是master的意思,然后I是input,然后s是slave,从机的意思
然后o是output输出的意思.
首先因为我全双工的,那么每个终端需要两个引脚的,都是独立的,可以接收也可以发送.
然后,他是可以做主机,也可以做从机.
这里MISO的意思是,这个做主机的时候就是输入,做从机的时候,就是输出
MOSI的意思,作为主机的时候是输出,作为从机的时候是输入.
然后看一下图
可以看到按照左侧的,这里作为主机的时候master,这个时候是MISO,是输入,然后作为从机的时候,是
输出.
然后再看一下这里的移位寄存器.
这个移位寄存器的意思是,他可以把数据位一位一位的,移出去,这样就实现了数据的传输.
每移动一位,那么最高位就变成了次高位,次高位就变成了,原来的最高位,
然后对于环形移位寄存器:
这个环形移位寄存器的意思是这样的,
就是说比如右边的移位寄存器中的值是01010101,
然后左侧移位寄存器中的值是10101010,这个时候
左侧的移位寄存器,作为主机的话,那么就是MISO,从机作为输出
右边的从机会先把1,移到左边的主机MI主机作为输入,然后这样一位一位的移动,就会导致
最终,主机中的数据到了从机,从机中的数据到了主机.
这样,这个就像一个环形一样.
这个就是SPI的内部结构,主要了解这个移位寄存器
然后
然后这里,这里每当,咱们要写数据的时候,比如写入8字节,实际上调用的函数是readWrite也就是,这边写入了8个
字节的数据,那么就会再另一个移位寄存器中输入8个字节数据,这个类似于一个循环.
然后看一下SPI的接口创图,左上角,其实就是咱们说的,他怎么传数据,下面有个波特率发生器,右边就是一些控制
寄存器.
主机要读取数据的话,读取字节,那么从机要发送一个空字节来引发从机的传输.
主机通过向SPI串行寄存器写入一个字节来发起一次传输.
这里写了SPI的所有的特征,这里看看这个
可触发中断的专用发送和接收标志,也就是可以通过配置寄存器,使能位,
可以让这个接收发送,来触发中断.
接下来,挑几个重要的点来说明一下:
这里是NSS脚管理是这样的,NSS就是片选引脚,这个引脚的作用是,
可以让咱们的一个SPI去连接多个设备,也就是通过SPI的引脚,连接到MCU上,然后通过比如MCU的PA2连接一个设备
然后PA3连接一个设备,PA4也连接一个设备,然后,当我使用PA2对应的设备的时候,这个时候就可以把对应的设备对应的
片选拉低,其他的片选拉高,这样就可以实现这个设备的通信了.其他的设备占时不通信,
这样就实现了用一个SPI口,来实现控制多个SPI设备的方法.
这里的CPOL是指的是,没有数据传输时时钟的空闲状态电平,如果CPOL被设置为0,SCK引脚在空闲状态下保持低电平
如果CPOL设置为1,然后CPHA指的是时钟相位,这个指定了什么时候开始采集边沿,同时CPHA如果被设置为1,则在SCK时钟的
第二个边沿开始采集,然后如果CPHA被设置为0,就再SCK时钟的第一个边沿,进行采集.
这里的CPOL和CPHA有两个位,也就是4个组合
这里通过图再理解一下
也就是如果CPOL=1的话,那么就是高电平有效,也就是上面画的一个情况,
这个时候可以看到,第一个边沿是下降沿,第二个边沿是上升沿,如果这个时候CPHA=1的话,
那么就说明要从第二个边沿,也就是上升沿开始去采集.
如果CPOL=0的话,那么就是低电平有效,就是下面的那种情况
这个时候可以看到,第一个边沿是上升沿,第二个边沿是下降沿,如果这个时候CPHA=1的话,
那么就说明要从第二个边沿,也就是下降沿开始去采集.
同样,如果这里CPHA=0 的时候,那么,
CPOL=1是高电平有效,那么第一个边沿就是下降沿,这个时候CPHA=0,从第一个边沿开始采集,
就是从下降沿开始采集.
CPOL=0是低电平有效,那么第一个边沿就是上升沿,这个时候CPHA=0,从第一个边沿开始采集,
就是从上升沿开始采集.
比如我们的主机来连接从机,那么一般对从机的极性都是有严格要求的
这里就要求,我们需要根据从机的相位和极性等来,配置我们的主机的极性和相位
SPI的中断,一共有这几个中断事件,对应的事件标志位,
SPI数据寄存器就是存放数据的.
void SPI_I2S_DeInit(SPI_TypeDef* SPIx);
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
//这个用来设置是主机还是从机,数据帧是8位还是16位,
//然后LSB在前还是在后
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);//还有SPI的使能,要使能哪个SPI
void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);//要开启中断.
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
//还可以通过DMA来传输数据.
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);//是发送数据
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);//接收数据
void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize);//8位还是16位.
//下面是4个状态.
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
打开spi的实验:
这个SPI初始化的函数,第一个参数是哪个SPI这样,
然后第二个是一个结构体,这里看一下这个结构体.
来过一下这个参数
第一个是方向SPI_Direction
去定义看一下
对于方向可以是:
对于
typedef struct
{
uint16_t SPI_Direction;
uint16_t SPI_Mode;
uint16_t SPI_DataSize;
uint16_t SPI_CPOL;
uint16_t SPI_CPHA;
uint16_t SPI_NSS;
uint16_t SPI_BaudRatePrescaler;
uint16_t SPI_FirstBit;
uint16_t SPI_CRCPolynomial;
}SPI_InitTypeDef;
结构体成员变量比较多,这里我们挑取几个重要的成员变量讲解一下:
第一个参数 SPI_Direction 是用来设置 SPI 的通信方式, 可以选择为半双工,全双工,以及串行
发和串行收方式, 这里我们选择全双工模式 SPI_Direction_2Lines_FullDuplex。
第二个参数 SPI_Mode 用来设置 SPI 的主从模式,这里我们设置为主机模式 SPI_Mode_Master,
当然有需要你也可以选择为从机模式 SPI_Mode_Slave。
第三个参数 SPI_DataSiz 为 8 位还是 16 位帧格式选择项,这里我们是 8 位传输,选择
SPI_DataSize_8b。
第四个参数 SPI_CPOL 用来设置时钟极性, 我们设置串行同步时钟的空闲状态为高电平所以我
们选择 SPI_CPOL_High。
第五个参数 SPI_CPHA 用来设置时钟相位, 也就是选择在串行同步时钟的第几个跳变沿(上升
或下降)数据被采样, 可以为第一个或者第二个条边沿采集, 这里我们选择第二个跳变沿,所
以选择 SPI_CPHA_2Edge
第六个参数 SPI_NSS 设置 NSS 信号由硬件(NSS 管脚)还是软件控制,这里我们通过软件控
制 NSS 关键,而不是硬件自动控制,所以选择 SPI_NSS_Soft。
第七个参数 SPI_BaudRatePrescaler 很关键,就是设置 SPI 波特率预分频值也就是决定 SPI 的时
钟的参数, 从不分频道 256 分频 8 个可选值,初始化的时候我们选择 256 分频值
SPI_BaudRatePrescaler_256, 传输速度为 36M/256=140.625KHz。
第八个参数 SPI_FirstBit 设置数据传输顺序是 MSB 位在前还是 LSB 位在前, ,这里我们选择
SPI_FirstBit_MSB 高位在前。
第九个参数 SPI_CRCPolynomial 是用来设置 CRC 校验多项式, 提高通信可靠性, 大于 1 即可。
IO口的配置用下面的表格中配置
可以看到有两个数据口:
SPI2_MISO
SPI2_MOSI
一个时钟口:
SPI2_SCK
一个片选口:
F_CS
这里战舰版用到的口是
PB14 这个数据口 MISO
PB15 MOSI这个数据口
PB13这个是SPI2_SCK这个是时钟口
PB12对应的是片选口
战舰版这里用的是SPI2这个口.
然后对于mini版,对应的口是PA2 F_CS这个片选口
他用的SPI1这个口
然后由于:
W25Q128(W25Q64)将16M(8M)的容量分为256(128)个块(Block),每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K个字节。W25Qxx的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节。这样我们需要给W25Qxx开辟一个至少4K的缓存区,这样对SRAM要求比较高,要求芯片必须有4K以上SRAM才能很好的操作。
也就说在我们同SPI口写入数据的时候,要注意,在所有的写入数据的时候,操作是这样的,
要先把数据写入到缓存中区,而且缓存是4k,为什么要求4k呢,因为往flash中写入数据的时候
首先要写入一个地址的话,要必须,首先擦除一个扇区,只有先擦除了一个扇区的数据,然后
才能把后面的数据,写入到这个扇区中去,而扇区是flash的最小的单位,这个最小的单位就是4k.
这个文件中记录这个命令.
比如这里读数据的命令等等,那么,这一讲先说到这里,下一讲继续说代码
下一讲会说,比如这类spi的初始化配置
w25qx的命令的用法等等.