基于HAL库实现看门狗喂狗实时时钟睡眠停止模式ADC采集w25qx写入读取
1.基于HAL库实现看门狗喂狗
在芯片内部有两个看门狗系统一个是独立看门狗一个是窗口看门狗,看门狗的作用就是监视程序的执行若程序执行出现错误没有及时喂狗,就会触发中断给系统复位。窗口看门狗相比于独立看门狗来说会有一个窗口期,只有在该时期喂狗才会有效,其他时期喂狗或者不喂狗都会造成系统复位,所以窗口看门狗的监视能力更强。下面我们来看CubeMX配置和程序(带有详细注释):

void IWDG_Test(void) //独立看门狗测试函数
{OLED_ShowStr(16,0,(unsigned char*)"IWDG Test",2);if(key_Value == KEY_ESC){key_Value = 0; //进入之后给按键键值清0HAL_IWDG_Refresh(&hiwdg); //独立看门狗喂狗函数,2秒复位BEEP_Control(ON); //通过BEEP来显示是否成功执行HAL_Delay(20);BEEP_Control(OFF);}HAL_Delay(500); //延时让按键检测不要太快
}
这是独立看门狗的喂狗程序,程序为了验证看门狗的喂狗功能,通过CubeMX配置设置系统2s内不为狗则发生复位,通过按键控制是否喂狗。主要函数为HAL_IWDG_Refresh(&hiwdg);HAL库提供的独立看门狗喂狗函数。
下面来看窗口看门狗的配置与程序:

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)//通过配置50ms执行一次中断回调函数
{static uint32_t wwdg_count=0; //计数值wwdg_count++;if(key_Value == KEY_ESC){key_Value = 0; //清空键值wwdg_count = 0; //计数清0}if(wwdg_count <= 40) //2s{HAL_WWDG_Refresh(hwwdg);//喂狗} //若在2s钟之内有按键按下则会进行喂狗,喂狗由系统函数进行else if(wwdg_count > 40) //超过2s不进行喂狗,系统复位{}
}
通过CubeMX配置窗口看门狗的串口值和递减值,在窗口看门狗中系统提供了在要复位前进入中断,并调用回调函数的机制所以我们要在回调函数中处理,同样用按键来控制是狗喂狗,若在回调函数被调用时有按键按下则启用喂狗,没有则不喂狗系统复位。HAL_WWDG_Refresh(hwwdg);是HAL库提供的窗口看门狗喂狗函数。
2.基于HAL库实现实时时钟
芯片内置了RTC模块可以用来进行实时时钟的实现,下面看配置和程序来实现实时时钟:

void MX_RTC_Init(void)
{/* USER CODE BEGIN RTC_Init 0 *//* USER CODE END RTC_Init 0 */RTC_TimeTypeDef sTime = {0};RTC_DateTypeDef DateToUpdate = {0};/* USER CODE BEGIN RTC_Init 1 *//* USER CODE END RTC_Init 1 *//** Initialize RTC Only*/hrtc.Instance = RTC;hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;if (HAL_RTC_Init(&hrtc) != HAL_OK){Error_Handler();}/* USER CODE BEGIN Check_RTC_BKUP */if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1) != 0x5051)//判断标志位,若没有该标志位初始化时间,若有该标志为时间不进行初始化{/* USER CODE END Check_RTC_BKUP *//** Initialize RTC and set the Time and Date*/sTime.Hours = 0x19;sTime.Minutes = 0x0;sTime.Seconds = 0x0;if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK){Error_Handler();}DateToUpdate.WeekDay = RTC_WEEKDAY_THURSDAY;DateToUpdate.Month = RTC_MONTH_NOVEMBER;DateToUpdate.Date = 0x6;DateToUpdate.Year = 0x25;if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK){Error_Handler();}/* USER CODE BEGIN RTC_Init 2 */struct tm rtc_tm; //定义时间结构体变量,在下面对其赋值rtc_tm.tm_year = 2024-1900;rtc_tm.tm_mon = 8-1;rtc_tm.tm_mday = 8;rtc_tm.tm_hour = 2;rtc_tm.tm_min = 48;rtc_tm.tm_sec = 10;RTC_WriteTimeCounter(&hrtc,mktime(&rtc_tm)); //mktime函数,将该时间结构变量转化成时间戳,并通过函数写入时间计数器HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,0x5051); // 设置标志位, 表示时间已经被设置
}/* USER CODE END RTC_Init 2 */}void RTC_Test(void)
{struct tm *tp; //定义结构体指针,用来在后续使用函数将秒数转化成对应结构体中的相应日期uint8_t str[64]; //定义一个64字节空间的一个数组,用来存放格式化的日期OLED_ShowStr(16,0, (unsigned char*)"RTC Test", 2); time_t t = RTC_ReadTimeCounter(&hrtc); // t 就是秒数,通过函数将rtc结构体中的时间计数器读取出来tp = localtime(&t) ; // 把秒数转换成时间结构体printf("%u::%d-%d-%d %d:%d:%d\n",t,tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec); //printf重定向,将数据通过串口输出显示出来sprintf((char *)str,"Date:%04d-%02d-%02d",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday); //将一些值以格式化的形式转化成字符串,并保存到str数组中OLED_ShowStr(0,3, (unsigned char*)str, 2); //将str数组中的值显示到oled屏幕上sprintf((char *)str,"Time:%02d:%02d:%02d",tp->tm_hour,tp->tm_min,tp->tm_sec);OLED_ShowStr(0,5, (unsigned char*)str, 2);HAL_Delay(1000);
}
针对于F103c8t6实时时钟HAL库实现实时时钟存在的一些不足,程序中首先使用了首先将日期和时间转化成时间戳然后将其放入到系统的时间计数器中,然后通过BKP保存时钟已被修改的标志位,然后判断标志位,将计数器中的时间戳转化为日期和时间的方式实现了实时时钟。
3.基于HAL库实现睡眠停止模式
芯片的睡眠停止模式都是芯片的低功耗运行模式,下面来看程序实现:
LED_Control(LED1,ON);HAL_Delay(2000);LED_Control(LED1,OFF);LED_Control(LED2,ON);HAL_SuspendTick();//暂停系统滴答定时器,因为该定时器也会产生中断printf("System is sleep\n");HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI); //通过HAL库函数的使用,使系统通过中断方式进入睡眠模式printf("System is wakup\n");LED_Control(LED2,OFF);HAL_ResumeTick();//开启系统滴答定时器
该段程序实现了在LED1灯亮灭后,系统进入睡眠模式,然后通过外部中断按键按下来唤醒系统,HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);是主要函数是HAL库提供的让系统进入睡眠模式的函数通过WFI方式进入睡眠。
printf("System is running\n");LED_Control(LED1,ON);HAL_Delay(2000);LED_Control(LED1,OFF);LED_Control(LED2,ON);HAL_SuspendTick();//暂停系统滴答定时器,因为该定时器也会产生中断printf("System is sleep\n");//HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI); //通过HAL库函数的使用,使系统通过中断方式进入睡眠模式,要通过中断唤醒系统HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI); //通过HAL库函数,使系统通过中断进入停止模式,要通过中断唤醒系统SystemClock_Config(); //系统进入停止模式,通过中断唤醒后系统时钟会变成HSI(8MHZ),我们要重新使用时钟配置函数,配置时钟为72MHZHAL_ResumeTick();//开启系统滴答定时器printf("System is wakup\n");LED_Control(LED2,OFF);//通过函数获取到系统的内部时钟,显示内部时钟配置正确uint32_t SYSCLK_Frequency = HAL_RCC_GetSysClockFreq(); //该函数功能获取系统时钟uint32_t HCLK_Frequency = HAL_RCC_GetHCLKFreq(); //获取HCLK线上的时钟uint32_t PCLK1_Frequency = HAL_RCC_GetPCLK1Freq(); //获取PCLK1线上的时钟uint32_t PCLK2_Frequency = HAL_RCC_GetPCLK2Freq(); //获取PCLK2线上的时钟uint32_t SYSCLK_Source = __HAL_RCC_GET_SYSCLK_SOURCE();//获取时钟源printf("2: SYSCLK:%d,\n HCLK:%d,\n PCLK1:%d,\n PCLK2:%d,\n Source:%d (0 HSI , 8 PLLCLK)\n",SYSCLK_Frequency,HCLK_Frequency,PCLK1_Frequency,PCLK2_Frequency,SYSCLK_Source);
该段程序实现了在灯亮灭后进入停止模式,然后通过外部中断按键按下唤醒。
4.基于HAL库实现ADC采集和转化
配置和程序如下,程序中配备详细解析:

void ADC_VR_CPU_Test(void)
{uint8_t str[32] = {0}; //用来存储使用sprintf函数后转化得到的字符串OLED_ShowStr(16,0,(unsigned char*)"ADC VR CPU Test",2);//OLED显示uint32_t adc_value = 0; //用来接收adc,转化到的数字量ADC_ChannelConfTypeDef sConfig = {0};sConfig.Channel = ADC_CHANNEL_1;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}for(uint8_t i=0;i<10;i++){HAL_ADC_Start(&hadc1);//开启ADC转化if(HAL_ADC_PollForConversion(&hadc1,100) == HAL_OK)//等待ADC转化完成{adc_value += HAL_ADC_GetValue(&hadc1); //获取adc的数字量,并累加}}adc_value = adc_value/10;float val = adc_value*3.3/4095; //将得到的数字量转化成模拟量printf("VR : %.2fv",val);//通过串口显示val值sprintf((char *)str,"VR : %.2fv",val);//将值进行格式化转化成字符串OLED_ShowStr(0,3,(unsigned char*)str,2);adc_value = 0;sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}for(uint8_t i=0;i<10;i++){HAL_ADC_Start(&hadc1);if(HAL_ADC_PollForConversion(&hadc1,1000) == HAL_OK){adc_value += HAL_ADC_GetValue(&hadc1);}}adc_value = adc_value/10;val = (1.43 - adc_value*3.3/4095)/0.0043+25;printf("CPU : %.1fC",val);sprintf((char*)str,"CPU : %.1fC",val);OLED_ShowStr(0,5,(unsigned char*)str,2);HAL_Delay(1000);
}
通过芯片内部的ADC通道将外接的电位器两端的电压进行显示和对芯片内部的温度进行采集显示。
5.基于HAL库实现w25qx的写入和读取
w25qx系列芯片是一款掉电不丢失的flash,可以用来存储字库数据图片等,下面我们就来给出对该芯片读取和写入的程序如下:
#ifndef __W25Qxx_H
#define __W25Qxx_H/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx.h"
#include "spi.h"#define W25Q128FV_FLASH_SIZE 0x1000000 /* 128 MBits => 16MBytes */
#define W25Q128FV_SECTOR_SIZE 0x10000 /* 256 sectors of 64KBytes */
#define W25Q128FV_SUBSECTOR_SIZE 0x1000 /* 4096 subsectors of 4kBytes */
#define W25Q128FV_PAGE_SIZE 0x100 /* 65536 pages of 256 bytes */#define W25Q128FV_DUMMY_CYCLES_READ 4
#define W25Q128FV_DUMMY_CYCLES_READ_QUAD 10#define W25Q128FV_BULK_ERASE_MAX_TIME 250000
#define W25Q128FV_SECTOR_ERASE_MAX_TIME 3000
#define W25Q128FV_SUBSECTOR_ERASE_MAX_TIME 800
#define W25Qx_TIMEOUT_VALUE 1000/* Reset Operations */
#define RESET_ENABLE_CMD 0x66
#define RESET_MEMORY_CMD 0x99#define ENTER_QPI_MODE_CMD 0x38
#define EXIT_QPI_MODE_CMD 0xFF/* Identification Operations */
#define READ_ID_CMD 0x90
#define DUAL_READ_ID_CMD 0x92
#define QUAD_READ_ID_CMD 0x94
#define READ_JEDEC_ID_CMD 0x9F/* Read Operations */
#define READ_CMD 0x03
#define FAST_READ_CMD 0x0B
#define DUAL_OUT_FAST_READ_CMD 0x3B
#define DUAL_INOUT_FAST_READ_CMD 0xBB
#define QUAD_OUT_FAST_READ_CMD 0x6B
#define QUAD_INOUT_FAST_READ_CMD 0xEB/* Write Operations */
#define WRITE_ENABLE_CMD 0x06
#define WRITE_DISABLE_CMD 0x04/* Register Operations */
#define READ_STATUS_REG1_CMD 0x05
#define READ_STATUS_REG2_CMD 0x35
#define READ_STATUS_REG3_CMD 0x15#define WRITE_STATUS_REG1_CMD 0x01
#define WRITE_STATUS_REG2_CMD 0x31
#define WRITE_STATUS_REG3_CMD 0x11/* Program Operations */
#define PAGE_PROG_CMD 0x02
#define QUAD_INPUT_PAGE_PROG_CMD 0x32/* Erase Operations */
#define SECTOR_ERASE_CMD 0x20
#define CHIP_ERASE_CMD 0xC7#define PROG_ERASE_RESUME_CMD 0x7A
#define PROG_ERASE_SUSPEND_CMD 0x75/* Flag Status Register */
#define W25Q128FV_FSR_BUSY ((uint8_t)0x01) /*!< busy */
#define W25Q128FV_FSR_WREN ((uint8_t)0x02) /*!< write enable */
#define W25Q128FV_FSR_QE ((uint8_t)0x02) /*!< quad enable */#define W25Qx_Enable() HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET)
#define W25Qx_Disable() HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET)#define W25Qx_OK ((uint8_t)0x00)
#define W25Qx_ERROR ((uint8_t)0x01)
#define W25Qx_BUSY ((uint8_t)0x02)
#define W25Qx_TIMEOUT ((uint8_t)0x03)uint8_t W25Qx_Init(void);
static void W25Qx_Reset(void);
static uint8_t W25Qx_GetStatus(void);
uint8_t W25Qx_WriteEnable(void);
void W25Qx_Read_ID(uint8_t *ID);
uint8_t W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size);
uint8_t W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size);
uint8_t W25Qx_Erase_Block(uint32_t Address);
uint8_t W25Qx_Erase_Chip(void);
void W25Qx_Test(void);#endif #include <string.h>
#include <stdio.h>
#include "w25qx.h"
#include "oled.h"/*********************************************************************************** 函数功能: 模块初始化*/
uint8_t W25Qx_Init(void)
{ W25Qx_Reset(); return W25Qx_GetStatus();
}static void W25Qx_Reset(void)
{uint8_t cmd[2] = {RESET_ENABLE_CMD,RESET_MEMORY_CMD};W25Qx_Enable();/* Send the reset command */HAL_SPI_Transmit(&hspi1, cmd, 2, W25Qx_TIMEOUT_VALUE); W25Qx_Disable();}/*********************************************************************************** 函数功能: 获取设备状态*/
static uint8_t W25Qx_GetStatus(void)
{uint8_t cmd[] = {READ_STATUS_REG1_CMD};uint8_t status;W25Qx_Enable();/* Send the read status command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE); /* Reception of the data */HAL_SPI_Receive(&hspi1,&status, 1, W25Qx_TIMEOUT_VALUE);W25Qx_Disable();/* Check the value of the register */if((status & W25Q128FV_FSR_BUSY) != 0){return W25Qx_BUSY;}else{return W25Qx_OK;}
}/*********************************************************************************** 函数功能: 写使能*/
uint8_t W25Qx_WriteEnable(void)
{uint8_t cmd[] = {WRITE_ENABLE_CMD};uint32_t tickstart = HAL_GetTick();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE); /*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(W25Qx_GetStatus() == W25Qx_BUSY){/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE){ return W25Qx_TIMEOUT;}}return W25Qx_OK;
}/*********************************************************************************** 函数功能: 获取设备ID*/
void W25Qx_Read_ID(uint8_t *ID)
{uint8_t cmd[4] = {READ_ID_CMD,0x00,0x00,0x00};W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE); /* Reception of the data */HAL_SPI_Receive(&hspi1,ID, 2, W25Qx_TIMEOUT_VALUE);W25Qx_Disable();}/*********************************************************************************** 函数功能: 读数据* 输入参数: 缓存数组指针、读地址、字节数*/
uint8_t W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{uint8_t cmd[4];/* Configure the command */cmd[0] = READ_CMD;cmd[1] = (uint8_t)(ReadAddr >> 16);cmd[2] = (uint8_t)(ReadAddr >> 8);cmd[3] = (uint8_t)(ReadAddr);W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE); /* Reception of the data */if (HAL_SPI_Receive(&hspi1, pData,Size,W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}W25Qx_Disable();return W25Qx_OK;
}/*********************************************************************************** 函数功能: 写数据* 输入参数: 缓存数组指针、写地址、字节数*/
uint8_t W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{uint8_t cmd[4];uint32_t end_addr, current_size, current_addr;uint32_t tickstart = HAL_GetTick();/* Calculation of the size between the write address and the end of the page */current_addr = 0;while (current_addr <= WriteAddr){current_addr += W25Q128FV_PAGE_SIZE;}current_size = current_addr - WriteAddr;/* Check if the size of the data is less than the remaining place in the page */if (current_size > Size){current_size = Size;}/* Initialize the adress variables */current_addr = WriteAddr;end_addr = WriteAddr + Size;/* Perform the write page by page */do{/* Configure the command */cmd[0] = PAGE_PROG_CMD;cmd[1] = (uint8_t)(current_addr >> 16);cmd[2] = (uint8_t)(current_addr >> 8);cmd[3] = (uint8_t)(current_addr);/* Enable write operations */W25Qx_WriteEnable();W25Qx_Enable();/* Send the command */if (HAL_SPI_Transmit(&hspi1,cmd, 4, W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}/* Transmission of the data */if (HAL_SPI_Transmit(&hspi1, pData,current_size, W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}W25Qx_Disable();/* Wait the end of Flash writing */while(W25Qx_GetStatus() == W25Qx_BUSY){/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE){ return W25Qx_TIMEOUT;}}/* Update the address and size variables for next page programming */current_addr += current_size;pData += current_size;current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128FV_PAGE_SIZE;} while (current_addr < end_addr);return W25Qx_OK;
}/*********************************************************************************** 函数功能: 扇区擦除* 输入参数: 地址*/
uint8_t W25Qx_Erase_Block(uint32_t Address)
{uint8_t cmd[4];uint32_t tickstart = HAL_GetTick();cmd[0] = SECTOR_ERASE_CMD;cmd[1] = (uint8_t)(Address >> 16);cmd[2] = (uint8_t)(Address >> 8);cmd[3] = (uint8_t)(Address);/* Enable write operations */W25Qx_WriteEnable();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE); /*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(W25Qx_GetStatus() == W25Qx_BUSY){/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Q128FV_SECTOR_ERASE_MAX_TIME){ return W25Qx_TIMEOUT;}}return W25Qx_OK;
}/*********************************************************************************** 函数功能: 芯片擦除*/
uint8_t W25Qx_Erase_Chip(void)
{uint8_t cmd[4];uint32_t tickstart = HAL_GetTick();cmd[0] = CHIP_ERASE_CMD;/* Enable write operations */W25Qx_WriteEnable();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE); /*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(W25Qx_GetStatus() != W25Qx_BUSY){/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Q128FV_BULK_ERASE_MAX_TIME){ return W25Qx_TIMEOUT;}}return W25Qx_OK;
}
void W25Qx_Test(void)
{uint8_t wData[0x100]; //写缓存数组uint8_t rData[0x100]; //读缓存数组uint8_t ID[4]; //设备ID缓存数组/*-Step1- 验证设备ID ************************************************Step1*/ W25Qx_Read_ID(ID);//第一位厂商ID固定0xEF,第二位设备ID根据容量不同,具体为://W25Q16为0x14、32为0x15、40为0x12、64为0x16、80为0x13、128为0x17if((ID[0] != 0xEF) | (ID[1] != 0x15)) { printf("something wrong in Step1 \n");}else{printf("W25Qxx ID is : ");for(uint32_t i=0;i<2;i++){printf("0x%02X ",ID[i]);}printf("\n");}
#if 1/*-Step2- 擦除块 ************************************************Step2*/ if(W25Qx_Erase_Block(0) == W25Qx_OK)printf("QSPI Erase Block OK!\n");elseprintf("something wrong in Step2\n");/*-Step3- 写数据 ************************************************Step3*/ for(uint32_t i =0;i<256;i ++){wData[i] = i;rData[i] = 0;}if(W25Qx_Write(wData,0,256)== W25Qx_OK)printf("QSPI Write OK!\n");elseprintf("something wrong in Step3\n");/*-Step4- 读数据 ************************************************Step4*/ if(W25Qx_Read(rData,0x00,0x100)== W25Qx_OK)printf("QSPI Read ok\n");elseprintf("something wrong in Step4\n");printf("QSPI Read Data : \n");for(uint32_t i =0;i<256;i++){printf("0x%02X ",rData[i]); } printf("\n");/*-Step5- 数据对比 ************************************************Step5*/ if(memcmp(wData,rData,0x100) == 0 ) {printf("W25Q32FV QuadSPI Test OK\n");OLED_ShowStr(0,3,(unsigned char *)"W25Q32 Test OK",2); }else{printf("W25Q32FV QuadSPI Test False\n");OLED_ShowStr(0,3,(unsigned char *)"W25Q32 Test Fail",2); }#endif
}
具体的实现原理可以参照我的标准库中对于w25q64的原理讲解,这里只是有HAL库进行了重新编写和封装。
