赞
踩
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主模式全双工连续传输模式下的时序图,
上图选择的是模式3,SCK高电平为空闲状态,在SCK第一个边沿移出数据,第二个编译移入数据。上面时序图采用小端模式,低位先行,这里对进行分析
发送:
接收:
由上图可知,SPI全双工连续通信是交叉进行的,发送数据1,发送数据2,再接收数据1;发送数据3,再接收数据2;在时序上要求操作之间的间隙非常小。
非连续传输模式,只需要四行代码。上图是SPI模式3,SCK高电平为空闲状态,分析如下
整体流程就是:等待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->PB0,MISO->PB4,MOSI->PB5,SCK->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_SCK,PB4复用为SPI1_MISO,PB5复用为SPI1_MOSI GPIO_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模拟片选信号SS GPIO_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; //软件模拟片选SS SPI_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 = 1 SPI_I2S_SendData(SPI1, ByteSend); //将数据写入到DR中 while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET); //等待RXNE = 1 return SPI_I2S_ReceiveData(SPI1); //读取RDR的数据 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。