做网站的主营业务,简单网站制作成品,网站公司市场营销方案,中宁网站建设SPI外设
一、简介 STM32F4XX内部集成硬件SPI收发电路#xff0c;可以由硬件自动执行时钟生成、数据收发等功能#xff0c;减轻CPU负担#xff0c;可配置8位/16位数据帧#xff0c;高位#xff08;最常用#xff09;/低位先行#xff0c;三组SPI接口#xff0c;支持DMA…SPI外设
一、简介 STM32F4XX内部集成硬件SPI收发电路可以由硬件自动执行时钟生成、数据收发等功能减轻CPU负担可配置8位/16位数据帧高位最常用/低位先行三组SPI接口支持DMA 由上图可知SPI是通过接收/发送缓冲区和移位寄存器进行通信其中SPI1是在APB2总线SPI2、SPI3在APB1总线。发送和接收共用一个SR即SPI是同步通信接口。SS引脚一般用GPIO口指定从机硬件NSS引脚一般是用来配置多主机模式。 发送数据先进入TDR经SR通过MOSI向从机输出 接收数据由MISO进入SR然后经过RDR向地址数据总线输出 由此可对上面SPI框图进行简化基本结构如下 这里给出SPI主模式全双工连续传输模式下的时序图 上图选择的是模式3SCK高电平为空闲状态在SCK第一个边沿移出数据第二个编译移入数据。上面时序图采用小端模式低位先行这里对进行分析 发送
SS置低电平开始时序选中从机。此时TXE 1TDR为空RXNE 0RDR为空。BSY 1软件写入0xF1到SPI_DR即要发送的第一个数据此时TXE 0RXNE 0TDR非空TDR中的0xF1会立刻转入到SR中TDR清空MOSI开始发送同时TXE 1软件等待TXE 1然后写入0xF2到SPI_DR即要发送的第二个数据此时TXE 0RXNE 0TDR中的0xF2会随后自动进入SRMOSI在发送完第一个数据会自动发送第二个数据TDR发送完所有数据TXE会自动置1SR发送完所有数据后BSY 0
接收
SS置低电平开始时序选中从机。此时TXE 1TDR为空RXNE 0RDR为空。BSY 1MISO依次接收从机的数据输出到SRSR中的数据以小端模式进入到SPI_DR中软件等待RXNE 1然后数据总线读取RDR中的数据0xA1同时RXNE 0RDR变为空MISO接收第二个数据输出到SRSR中的第二个数据以小端模式进入到SPI_DR中软件等待RXNE 1然后数据总线读取RDR中的第二个数据同时RXNE 0RDR变为空RDR接收完所有数据RXNE 0
由上图可知SPI全双工连续通信是交叉进行的发送数据1发送数据2再接收数据1发送数据3再接收数据2在时序上要求操作之间的间隙非常小。 非连续传输模式只需要四行代码。上图是SPI模式3SCK高电平为空闲状态分析如下
SS置低电平选中从机开始时序此时TXE 1RXNE 0TDR为空软件写入0xF1到SPI_DR此时TDR 0xF1TXE 0TDR中的0xF1立即进入SR中MOSI开始发送0xF1TDR清空TXE 1等待MOSI将第一个字节数据发送完毕此时接收第一个字节数据的时序也完成即RXNE 1读取接收到的第一个字节数据然后将第二个字节数据写入TDR开始发送第二个数据等待MOSI发送完第二个字节数据此时接收到了第二个字节数据读取完第二个字节数据然后将第三个字节数据写入TDR开始发送第三个数据
整体流程就是等待TXE 1写入数据到TDR等待RXNE 1读取RDR数据。这样实现发送数据1接收数据1发送数据2接收数据2。但是字节之间存在一定的间隙降低传输效率。
二、实验案例
进行STM32F4XX对板载W25Q16读写代码如下
#include stm32f4xx.h // Device header//硬件SPI通信采用非连续传输方案
/*PB0引脚模拟SS输出*/
void MySPI_W_SS(uint8_t BitValue)
{GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)BitValue);//片选引脚输出
}/*SS-PB0MISO-PB4MOSI-PB5SCK-PB3板载W25Q16支持SPI模式0和模式3*/
/*
* SPI1是在APB2总线SPI2、SPI3在APB1总线
* PB3: SPI1_SCK、SPI3_SCK
* PB4: SPI1_MISO、SPI3_MISO
* PB5: SPI1_MOSI、SPI3_MOSI
* PB0: 使用GPIO模拟SS
*/
void MySPI_Init()
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF;GPIO_InitStructure.GPIO_Pin GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; //PB3复用为SPI1_SCKPB4复用为SPI1_MISOPB5复用为SPI1_MOSIGPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP;GPIO_InitStructure.GPIO_OType GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB, GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode GPIO_Mode_OUT;GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; //使用GPIO模拟片选信号SSGPIO_Init(GPIOB, GPIO_InitStructure);GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1); //GPIO引脚复用GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);//SPI配置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;SPI_InitStructure.SPI_CRCPolynomial 7; //CRC校验根据实际需求填写SPI_InitStructure.SPI_DataSize SPI_DataSize_8b; //数据帧大小SPI_InitStructure.SPI_Direction SPI_Direction_2Lines_FullDuplex;//全双工SPI_InitStructure.SPI_FirstBit SPI_FirstBit_MSB; //高位先行SPI_InitStructure.SPI_Mode SPI_Mode_Master; //这里选择主机SPI_InitStructure.SPI_NSS SPI_NSS_Soft; //软件模拟片选SSSPI_Cmd(SPI1, ENABLE);// MySPI_W_SS(1); //默认是终止条件
}/*起始条件*/
void MySPI_Start()
{MySPI_W_SS(0);
}
/*终止条件*/
void MySPI_End()
{MySPI_W_SS(1);
}
/*交换一个字节这里选择模式0*/
/* SCK低电平为空闲状态
* SS下降沿启动主机移出高位数据到MOSI
* SCK上升沿主机移入高位数据MISO
* SCK下降沿主机移出高位数据MOSI
* 非连续传输需要四步
*/
uint8_t MySPI_SwapByte_Mode0(uint8_t ByteSend)
{while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) ! SET); //等待TXE 1SPI_I2S_SendData(SPI1, ByteSend); //将数据写入到DR中while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) ! SET); //等待RXNE 1return SPI_I2S_ReceiveData(SPI1); //读取RDR的数据
}