《STM32从零开始学习历程》 |
您所在的位置:网站首页 › 原子号是什么 › 《STM32从零开始学习历程》 |
《STM32从零开始学习历程》@EnzoReventon SPI读取FLSAH ID相关链接: SPI物理层及FLASH芯片介绍 SPI协议层 SPI特性及架构 参考资料: [野火EmbedFire]《STM32库开发实战指南——基于野火霸天虎开发板》 [正点原子]STM32F4开发指南-库函数版本_V1.2 [ST]《STM32F4xx中文参考手册》 SPI协议及总线协议介绍 W25Q128产品数据手册 1 实现功能本实验为学习SPI的入门实验,主要功能是实现使用SPI发送读取FLASH ID的指令来读取FLASH ID。 2 硬件设计本文使用的外设为SPI1(正点原子F4探索者开发板)、FLASH以及USART1。 USART用来调试程序,我们还是使用USART1,因此将PB9,PB10与TX,RX相连接即可。 查阅正点原子F4探索者开发板硬件手册,了解SPI引脚与GPIO的对应情况。 ① 使能SPIx和IO口时钟 RCC_AHBxPeriphClockCmd() / RCC_APBxPeriphClockCmd(); ② 初始化IO口为复用功能 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); ③ 设置引脚复用映射: GPIO_PinAFConfig(); ② 初始化SPIx,设置SPIx工作模式 void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct); ③ 使能SPIx void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState); ④ 编写字节发送函数:uint8_t SPI_FLASH_ByteWrite(uint8_t data) 发送数据(指令):void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data); 接收返回的数据:uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ; ⑤ 查看SPI传输状态 SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE); ⑥ 编写SPI发送函数 控制片选引脚:GPIO_ResetBits()、GPIO_SetBits(); ⑦ 主函数调用 ⑧ 优化程序(超时函数、宏定义) 4 代码分析 宏定义 /*宏定义*/ /*SPI GPIO 接口*/ #define FLASH_SPI SPI1 #define FLASH_SPI_CLK RCC_APB2Periph_SPI1 #define FLASH_SPI_CLK_INIT RCC_APB2PeriphClockCmd #define FLASH_SPI_SCK_PIN GPIO_Pin_3 #define FLASH_SPI_SCK_GPIO_PORT GPIOB #define FLASH_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_SCK_SOURCE GPIO_PinSource3 #define FLASH_SPI_SCK_AF GPIO_AF_SPI1 #define FLASH_SPI_MOSI_PIN GPIO_Pin_5 #define FLASH_SPI_MOSI_GPIO_PORT GPIOB #define FLASH_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MOSI_SOURCE GPIO_PinSource5 #define FLASH_SPI_MOSI_AF GPIO_AF_SPI1 #define FLASH_SPI_MISO_PIN GPIO_Pin_4 #define FLASH_SPI_MISO_GPIO_PORT GPIOB #define FLASH_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MISO_SOURCE GPIO_PinSource4 #define FLASH_SPI_MISO_AF GPIO_AF_SPI1 #define FLASH_SPI_CS_PIN GPIO_Pin_14 #define FLASH_SPI_CS_GPIO_PORT GPIOB #define FLASH_SPI_CS_GPIO_CLK RCC_AHB1Periph_GPIOB /*等待超时时间*/ #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000) 初始化时钟、GPIO、引脚复用 ================================================ SPI GPIO初始化 复用函数 ================================================ */ static void SPI_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; FLASH_SPI_CLK_INIT(FLASH_SPI_CLK, ENABLE); //使能SPI时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1) /* 使能 FLASH_SPI 及GPIO 时钟 */ /*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO, SPI_FLASH_SPI_MISO_GPIO,SPI_FLASH_SPI_SCK_GPIO 时钟使能 */ RCC_AHB1PeriphClockCmd(FLASH_SPI_SCK_GPIO_CLK | FLASH_SPI_MOSI_GPIO_CLK| FLASH_SPI_MISO_GPIO_CLK|FLASH_SPI_CS_GPIO_CLK, ENABLE); //初始化GPIO时钟 //查看引脚,初始化SCK,MOSI,MISO,CS引脚GPIO //设置引脚复用 GPIO_PinAFConfig(FLASH_SPI_SCK_GPIO_PORT, FLASH_SPI_SCK_SOURCE, FLASH_SPI_SCK_AF); GPIO_PinAFConfig(FLASH_SPI_MOSI_GPIO_PORT, FLASH_SPI_MOSI_SOURCE, FLASH_SPI_MOSI_AF); GPIO_PinAFConfig(FLASH_SPI_MISO_GPIO_PORT, FLASH_SPI_MISO_SOURCE, FLASH_SPI_MISO_AF); /*!< 配置 SPI_FLASH_SPI 引脚: SCK */ GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(FLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure); /*!< 配置 SPI_FLASH_SPI 引脚: MISO */ GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN; GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure); /*!< 配置 SPI_FLASH_SPI 引脚: MOSI */ GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN; GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure); /*!< 配置 SPI_FLASH_SPI 引脚: CS */ GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure); } SPI功能初始化 /* ================================================ SPI 初始化结构体初始化 ================================================ */ void SPI_Mode_Config(void) { /*!< 初始化SPI结构体函数 */ SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2; //预分频2 SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge; //第1个跳变沿数据被采样 SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low; //串行同步时钟的空闲状态为低电平 SPI_InitStructure.SPI_CRCPolynomial=7; //CRC值计算的多项式 SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b; //SPI发送接收 8位帧结构 SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex; //双线双向全双工 SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB; //数据传输从 MSB位开始 SPI_InitStructure.SPI_Mode=SPI_Mode_Master; //主 SPI SPI_InitStructure.SPI_NSS=SPI_NSS_Soft; //NSS信号由软件控制 SPI_Init(FLASH_SPI,&SPI_InitStructure); SPI_Cmd(FLASH_SPI,ENABLE); } 使能GPIO初始化以及SPI功能初始化 /* ================================================ SPI FLASH 外设初始化 ================================================ */ void SPI_FLASH_Init(void) { SPI_GPIO_Config(); SPI_Mode_Config(); } SPI FLASH 字节写入函数 /* ================================================ 通过SPI发送一个字节 参数:要写入的数据 返回值:错误代码 ================================================ */ uint8_t SPI_FLASH_ByteWrite(uint8_t data) { //等待TXE标志=1 //判断是否超时 SPITimeOut = ((uint32_t)(10 * SPIT_FLAG_TIMEOUT)); //重置等待时间 while(SPI_I2S_GetFlagStatus(FLASH_SPI,SPI_I2S_FLAG_TXE) == RESET) { SPITimeOut--; if(SPITimeOut == 0) { return SPI_TIMEOUT_UserCallback(1); } } SPI_I2S_SendData(FLASH_SPI,data); //发送指令给FLASH //等待RXNE标志来确认发送完成,即准备读取数据 //判断是否超时 SPITimeOut = ((uint32_t)(10 * SPIT_FLAG_TIMEOUT)); //重置等待时间 while(SPI_I2S_GetFlagStatus(FLASH_SPI,SPI_I2S_FLAG_RXNE) == RESET) { SPITimeOut--; if(SPITimeOut == 0) { return SPI_TIMEOUT_UserCallback(2); } } return SPI_I2S_ReceiveData(FLASH_SPI); //返回FLASH返回的数据 } SPI读取FLASH ID函数![]() 下载程序至开发板,通过串口调试助手可以看到返回的FLASH ID为0x17h。 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |