STM32F103RCT6+STM32CubeMX+keil5+NorFlash储存模块W25Q16/32+EEPROM存储模块AT24C02
·
https://item.taobao.com/item.htm?id=643663364434&mi_id=0000kQ3l-yHFJ4NI2oQRgc6KtbMi9MOZAtVKERJZEHa5i3g&spm=a21xtw.29978518.0.0&xxc=shop&skuId=4639727285420

1、
2、
3、w25q32.h
#ifndef __W25Q32_H
#define __W25Q32_H
#include "spi.h"
#include "gpio.h"
#include <stdint.h>
// W25Q32命令
#define W25QXX_WRITE_ENABLE 0x06
#define W25QXX_WRITE_DISABLE 0x04
#define W25QXX_READ_STATUS1 0x05
#define W25QXX_WRITE_STATUS1 0x01
#define W25QXX_READ_DATA 0x03
#define W25QXX_FAST_READ 0x0B
#define W25QXX_PAGE_PROGRAM 0x02
#define W25QXX_SECTOR_ERASE 0x20
#define W25QXX_BLOCK_ERASE 0xD8
#define W25QXX_CHIP_ERASE 0xC7
#define W25QXX_POWER_DOWN 0xB9
#define W25QXX_RELEASE_POWER_DOWN 0xAB
#define W25QXX_DEVICE_ID 0x90
#define W25QXX_MANUF_DEVICE_ID 0x90
#define W25QXX_JEDEC_DEVICE_ID 0x9F
// 片选引脚 (PA4)
#define W25QXX_CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define W25QXX_CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
// 函数声明
uint8_t W25Q32_Init(void);
uint16_t W25Q32_ReadID(void);
uint8_t W25Q32_ReadStatus(void);
void W25Q32_WriteEnable(void);
void W25Q32_WaitBusy(void);
void W25Q32_WriteByte(uint32_t addr, uint8_t data);
void W25Q32_ReadBytes(uint32_t addr, uint8_t *data, uint16_t len);
void W25Q32_WriteBytes(uint32_t addr, uint8_t *data, uint16_t len);
void W25Q32_EraseSector(uint32_t addr);
#endif
w25q32.c
#include "w25q32.h"
#include "spi.h"
#include "gpio.h"
// SPI收发一个字节
static uint8_t W25Q32_SPI_ReadWriteByte(uint8_t txData)
{
uint8_t rxData;
HAL_SPI_TransmitReceive(&hspi1, &txData, &rxData, 1, 100);
return rxData;
}
// 初始化
uint8_t W25Q32_Init(void)
{
W25QXX_CS_HIGH();
uint16_t id = W25Q32_ReadID();
// 支持多个制造商:0xEF=Winbond, 0x20=Micron, 0xC2=Macronix, 0x1F=Adesto
if((id >> 8) == 0xEF || (id >> 8) == 0x20 || (id >> 8) == 0xC2 || (id >> 8) == 0x1F)
return 1;
else
return 0;
}
// 读取芯片ID
uint16_t W25Q32_ReadID(void)
{
uint16_t temp = 0;
uint8_t manufacturer_id, device_id;
W25QXX_CS_LOW();
HAL_Delay(1);
W25Q32_SPI_ReadWriteByte(0x9F);
manufacturer_id = W25Q32_SPI_ReadWriteByte(0xFF);
device_id = W25Q32_SPI_ReadWriteByte(0xFF);
W25Q32_SPI_ReadWriteByte(0xFF);
W25QXX_CS_HIGH();
temp = (manufacturer_id << 8) | device_id;
return temp;
}
// 读取状态寄存器
uint8_t W25Q32_ReadStatus(void)
{
uint8_t byte = 0;
W25QXX_CS_LOW();
W25Q32_SPI_ReadWriteByte(W25QXX_READ_STATUS1);
byte = W25Q32_SPI_ReadWriteByte(0xFF);
W25QXX_CS_HIGH();
return byte;
}
// 写使能
void W25Q32_WriteEnable(void)
{
W25QXX_CS_LOW();
W25Q32_SPI_ReadWriteByte(W25QXX_WRITE_ENABLE);
W25QXX_CS_HIGH();
}
// 等待忙标志
void W25Q32_WaitBusy(void)
{
while((W25Q32_ReadStatus() & 0x01) == 0x01);
}
// 写入一个字节
void W25Q32_WriteByte(uint32_t addr, uint8_t data)
{
W25Q32_WaitBusy();
W25Q32_WriteEnable();
W25QXX_CS_LOW();
W25Q32_SPI_ReadWriteByte(W25QXX_PAGE_PROGRAM);
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 16));
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 8));
W25Q32_SPI_ReadWriteByte((uint8_t)addr);
W25Q32_SPI_ReadWriteByte(data);
W25QXX_CS_HIGH();
W25Q32_WaitBusy();
}
// 读取多个字节
void W25Q32_ReadBytes(uint32_t addr, uint8_t *data, uint16_t len)
{
W25Q32_WaitBusy();
W25QXX_CS_LOW();
W25Q32_SPI_ReadWriteByte(W25QXX_READ_DATA);
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 16));
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 8));
W25Q32_SPI_ReadWriteByte((uint8_t)addr);
for(uint16_t i = 0; i < len; i++)
{
data[i] = W25Q32_SPI_ReadWriteByte(0xFF);
}
W25QXX_CS_HIGH();
}
// 写入多个字节
void W25Q32_WriteBytes(uint32_t addr, uint8_t *data, uint16_t len)
{
uint16_t i;
W25Q32_WaitBusy();
W25Q32_WriteEnable();
W25QXX_CS_LOW();
W25Q32_SPI_ReadWriteByte(W25QXX_PAGE_PROGRAM);
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 16));
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 8));
W25Q32_SPI_ReadWriteByte((uint8_t)addr);
for(i = 0; i < len; i++)
{
W25Q32_SPI_ReadWriteByte(data[i]);
}
W25QXX_CS_HIGH();
W25Q32_WaitBusy();
}
// 擦除扇区(4KB)
void W25Q32_EraseSector(uint32_t addr)
{
W25Q32_WaitBusy();
W25Q32_WriteEnable();
W25QXX_CS_LOW();
W25Q32_SPI_ReadWriteByte(W25QXX_SECTOR_ERASE);
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 16));
W25Q32_SPI_ReadWriteByte((uint8_t)(addr >> 8));
W25Q32_SPI_ReadWriteByte((uint8_t)addr);
W25QXX_CS_HIGH();
W25Q32_WaitBusy();
}
at24c02.h
#ifndef __AT24C02_H
#define __AT24C02_H
#include "i2c.h"
#include <stdint.h>
#define AT24C02_ADDR 0xA0 // AT24C02设备地址(写)
#define AT24C02_PAGE_SIZE 8 // 页大小8字节
// 函数声明
uint8_t AT24C02_WriteByte(uint16_t addr, uint8_t data);
uint8_t AT24C02_ReadByte(uint16_t addr);
uint8_t AT24C02_WritePage(uint16_t addr, uint8_t *data, uint16_t len);
uint8_t AT24C02_ReadBytes(uint16_t addr, uint8_t *data, uint16_t len);
#endif
at24c02.c
#include "at24c02.h"
#include "i2c.h"
#include <string.h>
// 写入一个字节
uint8_t AT24C02_WriteByte(uint16_t addr, uint8_t data)
{
uint8_t status;
// 发送起始信号和设备地址(写)
status = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
if(status == HAL_OK)
return 1;
else
return 0;
}
// 读取一个字节
uint8_t AT24C02_ReadByte(uint16_t addr)
{
uint8_t data;
HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
return data;
}
// 写入一页数据(最多8字节)
// 写入一页数据(最多8字节,且不能跨页)
uint8_t AT24C02_WritePage(uint16_t addr, uint8_t *data, uint16_t len)
{
uint16_t i;
uint8_t status;
for(i = 0; i < len; i++)
{
// 单字节写入
status = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR,
addr + i, I2C_MEMADD_SIZE_8BIT,
&data[i], 1, 100);
if(status != HAL_OK)
return 0;
HAL_Delay(10); // 等待写入完成
}
return 1;
}
// 连续读取多个字节
uint8_t AT24C02_ReadBytes(uint16_t addr, uint8_t *data, uint16_t len)
{
uint8_t status = HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR, addr, I2C_MEMADD_SIZE_8BIT, data, len, 100);
return (status == HAL_OK) ? 1 : 0;
}
4、main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include "at24c02.h"
#include "w25q32.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t test_data[] = "Hello STM32!";
uint8_t read_data[32] = {0};
uint8_t eeprom_data[16] = {0};
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
HAL_Init();
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
printf("\r\n=== EEPROM & FLASH Test ===\r\n");
HAL_Delay(100);
/* ========== AT24C02 Test ========== */
printf("\r\n[1] AT24C02:\r\n");
AT24C02_WritePage(0x00, test_data, strlen((char*)test_data));
HAL_Delay(20);
AT24C02_ReadBytes(0x00, eeprom_data, strlen((char*)test_data));
if(strcmp((char*)test_data, (char*)eeprom_data) == 0)
printf(" [OK] Write & Read Passed!\r\n");
else
printf(" [FAIL] Data Mismatch!\r\n");
/* ========== W25Q32 Test ========== */
printf("\r\n[2] W25Q32:\r\n");
if(W25Q32_Init())
{
W25Q32_EraseSector(0x000000);
HAL_Delay(500);
W25Q32_WriteBytes(0x000000, test_data, strlen((char*)test_data));
HAL_Delay(20);
W25Q32_ReadBytes(0x000000, read_data, strlen((char*)test_data));
if(strcmp((char*)test_data, (char*)read_data) == 0)
printf(" [OK] Erase, Write & Read Passed!\r\n");
else
printf(" [FAIL] Data Mismatch!\r\n");
}
else
{
printf(" [FAIL] Init Failed!\r\n");
}
printf("\r\n=== Test Complete ===\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
HAL_Delay(500);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch;
HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
__disable_irq();
while (1) { }
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* USER CODE END 6 */
}
#endif
5、接线
AT24C02左侧的最外侧四个是VCC,中间的才是WP/A0/A1/A2引脚,最里面是GND,所以键帽给中间和最里面盖上就已经接地了
6、测试跑通的结果,并未添加任何功能。
更多推荐



所有评论(0)