硬件配置结构&非连续传输
- SPI的硬件配置结果如图:

- 非连续传输
非连续传输的特点如下:
①帧间可延迟:最大的特点就是允许在发送多帧数据时,在帧与帧之间插入延迟。软件可以等待某些条件(如处理完接收数据、检查某个引脚状态等)后再决定是否及何时发送下一帧。
②BSY贯穿始终:只要开始了传输,BSY就会一直为1,直到最后一帧的最后一刻。因此,不能使用BSY来判断何时可以发送下一帧数据(这是TXE的工作),而应用来判断一次完整的通信是否完全结束。
③SCK时钟会暂停:在非连续传输的帧间隔期间,SCK时钟会停止,直到下一个数据被写入SPI_DR后才会继续产生时钟。这与连续传输中时钟不间断产生形成鲜明对比。

硬件SPI读写W25Q64
- 接线图与软件SPI读写W25Q64的接线图一样:

- 修改软件SPI读写W25Q64的MySPI.c的代码,其他代码保持不变.
MySPI.c代码:
#include "stm32f10x.h" // Device header
//片选
void MySPI_W_SS(uint8_t BitValue)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_4,BitValue);
}
void MySPI_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
//配置片选引脚推挽输出
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置SCK和MOSI引脚为复用推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置MISO引脚为上拉输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
//配置CRC,大多数不使用,使用默认值7
SPI_InitStructure.SPI_CRCPolynomial = 7;
//配置8位还是16位数据帧
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
//配置单双工,接收发送
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
//配置高位先行还是低位先行
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
//配置STM32为主机
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
//配置片选信号时由软件还是硬件给出
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_Init(SPI1,&SPI_InitStructure);
SPI_Cmd(SPI1,ENABLE);
//置片选信号默认位高电平,不选中从机
MySPI_W_SS(1);
}
//开始信号
void MySPI_Start(void)
{
MySPI_W_SS(0);
}
//结束信号
void MySPI_Stop(void)
{
MySPI_W_SS(1);
}
//模式0输出一个字节
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
//SET表示发送寄存器已空
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) != SET);
SPI_I2S_SendData(SPI1,ByteSend);
//当接收完成后即发送完成
//接收完成的标志时判断接收寄存器是否满了,即RXNE是否为1
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) != SET);
return SPI_I2S_ReceiveData(SPI1);
}
////模式0输出一个字节(移位寄存器模型)
//uint8_t MySPI_SwapByte(uint8_t ByteSend)
//{
// uint8_t i;
// for(i=0;i<8;i++)
// {
// MySPI_W_MOSI(ByteSend & 0x80);
// ByteSend <<= 1;
// MySPI_W_SCK(1);
// if(MySPI_R_MISO() == 1){ByteSend |= 0x01;}
// MySPI_W_SCK(0);
// }
//
// return ByteSend;
//}
值得注意的是:
①使用的是SPI的模式0来读写W25Q64
②初始化时要将片选信号置为1,保证还没有选中任何从机
③在函数MySPI_SwapByte();中,想要发送一个字节或接收一个字节(接受字节必须要用数据与从机交换),先要判断发送机寄存器是否为空(即TEX标志位是否置为1),为空则向发送寄存器传入待发送字节,移位寄存器会将该字节从发送寄存器中取出,左移(高位先行)发送,同时,接收从机交换过来的数据到低位,将该待发送的1字节数据发送完毕后也就接收从机的1字节数据接收完毕,之后,在移位寄存器内的接收好的从机的1字节数据会被转移到接收寄存器,此时接收寄存器标志位RNXE被置为1(即SET),表示接收完成(交换数据完成),这也解释了为什么有这句代码:while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) != SET);,意思就是当接收完成后即发送完成,只需要判断接收寄存器的数据是否满了就知道发送的数据是否完成了.
④本工程采用非连续发送数据的方式.
- 硬件配置SPI(SPI1,软件控制片选时序)的流程图如下:
软件/硬件波形对比

可以看出硬件在每个SCK的边沿立即触发下一步,而软件则稍微慢些
1994

被折叠的 条评论
为什么被折叠?



