当前位置: 首页 > news >正文

个人网站免费建设苏州艺术家网站建设

个人网站免费建设,苏州艺术家网站建设,seo快速排名工具,如何给网站增加图标一、 SPI通信驱动W25Qxx 1、使用驱动文件快速配置工程代码驱动W25Qxx #xff08;此驱动文件只适合W25Qxx 16M及以下型号#xff0c;因为访问地址位数不同#xff09; 注#xff1a;本次使用SPI的方式进行访问W25Qxx Flash进行数据读写#xff0c;关于W25Qxx芯片不会做…一、 SPI通信驱动W25Qxx 1、使用驱动文件快速配置工程代码驱动W25Qxx 此驱动文件只适合W25Qxx 16M及以下型号因为访问地址位数不同 注本次使用SPI的方式进行访问W25Qxx Flash进行数据读写关于W25Qxx芯片不会做介绍只在于如何配置代码使其能使用该芯片 关于SPI想使用CubeMx的方式配置代码解以参考我的文章– 4、HAL库SPI数据收发 编写好的驱动文件下载 链接https://pan.baidu.com/s/1r0JCrUNAHt6sGJ6D_tT0lg 提取码fxzn W25Qxx驱动文件(SPI通信 SCK MOSI MISO CS) 使用方法 1、添加文件到工程Common_Driver.c、spi_Driver.c、W25Qxx_Driver.c 2、spi_Driver.h文件 修改外设SPI1相应挂载的外设片选引脚 3、spi_Driver.c文件 修改SPI1相应通信线(CLK、MOSI、MISO)的引脚宏 4、W25Qxx_Driver.h文件 修改W25Qxx通信时使用的SPI句柄和外设宏SPIx、SPIxHandle 修改W25Qxx型号对应的宏sFLASH_ID 5、W25Qxx_Driver.h文件 开启调试宏(芯片是否正常,会进行擦除数据写入读出对比数据),调试完毕后屏蔽:_W25Qxx_Debug 6、调用SPI初始化函数MX_SPI1_Init()(此时SPI进入空闲,CS引脚空闲) 7、调用W25Qxx_InitCheck()函数检查芯片(执行完后芯片进入省电模式) 8、完毕 时序说明全双工SPI 线束:SCK|MOSI|MISO CS SPI模式 CPOL CPHA 空闲时 SCK 时钟 采样时刻 0 0 0 低电平 奇数边沿(W25Qxx支持) 1 0 1 低电平 偶数边沿 2 1 0 高电平 奇数边沿 3 1 1 高电平 偶数边沿(W25Qxx支持)当前使用 数据长度8 高位在前 速度配置为PCLK2/2分频 42MHz 注意W25Qxx底层读写采用的直接操作寄存器,所以需要在MX_SPI1_Init()函数中的HAL_SPI_Init()后调用__HAL_SPI_ENABLE(hspi1); 以此使能外设SPI使用HAL库自带的收发函数不需要此使能 此驱动文件只适合W25Qxx 16M及以下型号因为访问地址位数不同 W25Qxx_Driver.c文件中的所有函数需要先初始化SPI后才可以调用 本代码W25Qxx驱动时序指令代码参考野火教程 驱动源码 Common_Driver.c /********************************************************************** *file:常用通用函数 *author:残梦 *date:2023.2.13 *note: **********************************************************************/ #include Common_Driver.h #include usart_Driver.h/**************************************************** function:串口重定义 param:void return:void date:2023.2.14 note:使用printf时需要此函数并在Keil魔术棒中勾选User MicroLIB库 ****************************************************/ int fputc(int ch,FILE *f) {uint8_t data ch;HAL_UART_Transmit(huart1,data,1,1);return(ch); }/**************************************************** function:计算数据的拟合系数 param:*pA,*pB--系数x[],y[]--数据源dataSize--数据个数 return:void date:2021.11.6 note:yAxB ****************************************************/ void LinearFitCoefficient(double *pA,double *pB,double x[],double y[],unsigned short int dataSize) {unsigned short int i 0;double AverX 0.0f,AverY 0.0f,a1 0.0f,a2 0.0f;if(dataSize 0){*pA *pB 0.0;return;}else if(dataSize 1){*pA 0.0;*pB y[0];return;}while(i dataSize) {AverX x[i];AverY y[i];i;}AverX / (double)(dataSize);AverY / (double)(dataSize);a1 a2 0.0f;for(i0;idataSize;i){a1 (x[i] - AverX)*(y[i] - AverY);a2 (x[i] - AverX)*(x[i] - AverX);}*pA a1/a2;*pB AverY - (*pA)*AverX; }/**************************************************** function:系统错误死循环显示信息 param:void return:void date:2023.2.14 note:使用printf时需要此函数并在Keil魔术棒中勾选User MicroLIB库 ****************************************************/ void FunctionError(char *str) {while(1){if(str ! NULL){printf(%s,str);}HAL_Delay(500);} }/**************************************************** function:比较两个缓冲区中的数据是否相等 param:stringA、stringB--待比较的字符串指针Length--字符串待比较的长度不得大于stringA或stringB的长度 return:-1--不相等0--相等 date:2023.2.17 note: ****************************************************/ int StringCompare(uint8_t* stringA, uint8_t* stringB, uint16_t Length) {while(Length--){if(*stringA ! *stringB){return -1;}stringA;stringB;}return 0; }/**************************************************** function:计数延时 param:nCount--待延时的大小 return:void date:2023.2.17 note: ****************************************************/ void EmptyDelay(uint32_t nCount) {while(nCount--); } Common_Driver.h #ifndef _Common_Driver_H_ #define _Common_Driver_H_ #include main.h #include stdio.h #include string.htypedef int32_t s32; typedef int16_t s16; typedef int8_t s8;typedef const int32_t sc32; typedef const int16_t sc16; typedef const int8_t sc8; typedef __IO int32_t vs32; typedef __IO int16_t vs16; typedef __IO int8_t vs8;typedef __I int32_t vsc32; typedef __I int16_t vsc16; typedef __I int8_t vsc8; typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8;typedef const uint32_t uc32; typedef const uint16_t uc16; typedef const uint8_t uc8; typedef __IO uint32_t vu32; typedef __IO uint16_t vu16; typedef __IO uint8_t vu8;typedef __I uint32_t vuc32; typedef __I uint16_t vuc16; typedef __I uint8_t vuc8; #define INVALID 0 #define VALID 1 #define RETURN_NORMAL INVALID #define RETURN_ABNORMAL -1 #define PI 3.14159265358979323846#define _BOOL(x) (x?VALID:INVALID) #define _SET_PIN(GPIOx,Pin) GPIOx-BSRR Pin //pin set 1 #define _RESET_PIN(GPIOx,Pin) GPIOx-BSRR ((uint32_t)Pin 16u) //pin set 0typedef struct {unsigned char byte1;unsigned char byte2;unsigned char byte3;unsigned char byte4; }Byte4_MemoryParameterStructDef;typedef struct {unsigned char byte1;unsigned char byte2; }Byte2_MemoryParameterStructDef;typedef union {short int Value;Byte2_MemoryParameterStructDef Memory; }Convert_ShortIntParameter_UnionDef;typedef union {unsigned short int Value;Byte2_MemoryParameterStructDef Memory; }Convert_UnsignedShortIntParameter_UnionDef;typedef union {unsigned long int Value;Byte4_MemoryParameterStructDef Memory; }Convert_UnsignedLongIntParameter_UnionDef;typedef union {float Value;Byte4_MemoryParameterStructDef Memory; }Convert_FloatParameter_UnionDef;extern void LinearFitCoefficient(double *pA,double *pB,double x[],double y[],unsigned short int dataSize); extern void FunctionError(char *str); extern int StringCompare(uint8_t* stringA, uint8_t* stringB, uint16_t Length); extern void EmptyDelay(uint32_t nCount);#endif spi_Driver.c /********************************************************************** *file:spi驱动文件 *author:残梦 *date:2023.2.16 *note: **********************************************************************/ #include spi_Driver.h#define SPI1_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define SPI1_CLK_GPIO_PORT GPIOB #define SPI1_CLK_GPIO_PIN GPIO_PIN_3 #define SPI1_CLK_GPIO_AF GPIO_AF5_SPI1#define SPI1_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define SPI1_MOSI_GPIO_PORT GPIOB #define SPI1_MOSI_GPIO_PIN GPIO_PIN_5 #define SPI1_MOSI_GPIO_AF GPIO_AF5_SPI1#define SPI1_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define SPI1_MISO_GPIO_PORT GPIOB #define SPI1_MISO_GPIO_PIN GPIO_PIN_4 #define SPI1_MISO_GPIO_AF GPIO_AF5_SPI1SPI_HandleTypeDef hspi1; /**************************************************** function:SPI1初始化 param:void return:void date:2023.2.16 note:时序说明全双工SPI 线束:SCK|MOSI|MISO CSSPI模式 CPOL CPHA 空闲时 SCK 时钟 采样时刻0 0 0 低电平 奇数边沿(W25Qxx支持)1 0 1 低电平 偶数边沿2 1 0 高电平 奇数边沿3 1 1 高电平 偶数边沿(W25Qxx支持)当前使用数据长度8高位在前速度配置为PCLK2/2分频 42MHz注意W25Qxx底层读写采用的直接操作寄存器,所以需要在MX_SPI1_Init()函数中的HAL_SPI_Init()后调用__HAL_SPI_ENABLE(hspi1);以此使能外设SPI使用HAL库自带的收发函数不需要此使能 ****************************************************/ void MX_SPI1_Init(void) {hspi1.Instance SPI1;hspi1.Init.Mode SPI_MODE_MASTER;hspi1.Init.Direction SPI_DIRECTION_2LINES;hspi1.Init.DataSize SPI_DATASIZE_8BIT;hspi1.Init.CLKPolarity SPI_POLARITY_HIGH;hspi1.Init.CLKPhase SPI_PHASE_2EDGE;hspi1.Init.NSS SPI_NSS_SOFT;hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_2;hspi1.Init.FirstBit SPI_FIRSTBIT_MSB;hspi1.Init.TIMode SPI_TIMODE_DISABLE;hspi1.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial 7;if(HAL_SPI_Init(hspi1) ! HAL_OK){Error_Handler();}__HAL_SPI_ENABLE(hspi1);//W25Qxx底层读写采用的直接操作寄存器,所以需要在MX_SPI1_Init()函数中的HAL_SPI_Init()后调用__HAL_SPI_ENABLE(hspi1),以此使能外设SPI使用HAL库自带的收发函数不需要此使能 }/**************************************************** function:SPI1 GPIO、NVIC、CLOCK初始化 param:void return:void date:2023.2.16 note: ****************************************************/ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) {GPIO_InitTypeDef GPIO_InitStruct {0};if(spiHandle-Instance SPI1){__HAL_RCC_SPI1_CLK_ENABLE();SPI1_CLK_GPIO_CLK_ENABLE();SPI1_MOSI_GPIO_CLK_ENABLE();SPI1_MISO_GPIO_CLK_ENABLE();SPI1_W25Qxx_CS_GPIO_CLK_ENABLE();GPIO_InitStruct.Pin SPI1_CLK_GPIO_PIN;GPIO_InitStruct.Mode GPIO_MODE_AF_PP;GPIO_InitStruct.Pull GPIO_PULLUP;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate SPI1_CLK_GPIO_AF;HAL_GPIO_Init(SPI1_CLK_GPIO_PORT,GPIO_InitStruct);GPIO_InitStruct.Pin SPI1_MOSI_GPIO_PIN;GPIO_InitStruct.Mode GPIO_MODE_AF_PP;GPIO_InitStruct.Pull GPIO_PULLUP;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate SPI1_MOSI_GPIO_AF;HAL_GPIO_Init(SPI1_MOSI_GPIO_PORT,GPIO_InitStruct);GPIO_InitStruct.Pin SPI1_MISO_GPIO_PIN;GPIO_InitStruct.Mode GPIO_MODE_AF_PP;GPIO_InitStruct.Pull GPIO_PULLUP;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate SPI1_MISO_GPIO_AF;HAL_GPIO_Init(SPI1_MISO_GPIO_PORT,GPIO_InitStruct);GPIO_InitStruct.Pin SPI1_W25Qxx_CS_GPIO_PIN;GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull GPIO_PULLUP;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate 0;HAL_GPIO_Init(SPI1_W25Qxx_CS_GPIO_PORT,GPIO_InitStruct);} } spi_Driver.h #ifndef _spi_Driver_H_ #define _spi_Driver_H_ #include main.h//外设SPI1相应挂载的外设片选引脚 #define SPI1_W25Qxx_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define SPI1_W25Qxx_CS_GPIO_PORT GPIOB #define SPI1_W25Qxx_CS_GPIO_PIN GPIO_PIN_14extern SPI_HandleTypeDef hspi1;extern void MX_SPI1_Init(void);#endif W25Qxx_Driver.c /********************************************************************** *file:W25Qxx驱动文件(SPI通信 SCK MOSI MISO CS) *author:残梦 *date:2023.2.17 *note:使用方法1、添加文件到工程Common_Driver.c、spi_Driver.c、W25Qxx_Driver.c2、spi_Driver.h文件修改外设SPI1相应挂载的外设片选引脚3、spi_Driver.c文件修改SPI1相应通信线(CLK、MOSI、MISO)的引脚宏4、W25Qxx_Driver.h文件修改W25Qxx通信时使用的SPI句柄和外设宏SPIx、SPIxHandle修改W25Qxx型号对应的宏sFLASH_ID5、W25Qxx_Driver.h文件开启调试宏(芯片是否正常,会进行擦除数据写入读出对比数据),调试完毕后屏蔽:_W25Qxx_Debug6、调用SPI初始化函数MX_SPI1_Init()(此时SPI进入空闲,CS引脚空闲)7、调用W25Qxx_InitCheck()函数检查芯片(执行完后芯片进入省电模式)8、完毕时序说明全双工SPI 线束:SCK|MOSI|MISO CSSPI模式 CPOL CPHA 空闲时 SCK 时钟 采样时刻0 0 0 低电平 奇数边沿(W25Qxx支持)1 0 1 低电平 偶数边沿2 1 0 高电平 奇数边沿3 1 1 高电平 偶数边沿(W25Qxx支持)当前使用数据长度8高位在前速度配置为PCLK2/2分频 42MHz注意W25Qxx底层读写采用的直接操作寄存器,所以需要在MX_SPI1_Init()函数中的HAL_SPI_Init()后调用__HAL_SPI_ENABLE(hspi1);以此使能外设SPI使用HAL库自带的收发函数不需要此使能此驱动文件只适合W25Qxx 16M及以下型号因为访问地址位数不同W25Qxx_Driver.c文件中的所有函数需要先初始化SPI后才可以调用 **********************************************************************/ #include W25Qxx_Driver.h #include spi_Driver.h#define W25Qxx_CS_LOW() _RESET_PIN(SPI1_W25Qxx_CS_GPIO_PORT,SPI1_W25Qxx_CS_GPIO_PIN) #define W25Qxx_CS_HIGH() _SET_PIN(SPI1_W25Qxx_CS_GPIO_PORT,SPI1_W25Qxx_CS_GPIO_PIN)static __IO uint32_t SPITimeout SPIT_LONG_TIMEOUT;static uint8_t W25Qxx_ReadByte(void); static uint8_t W25Qxx_SendByte(uint8_t byte); static uint16_t W25Qxx_SendHalfWord(uint16_t HalfWord); static void W25Qxx_WriteEnable(void); static void W25Qxx_WaitForWriteEnd(void); static uint16_t W25Qxx_SPI_TIMEOUT_UserCallback(uint8_t errorCode);/**************************************************** function:W25Q擦除FLASH扇区 param:SectorAddr要擦除的扇区地址 return:void date:2023.2.17 note: ****************************************************/ void W25Qxx_SectorErase(uint32_t SectorAddr) {/* 发送FLASH写使能命令 */W25Qxx_WriteEnable();W25Qxx_WaitForWriteEnd();/* 擦除扇区 *//* 选择FLASH: CS低电平 */W25Qxx_CS_LOW();/* 发送扇区擦除指令*/W25Qxx_SendByte(W25X_SectorErase);/*发送擦除扇区地址的高位*/W25Qxx_SendByte((SectorAddr 0xFF0000) 16);/* 发送擦除扇区地址的中位 */W25Qxx_SendByte((SectorAddr 0xFF00) 8);/* 发送擦除扇区地址的低位 */W25Qxx_SendByte(SectorAddr 0xFF);/* 停止信号 FLASH: CS 高电平 */W25Qxx_CS_HIGH();/* 等待擦除完毕*/W25Qxx_WaitForWriteEnd(); }/**************************************************** function:W25Q擦除FLASH扇区整片擦除 param:void return:void date:2023.2.17 note: ****************************************************/ void W25Qxx_BulkErase(void) {/* 发送FLASH写使能命令 */W25Qxx_WriteEnable();/* 整块 Erase *//* 选择FLASH: CS低电平 */W25Qxx_CS_LOW();/* 发送整块擦除指令*/W25Qxx_SendByte(W25X_ChipErase);/* 停止信号 FLASH: CS 高电平 */W25Qxx_CS_HIGH();/* 等待擦除完毕*/W25Qxx_WaitForWriteEnd(); }/**************************************************** function:对FLASH按页写入数据调用本函数写入数据前需要先擦除扇区 param: pBuffer要写入数据的指针WriteAddr写入地址NumByteToWrite写入数据长度必须小于等于W25Qxx_PerWritePageSize return:void date:2023.2.17 note: ****************************************************/ void W25Qxx_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {/* 发送FLASH写使能命令 */W25Qxx_WriteEnable();/* 选择FLASH: CS低电平 */W25Qxx_CS_LOW();/* 写页写指令*/W25Qxx_SendByte(W25X_PageProgram);/*发送写地址的高位*/W25Qxx_SendByte((WriteAddr 0xFF0000) 16);/*发送写地址的中位*/W25Qxx_SendByte((WriteAddr 0xFF00) 8);/*发送写地址的低位*/W25Qxx_SendByte(WriteAddr 0xFF);if(NumByteToWrite W25Qxx_PerWritePageSize){NumByteToWrite W25Qxx_PerWritePageSize;FLASH_ERROR(W25Qxx_PageWrite too large!);}/* 写入数据*/while (NumByteToWrite--){/* 发送当前要写入的字节数据 */W25Qxx_SendByte(*pBuffer);/* 指向下一字节数据 */pBuffer;}/* 停止信号 FLASH: CS 高电平 */W25Qxx_CS_HIGH();/* 等待写入完毕*/W25Qxx_WaitForWriteEnd(); }/**************************************************** function:对FLASH写入数据调用本函数写入数据前需要先擦除扇区 param: pBuffer要写入数据的指针WriteAddr写入地址NumByteToWrite写入数据长度 return:void date:2023.2.17 note: ****************************************************/ void W25Qxx_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {uint8_t NumOfPage 0, NumOfSingle 0, Addr 0, count 0, temp 0;/*mod运算求余若writeAddr是W25Qxx_PageSize整数倍运算结果Addr值为0*/Addr WriteAddr % W25Qxx_PageSize;/*差count个数据值刚好可以对齐到页地址*/count W25Qxx_PageSize - Addr; /*计算出要写多少整数页*/NumOfPage NumByteToWrite / W25Qxx_PageSize;/*mod运算求余计算出剩余不满一页的字节数*/NumOfSingle NumByteToWrite % W25Qxx_PageSize;/* Addr0,则WriteAddr 刚好按页对齐 aligned */if (Addr 0) {/* NumByteToWrite W25Qxx_PageSize */if (NumOfPage 0) {W25Qxx_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}else /* NumByteToWrite W25Qxx_PageSize */{/*先把整数页都写了*/while (NumOfPage--){W25Qxx_PageWrite(pBuffer, WriteAddr, W25Qxx_PageSize);WriteAddr W25Qxx_PageSize;pBuffer W25Qxx_PageSize;}/*若有多余的不满一页的数据把它写完*/W25Qxx_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}/* 若地址与 W25Qxx_PageSize 不对齐 */else {/* NumByteToWrite W25Qxx_PageSize */if (NumOfPage 0) {/*当前页剩余的count个位置比NumOfSingle小写不完*/if (NumOfSingle count) {temp NumOfSingle - count;/*先写满当前页*/W25Qxx_PageWrite(pBuffer, WriteAddr, count);WriteAddr count;pBuffer count;/*再写剩余的数据*/W25Qxx_PageWrite(pBuffer, WriteAddr, temp);}else /*当前页剩余的count个位置能写完NumOfSingle个数据*/{ W25Qxx_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}}else /* NumByteToWrite W25Qxx_PageSize */{/*地址不对齐多出的count分开处理不加入这个运算*/NumByteToWrite - count;NumOfPage NumByteToWrite / W25Qxx_PageSize;NumOfSingle NumByteToWrite % W25Qxx_PageSize;W25Qxx_PageWrite(pBuffer, WriteAddr, count);WriteAddr count;pBuffer count;/*把整数页都写了*/while (NumOfPage--){W25Qxx_PageWrite(pBuffer, WriteAddr, W25Qxx_PageSize);WriteAddr W25Qxx_PageSize;pBuffer W25Qxx_PageSize;}/*若有多余的不满一页的数据把它写完*/if (NumOfSingle ! 0){W25Qxx_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}} }/**************************************************** function:读取FLASH数据 param: pBuffer存储读出数据的指针ReadAddr读取地址NumByteToRead读取数据长度 return:void date:2023.2.17 note: ****************************************************/ void W25Qxx_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) {/* 选择FLASH: CS低电平 */W25Qxx_CS_LOW();/* 发送 读 指令 */W25Qxx_SendByte(W25X_ReadData);/* 发送 读 地址高位 */W25Qxx_SendByte((ReadAddr 0xFF0000) 16);/* 发送 读 地址中位 */W25Qxx_SendByte((ReadAddr 0xFF00) 8);/* 发送 读 地址低位 */W25Qxx_SendByte(ReadAddr 0xFF);/* 读取数据 */while (NumByteToRead--){/* 读取一个字节*/*pBuffer W25Qxx_SendByte(Dummy_Byte);/* 指向下一个字节缓冲区 */pBuffer;}/* 停止信号 FLASH: CS 高电平 */W25Qxx_CS_HIGH(); }/**************************************************** function:读取FLASH ID param:void return:FLASH ID date:2023.2.17 note: ****************************************************/ uint32_t W25Qxx_ReadID(void) {uint32_t Temp 0, Temp0 0, Temp1 0, Temp2 0;/* 开始通讯CS低电平 */W25Qxx_CS_LOW();/* 发送JEDEC指令读取ID */W25Qxx_SendByte(W25X_JedecDeviceID);/* 读取一个字节数据 */Temp0 W25Qxx_SendByte(Dummy_Byte);/* 读取一个字节数据 */Temp1 W25Qxx_SendByte(Dummy_Byte);/* 读取一个字节数据 */Temp2 W25Qxx_SendByte(Dummy_Byte);/* 停止通讯CS高电平 */W25Qxx_CS_HIGH();/*把数据组合起来作为函数的返回值*/Temp (Temp0 16) | (Temp1 8) | Temp2;return Temp; }/**************************************************** function:读取FLASH Device ID param:void return:FLASH Device ID date:2023.2.17 note: ****************************************************/ uint32_t W25Qxx_ReadDeviceID(void) {uint32_t Temp 0;/* Select the FLASH: Chip Select low */W25Qxx_CS_LOW();/* Send RDID instruction */W25Qxx_SendByte(W25X_DeviceID);W25Qxx_SendByte(Dummy_Byte);W25Qxx_SendByte(Dummy_Byte);W25Qxx_SendByte(Dummy_Byte);/* Read a byte from the FLASH */Temp W25Qxx_SendByte(Dummy_Byte);/* Deselect the FLASH: Chip Select high */W25Qxx_CS_HIGH();return Temp; }/**************************************************** function:W25Qxx_StartReadSequence param:ReadAddr : FLASHs internal address to read from. return:void date:2023.2.17 note:Initiates a read data byte (READ) sequence from the Flash. * This is done by driving the /CS line low to select the device, * then the READ instruction is transmitted followed by 3 bytes * address. This function exit and keep the /CS line low, so the * Flash still being selected. With this technique the whole * content of the Flash is read with a single READ instruction. ****************************************************/ void W25Qxx_StartReadSequence(uint32_t ReadAddr) {/* Select the FLASH: Chip Select low */W25Qxx_CS_LOW();/* Send Read from Memory instruction */W25Qxx_SendByte(W25X_ReadData);/* Send the 24-bit address of the address to read from -----------------------*//* Send ReadAddr high nibble address byte */W25Qxx_SendByte((ReadAddr 0xFF0000) 16);/* Send ReadAddr medium nibble address byte */W25Qxx_SendByte((ReadAddr 0xFF00) 8);/* Send ReadAddr low nibble address byte */W25Qxx_SendByte(ReadAddr 0xFF); }/**************************************************** function:使用SPI读取一个字节的数据 param:void return:返回接收到的数据 date:2023.2.17 note: ****************************************************/ static uint8_t W25Qxx_ReadByte(void) {return (W25Qxx_SendByte(Dummy_Byte)); }/**************************************************** function:使用SPI发送一个字节的数据 param:byte要发送的数据 return:返回接收到的数据 date:2023.2.17 note: ****************************************************/ static uint8_t W25Qxx_SendByte(uint8_t byte) {SPITimeout SPIT_FLAG_TIMEOUT;/* 等待发送缓冲区为空TXE事件 */while (__HAL_SPI_GET_FLAG( SPIxHandle, SPI_FLAG_TXE ) RESET){if((SPITimeout--) 0) return W25Qxx_SPI_TIMEOUT_UserCallback(0);}/* 写入数据寄存器把要写入的数据写入发送缓冲区 */WRITE_REG(SPIxHandle.Instance-DR, byte);SPITimeout SPIT_FLAG_TIMEOUT;/* 等待接收缓冲区非空RXNE事件 */while (__HAL_SPI_GET_FLAG( SPIxHandle, SPI_FLAG_RXNE ) RESET){if((SPITimeout--) 0) return W25Qxx_SPI_TIMEOUT_UserCallback(1);}/* 读取数据寄存器获取接收缓冲区数据 */return READ_REG(SPIxHandle.Instance-DR); }/**************************************************** function:W25Qxx_SendHalfWord param:Half Word : Half Word to send. return:The value of the received Half Word. date:2023.2.17 note:Sends a Half Word through the SPI interface and return theHalf Word received from the SPI bus. ****************************************************/ static uint16_t W25Qxx_SendHalfWord(uint16_t HalfWord) {SPITimeout SPIT_FLAG_TIMEOUT;/* Loop while DR register in not emplty */while (__HAL_SPI_GET_FLAG( SPIxHandle, SPI_FLAG_TXE ) RESET){if((SPITimeout--) 0) return W25Qxx_SPI_TIMEOUT_UserCallback(2);}/* Send Half Word through the SPIx peripheral */WRITE_REG(SPIxHandle.Instance-DR, HalfWord);SPITimeout SPIT_FLAG_TIMEOUT;/* Wait to receive a Half Word */while (__HAL_SPI_GET_FLAG( SPIxHandle, SPI_FLAG_RXNE ) RESET){if((SPITimeout--) 0) return W25Qxx_SPI_TIMEOUT_UserCallback(3);}/* Return the Half Word read from the SPI bus */return READ_REG(SPIxHandle.Instance-DR); }/**************************************************** function:向FLASH发送 写使能 命令 param:void return:void date:2023.2.17 note: ****************************************************/ static void W25Qxx_WriteEnable(void) {/* 通讯开始CS低 */W25Qxx_CS_LOW();/* 发送写使能命令*/W25Qxx_SendByte(W25X_WriteEnable);/*通讯结束CS高 */W25Qxx_CS_HIGH(); }/**************************************************** function:等待WIP(BUSY)标志被置0即等待到FLASH内部数据写入完毕 param:void return:void date:2023.2.17 note: ****************************************************/ static void W25Qxx_WaitForWriteEnd(void) {uint8_t FLASH_Status 0;/* 选择 FLASH: CS 低 */W25Qxx_CS_LOW();/* 发送 读状态寄存器 命令 */W25Qxx_SendByte(W25X_ReadStatusReg);SPITimeout SPIT_FLAG_TIMEOUT;/* 若FLASH忙碌则等待 */do{/* 读取FLASH芯片的状态寄存器 */FLASH_Status W25Qxx_SendByte(Dummy_Byte); {if((SPITimeout--) 0) {W25Qxx_SPI_TIMEOUT_UserCallback(4);return;}} }while ((FLASH_Status WIP_Flag) SET); /* 正在写入标志 *//* 停止信号 FLASH: CS 高 */W25Qxx_CS_HIGH(); }/**************************************************** function:进入掉电模式 param:void return:void date:2023.2.17 note: ****************************************************/ void W25Qxx_PowerDown(void) { /* 选择 FLASH: CS 低 */W25Qxx_CS_LOW();/* 发送 掉电 命令 */W25Qxx_SendByte(W25X_PowerDown);/* 停止信号 FLASH: CS 高 */W25Qxx_CS_HIGH(); }/**************************************************** function:唤醒 param:void return:void date:2023.2.17 note: ****************************************************/ void W25Qxx_WAKEUP(void) {/*选择 FLASH: CS 低 */W25Qxx_CS_LOW();/* 发上 上电 命令 */W25Qxx_SendByte(W25X_ReleasePowerDown);/* 停止信号 FLASH: CS 高 */W25Qxx_CS_HIGH(); //等待TRES1 } /**************************************************** function:等待超时回调函数 param:void return:void date:2023.2.17 note: ****************************************************/ static uint16_t W25Qxx_SPI_TIMEOUT_UserCallback(uint8_t errorCode) {/* 等待超时后的处理,输出错误信息 */FLASH_ERROR(SPI 等待超时!errorCode %d,errorCode);return 0; }/**************************************************** function:计数延时 param:nCount--待延时的大小 return:void date:2023.2.17 note: ****************************************************/ static void W25Qxx_EmptyDelay(uint32_t nCount) {while(nCount--); }/********************以下为测试代码*********************/ #ifdef _W25Qxx_Debug#define FLASH_WriteAddress 0x00000 #define FLASH_ReadAddress FLASH_WriteAddress #define FLASH_SectorToErase FLASH_WriteAddress/* 获取缓冲区的长度 */ #define TxBufferSize1 (countof(TxBuffer1) - 1) #define RxBufferSize1 (countof(TxBuffer1) - 1) #define countof(a) (sizeof(a) / sizeof(*(a))) #define BufferSize (countof(Tx_Buffer)-1)/**************************************************** function:比较两个缓冲区中的数据是否相等 param:stringA、stringB--待比较的字符串指针Length--字符串待比较的长度不得大于stringA或stringB的长度 return:-1--不相等0--相等 date:2023.2.17 note: ****************************************************/ static int W25Qxx_StringCompare(uint8_t* stringA, uint8_t* stringB, uint16_t Length) {while(Length--){if(*stringA ! *stringB){return -1;}stringA;stringB;}return 0; }#endif/**************************************************** function:W25Q初始化 param:void return:-1--异常0--正常 date:2023.2.17 note: ****************************************************/ int W25Qxx_InitCheck(void) { //读取的ID存储位置uint32_t DeviceID 0,FlashID 0;DeviceID W25Qxx_ReadDeviceID();//获取 Flash Device IDW25Qxx_EmptyDelay(200);FlashID W25Qxx_ReadID();//获取 SPI Flash IDprintf(W25Qxx FlashID:0x%0X, Manufacturer Device ID:0x%0X\r\n, FlashID, DeviceID);if (FlashID sFLASH_ID)//检验SPI Flash ID{printf(检测到SPI FLASH W25Q128 !\r\n);#ifdef _W25Qxx_Debug/* 发送缓冲区初始化 */uint8_t Tx_Buffer[] 感谢您选用野火stm32开发板\r\nhttp://firestm32.taobao.com;uint8_t Rx_Buffer[BufferSize];W25Qxx_SectorErase(FLASH_SectorToErase);//擦除将要写入的 SPI FLASH 扇区FLASH写入前要先擦除W25Qxx_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);//将发送缓冲区的数据写到flash中printf(写入的数据为:\r\n%s, Tx_Buffer);W25Qxx_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);//将刚刚写入的数据读出来放到接收缓冲区中printf(读出的数据为:\r\n%s, Rx_Buffer);if(W25Qxx_StringCompare(Tx_Buffer, Rx_Buffer, BufferSize) 0)//检查写入的数据与读出的数据是否相等{printf(16M串行flash(W25Q128)测试失败!\n\r);return -1;}else{printf(16M串行flash(W25Q128)测试成功!\n\r);}#endif}else{printf(获取不到 W25Q128 ID!\n\r);return -1;}W25Qxx_PowerDown();//进入省电模式return 0; } W25Qxx_Driver.h #ifndef _W25Qxx_Driver_H_ #define _W25Qxx_Driver_H_ #include Common_Driver.h #define _W25Qxx_Debug //未定义--平时无需此代码,定义--芯片是否正常,会进行擦除数据写入读出对比数据#define SPIx SPI1 //使用的SPIx相应外设 #define SPIxHandle hspi1 //使用的spi相应句柄 //#define SPIx_FORCE_RESET() __HAL_RCC_SPI1_FORCE_RESET() //#define SPIx_RELEASE_RESET() __HAL_RCC_SPI1_RELEASE_RESET()/* Private typedef ------选择实际使用的型号-------------------------------------*/ //#define sFLASH_ID 0xEF3015 //W25X16 //#define sFLASH_ID 0xEF4015 //W25Q16 //#define sFLASH_ID 0XEF4017 //W25Q64 #define sFLASH_ID 0XEF4018 //W25Q128//#define W25Qxx_PageSize 4096 #define W25Qxx_PageSize 256 #define W25Qxx_PerWritePageSize 256/* Private define ------------------------------------------------------------*/ /*命令定义-开头*******************************/ #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F #define WIP_Flag 0x01 /* Write In Progress (WIP) flag */ #define Dummy_Byte 0xFF /*命令定义-结尾*******************************//*等待超时时间*/ #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)//使用HAL库SPI收发函数时超时时间需加大 #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))/*信息输出*/ #define FLASH_DEBUG_ON 1#define FLASH_INFO(fmt,arg...) printf(-FLASH-INFO- fmt\n,##arg) #define FLASH_ERROR(fmt,arg...) printf(-FLASH-ERROR- fmt\n,##arg) #define FLASH_DEBUG(fmt,arg...) do{\if(FLASH_DEBUG_ON)\printf(-FLASH-DEBUG- [%d]fmt\n,__LINE__, ##arg);\}while(0)extern void W25Qxx_Init(void); extern void W25Qxx_SectorErase(uint32_t SectorAddr); extern void W25Qxx_BulkErase(void); extern void W25Qxx_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); extern void W25Qxx_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); extern void W25Qxx_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead); extern uint32_t W25Qxx_ReadID(void); extern uint32_t W25Qxx_ReadDeviceID(void); extern void W25Qxx_StartReadSequence(uint32_t ReadAddr); extern void W25Qxx_PowerDown(void); extern void W25Qxx_WAKEUP(void); extern int W25Qxx_InitCheck(void);#endif 2、驱动代码笔记说明 1、HAL库和直接使用野火W25Qxx代码时进行SPI读写区别 __HAL_SPI_ENABLE(hspi1);这句是什么作用呢 /** brief Enable the SPI peripheral.* param __HANDLE__ specifies the SPI Handle.* This parameter can be SPI where x: 1, 2, or 3 to select the SPI peripheral.* retval None*/ #define __HAL_SPI_ENABLE(__HANDLE__) SET_BIT((__HANDLE__)-Instance-CR1, SPI_CR1_SPE)由此明白了SPE 注意CubeMx配置生成的代码MX_SPI1_Init()函数并没有对SPI外设使能只有在调用读写函数时才进行使能后面会说到 W25Qxx底层读写采用的直接操作寄存器,所以需要在MX_SPI1_Init()函数中的HAL_SPI_Init()后调用__HAL_SPI_ENABLE(hspi1),以此使能外设SPI使用HAL库自带的收发函数不需要此使能语句 比如说这个使用SPI发送一个字节的数据函数 /**************************************************** function:使用SPI发送一个字节的数据 param:byte要发送的数据 return:返回接收到的数据 date:2023.2.17 note: ****************************************************/ static uint8_t W25Qxx_SendByte(uint8_t byte) {SPITimeout SPIT_FLAG_TIMEOUT;/* 等待发送缓冲区为空TXE事件 */while (__HAL_SPI_GET_FLAG( SPIxHandle, SPI_FLAG_TXE ) RESET){if((SPITimeout--) 0) return W25Qxx_SPI_TIMEOUT_UserCallback(0);}/* 写入数据寄存器把要写入的数据写入发送缓冲区 */WRITE_REG(SPIxHandle.Instance-DR, byte);SPITimeout SPIT_FLAG_TIMEOUT;/* 等待接收缓冲区非空RXNE事件 */while (__HAL_SPI_GET_FLAG( SPIxHandle, SPI_FLAG_RXNE ) RESET){if((SPITimeout--) 0) return W25Qxx_SPI_TIMEOUT_UserCallback(1);}/* 读取数据寄存器获取接收缓冲区数据 */return READ_REG(SPIxHandle.Instance-DR); }由此可以看出里面是寄存器直接读写但是读写前SPI外设没有进行使能 再来看看HAL自带的读写函数HAL_SPI_TransmitReceive() HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,uint32_t Timeout) {/* Set the transaction information */hspi-ErrorCode HAL_SPI_ERROR_NONE;hspi-pRxBuffPtr (uint8_t *)pRxData;hspi-RxXferCount Size;hspi-RxXferSize Size;hspi-pTxBuffPtr (uint8_t *)pTxData;hspi-TxXferCount Size;hspi-TxXferSize Size;/*Init field not used in handle to zero */hspi-RxISR NULL;hspi-TxISR NULL;/* Check if the SPI is already enabled */if ((hspi-Instance-CR1 SPI_CR1_SPE) ! SPI_CR1_SPE){/* Enable SPI peripheral */__HAL_SPI_ENABLE(hspi);}}此处可以可以看出该函数内部会自动使能CR1的SPE位注意这个函数使能此SPI外设后不会进行关闭如果不使用__HAL_SPI_ENABLE(hspi1)也可以直接随意调用HAL库的SPI收发轮询函数进行读写开启外设
http://www.dnsts.com.cn/news/193647.html

相关文章:

  • 做网站设计制作的抖音小程序源码
  • 怎么上传视频到公司网站新民网站建设价格咨询
  • 建设网站的工作步骤个人网站可以做营销吗
  • 有哪些网站建设方案网址你懂我意思正能量
  • 上海网站建设管理做一个网站需要多少费用
  • 李笑来做的一个网站深圳市做网站的公司
  • 网站qq未启用广告公司网站策划
  • 网站域名一年多少钱厦门最早做网站的公司
  • 网站设计做什么网站开发设计概述
  • 九江网站设计公司wordpress如何在地址栏中加网站logo
  • 网上快速学做网站物流网络规划
  • 广州营销型网站建设培训班贵州域网网站建设
  • 漯河住房建设局网站seo人才招聘
  • 给个网站做填空题删除wordpress媒体库多余
  • 专业手机网站公司吗ppt模板简约 淡雅 大气
  • 厦门做公司网站电子网站建设实验报告
  • 安贞网站建设深圳做网站de公司
  • 三亚最新通告文昌最新通告seo做什么行业比较好
  • 公司做网站用什么主机争对银行排队做一网站
  • 做网站代理属于开设赌场罪吗网站的模版
  • 中升乙源建设工程有限公司网站关于网站开发的个人小结
  • 百度生成在线网站地图网站屏蔽右键破解
  • 网站开发是做啥的打广告专用配图
  • 江西省做网站创意网站页面设计
  • 个性化网站建设公司WordPress最快主题
  • 专业从事成都网站建设做外贸的免费网站有哪些
  • 网站公司怎么做的好某网站优化方案
  • 河北区网站建设西安互联网推广公司
  • 网站建设实现功能wordpress 2015主题公园
  • 做论坛网站需要多大空间视频解析网站制作