STM32CubeMX + HAL 库:用硬件IIC接口实现AT24C02 EEPROM芯片的读写操作
本实验基于STM32硬件I²C接口实现了AT24C02 EEPROM的读写操作,包括单字节、多字节和跨页写入功能。实验详细介绍了I²C协议原理、AT24C02芯片特性及与Flash存储器的区别,提供了完整的驱动代码和STM32CubeMX配置方法。实验结果为嵌入式系统中的小容量数据存储应用(如配置参数保存)提供了实用方案,同时指出该驱动不适用于地址空间更大的AT24C32等型号。
1 概述
1.1 实验目的
本实验旨在通过 STM32 微控制器的硬件 I²C 接口,对 AT24C02 外部 EEPROM 存储芯片 进行读写操作。实验演示了芯片地址配置、单字节/多字节读写、跨页写入(Page Write)功能。并提供完整的驱动代码,帮助读者深入理解 STM32 硬件 I²C 通信协议 的工作机制,并掌握基于 I²C 总线的低速存储设备 的数据存储与访问方法。
通过本实验,读者不仅可以掌握 I²C 接口的基本使用技巧,还能够熟悉 AT24C02 的命令结构、存储特性及应用方法。这对于日后在嵌入式系统开发中涉及 小容量数据存储(如配置参数、掉电保存数据、传感器校准值等) 提供了技术积累和实践基础,具有良好的工程指导意义。
1.2 IIC协议
I2C(Inter-Integrated Circuit)是一种同步、半双工、多主多从的串行通信协议。它通过两根信号线(SCL时钟线、SDA数据线)实现设备间通信,广泛应用于传感器、存储器、显示器等低速外设与主控制器(如MCU)的连接。接口引脚
| 引脚名称 | 全称 | 功能说明 | 方向 | 特点 |
|---|---|---|---|---|
| SCL | Serial Clock | 串行时钟信号,由主设备(Master)产生,用于同步数据传输 | 主输出从输入 | 开漏/开集电极输出,需要上拉电阻 |
| SDA | Serial Data | 串行数据信号,双向传输数据(主、从设备之间共用) | 双向 | 开漏/开集电极输出,需要上拉电阻 |
1.3 AT24C02介绍

1.3.1 芯片引脚
| 引脚号 | 名称 | 功能说明 |
|---|---|---|
| 1 | A0 | 器件地址选择引脚(Address Input 0),用于设定 I²C 从机地址的低位。可接 GND 或 VCC。 |
| 2 | A1 | 器件地址选择引脚(Address Input 1),作用同 A0。 |
| 3 | A2 | 器件地址选择引脚(Address Input 2),作用同 A0。 |
| 4 | GND | 电源地。 |
| 5 | SDA | 串行数据线(Serial Data)。I²C 双向数据线,开漏输出,需要上拉电阻。 |
| 6 | SCL | 串行时钟线(Serial Clock)。由 I²C 主机产生,开漏输出,需要上拉电阻。 |
| 7 | WP | 写保护(Write Protect)。高电平时禁止写操作(只读),低电平时可读可写。 |
| 8 | VCC | 电源正极(常用 2.7V–5.5V)。 |

1.3.2 芯片地址
AT24C 系列 EEPROM 的 I²C 从机地址由固定的高 4 位(1010)和由引脚 A2、A1、A0 决定的 3 位地址位组成,最后一位是读写控制位(R/W)。A0~A2 引脚可接高电平(VCC)或低电平(GND)来改变芯片地址,从而在同一总线上使用多个 EEPROM 设备。
-
写操作地址:R/W = 0
-
读操作地址:R/W = 1
因此,芯片最多可以有8种地址,枚举如下
| A2 | A1 | A0 | 7 位地址(十六进制) | 写地址(8 位) | 读地址(8 位) |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0x50 | 0xA0 | 0xA1 |
| 0 | 0 | 1 | 0x51 | 0xA2 | 0xA3 |
| 0 | 1 | 0 | 0x52 | 0xA4 | 0xA5 |
| 0 | 1 | 1 | 0x53 | 0xA6 | 0xA7 |
| 1 | 0 | 0 | 0x54 | 0xA8 | 0xA9 |
| 1 | 0 | 1 | 0x55 | 0xAA | 0xAB |
| 1 | 1 | 0 | 0x56 | 0xAC | 0xAD |
| 1 | 1 | 1 | 0x57 | 0xAE | 0xAF |
1.3.3 其他型号
| 型号 | 寻址范围 | 页大小(Byte) | 页数量 | 总容量(Byte) | 总容量(Kbit) |
|---|---|---|---|---|---|
| AT24C01 | 0x00 – 0x7F | 8 | 16 | 128 | 1 Kbit |
| AT24C02 | 0x00 – 0xFF | 8 | 32 | 256 | 2 Kbit |
| AT24C04 | 0x000 – 0x1FF | 16 | 32 | 512 | 4 Kbit |
| AT24C08 | 0x000 – 0x3FF | 16 | 64 | 1024 | 8 Kbit |
| AT24C16 | 0x000 – 0x7FF | 16 | 128 | 2048 | 16 Kbit |
| AT24C32 | 0x0000 – 0x0FFF | 32 | 128 | 4096 | 32 Kbit |
| AT24C64 | 0x0000 – 0x1FFF | 32 | 256 | 8192 | 64 Kbit |
| AT24C128 | 0x0000 – 0x3FFF | 64 | 256 | 16384 | 128 Kbit |
| AT24C256 | 0x0000 – 0x7FFF | 64 | 512 | 32768 | 256 Kbit |
| AT24C512 | 0x0000 – 0xFFFF | 128 | 512 | 65536 | 512 Kbit |
注:在阅读芯片资料时,AT24C02的页大小是8字节,但在实际测试过程中,我发现芯片页大小其实是16字节。其实是芯片版本不同导致的,我芯片具体型号是Atmel327 24C02BN 其中 “24C02BN” 里的 B 版本,就是 16 Byte 页大小的版本。而 N 一般表示封装(SOIC、PDIP、TSSOP 等)及无铅环保版本,不影响存储结构。
| 版本标识 | 页大小 | 总容量 | 备注 |
|---|---|---|---|
| AT24C02A / AT24C02C | 8 Byte | 256 Byte | 经典版本,很多资料引用这个 |
| AT24C02B / AT24C02BN | 16 Byte | 256 Byte | 后期改进版,页写效率更高 |
1.3.4 与flash区别
| 对比项 | AT24C02(I²C EEPROM) | W25Q32(SPI NOR Flash) |
|---|---|---|
| 总容量 | 256 Byte | 4 MByte |
| 接口 | I²C(2 线) | SPI(4 线) |
| 最小写入单元 | 1 Byte(页写一次最多 8 Byte) | 1 Byte(页编程一次最多 256 Byte) |
| 最小擦除单元 | 无需擦除,自动覆盖 | 4KB 扇区 |
| 擦写机制 | 自动擦写,直接覆盖 | 擦除→写入(1→0,0→1 需擦除) |
| 写入延迟 | 固定 5ms 左右/页写 | 擦除慢(50~150ms),写快(<1ms) |
| 寿命 | 100 万次写/字节 | 10 万次擦/扇区 |
| 断电数据保持 | 典型 100 年 | 典型 20 年 |
| 使用场景 | 小容量配置存储 | 大容量固件、资源存储 |
AT24C02芯片是EEPROM类型芯片,写入不用擦除,相对方便,字节在对应地址中写入数据即可,如果原来有就覆盖。
2. STM32CubeMX 配置
2.1 SYS配置
不管你用的是STLink 还是JLink,都属于并行调试下载,所以在配置SYS时,均以下图为准。

2.2 RCC配置


2.3 USART配置
用于串口打印日志,调试用

2.4 IIC配置
由于芯片连接的是stm32通用引脚PB10和PB11,这两个引脚的复用接口是stm32第二个IIC的接口,所以此处配置要选IIC2和硬件连线相匹配。

2.5 project配置


3. Keil MDK配置
3.1 debug配置
根据自己的下载器选择debug现象,作者用的JLink

避免每次下载完程序后,还要按复位键才能跑最新程序

3.2 target配置
为了使用串口进行调试重定向打印调试信息,在target设置卡中引入LIB包

3.3 新增文件夹及文件

3.4 配置工程目录

3.5 配置工程文件

4. VSCode代码
4.1 驱动文件
#include "at24c02.h"
#include "string.h"
/**
特性 M24C02 (2Kbit) M24C32 (32Kbit)
容量 256字节 (0x00-0xFF) 4096字节 (0x000-0xFFF)
地址位宽 8位地址 16位地址(需2字节)
页大小 16字节/页 32字节/页
页数量 16页 128页
设备地址 固定(A2-A0=0) 固定(A2-A0=0)
24C32
第 0 页:0x0000 ~ 0x001F(32 字节)
第 1 页:0x0020 ~ 0x003F(32 字节)
第 2 页:0x0040 ~ 0x005F(32 字节)
...
第 127 页:0x0F80 ~ 0x0FFF(32 字节)
总字节数:128 页 × 32 字节/页 = 4,096 字节(与 AT24C32 容量一致)。
24C02
第 0 页:0x00 ~ 0x0F(16 字节)
第 1 页:0x10 ~ 0x1F(16 字节)
第 2 页:0x20 ~ 0x2F(16 字节)
...
第 15 页:0xF0 ~ 0xFF(16 字节)
总字节数:16 页 × 16 字节/页 = 256 字节(与 AT24C02 容量一致)。
*/
//向EEPROM写入一个字节
void AT24C02_WriteByte(uint8_t innerAddr, uint8_t byte){
HAL_I2C_Mem_Write(&hi2c2, W_ADDR, innerAddr, I2C_MEMADD_SIZE_8BIT , &byte , 1 , 1000);
// 延迟等待写入周期结束
HAL_Delay(5);
}
//读取EEPROM一个字节
uint8_t AT24C02_ReadByte(uint8_t innerAddr){
uint8_t byte;
HAL_I2C_Mem_Read(&hi2c2, R_ADDR, innerAddr, I2C_MEMADD_SIZE_8BIT , &byte , 1 ,1000);
return byte;
}
//连续写入多个字节(页写入)
void AT24C02_WriteBytes(uint8_t innerAddr, uint8_t *bytes, uint8_t size){
HAL_I2C_Mem_Write(&hi2c2, W_ADDR, innerAddr, I2C_MEMADD_SIZE_8BIT , bytes, size , 1000);
// 延迟等待写入周期结束
HAL_Delay(5);
}
//连续读出多个字节(页读出 等价于 跨页读出)
void AT24C02_ReadBytes(uint8_t innerAddr, uint8_t *buffer, uint8_t size){
HAL_I2C_Mem_Read(&hi2c2, R_ADDR, innerAddr, I2C_MEMADD_SIZE_8BIT , buffer , size ,1000);
}
//跨页写入
void AT24C02_WriteBytesPro(uint8_t innerAddr, uint8_t *data, uint8_t size) {
while (size > 0) {
uint8_t page_offset = innerAddr % EEPROM_PAGE_SIZE; // AT24C02 页大小通常是 8 或 16
uint8_t page_space = EEPROM_PAGE_SIZE - page_offset;
uint8_t bytes_to_write = (size < page_space) ? size : page_space;
// 使用 HAL_I2C_Mem_Write 自动处理地址
HAL_I2C_Mem_Write(
&hi2c2, W_ADDR, innerAddr, I2C_MEMADD_SIZE_8BIT,
data, bytes_to_write, HAL_MAX_DELAY
);
HAL_Delay(5); // AT24C02 写入需要 5ms
// 更新指针和剩余长度
innerAddr += bytes_to_write; // 确保这里正确递增
data += bytes_to_write;
size -= bytes_to_write;
}
}
#ifndef __AT24C02_H__
#define __AT24C02_H__
#include "i2c.h"
#define W_ADDR 0xA0
#define R_ADDR 0xA1
// 每页写入限制大小16字节
#define EEPROM_PAGE_SIZE 16
//向EEPROM写入一个字节
void AT24C02_WriteByte(uint8_t innerAddr, uint8_t byte);
//读取EEPROM一个字节
uint8_t AT24C02_ReadByte(uint8_t innerAddr);
//连续写入多个字节(页写入)
void AT24C02_WriteBytes(uint8_t innerAddr, uint8_t * bytes, uint8_t size);
//连续读出多个字节(可跨页读出)
void AT24C02_ReadBytes(uint8_t innerAddr, uint8_t * buffer, uint8_t size);
//跨页写入函数
void AT24C02_WriteBytesPro(uint8_t innerAddr, uint8_t *data, uint8_t size);
#endif
4.2 usart重定向代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.c
* @brief This file provides code for the configuration
* of the USART instances.
******************************************************************************
* @attention
*
* Copyright (c) 2025 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 "usart.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
UART_HandleTypeDef huart1;
/* USART1 init function */
void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspInit 0 */
/* USER CODE END USART1_MspInit 0 */
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 4, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
/* USER CODE END USART1_MspInit 1 */
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspDeInit 0 */
/* USER CODE END USART1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART1_CLK_DISABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
/* USART1 interrupt Deinit */
HAL_NVIC_DisableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspDeInit 1 */
/* USER CODE END USART1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
int fputc(int ch, FILE * file){ //打印重定向
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,1000);
return ch;
}
/* USER CODE END 1 */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.h
* @brief This file contains all the function prototypes for
* the usart.c file
******************************************************************************
* @attention
*
* Copyright (c) 2025 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 */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_USART1_UART_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */
4.3 主函数
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 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 "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "at24c02.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 */
/* 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--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
printf("hello my at24c02\t\n");
//读写单个字节
AT24C02_WriteByte(0x00,'A');
uint8_t byte1 = AT24C02_ReadByte(0x00);
printf("byte1= %c\t" , byte1);
// 读写多个字节
AT24C02_WriteBytes(0x00,"123456",6);
uint8_t buffer[100] = {0};
AT24C02_ReadBytes(0x00,buffer,6);
printf("buffer= %s\n" , buffer);
// 跨页读写
uint8_t bufferPro[256] = {0};
AT24C02_WriteBytesPro(0x00,"Hello darkness, my old friend,I've come to talk with you again,Because a vision softly creeping, Left its seeds while I was sleeping, And the vision that was planted in my brain Still remains Within the sound of silence.",255);
AT24C02_ReadBytes(0x00,bufferPro,255);
printf("bufferPro= %s\n" , bufferPro);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(3000);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
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();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
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 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
5. 结论

本次实验 成功验证了 AT24C02 EEPROM 的基本读写功能,包括单字节、多字节连续读写和跨页读写。通过STM32硬件I2C 协议与芯片通信,确保了数据存储的准确性和可靠性。实验结果符合预期,为后续 数据掉电存储、传感器数据记录 等应用奠定了基础。注意事项:
- I2C 地址参数:AT24C02 必须使用
I2C_MEMADD_SIZE_8BIT。 - 页边界处理:跨页写入需分页处理,避免数据丢失,芯片24C02带后缀B版本页大小为16字节。
- 写入延迟:EEPROM 写入后需等待 5ms 确保数据固化。
- 芯片地址:注意查看芯片地址引脚接线,判断地址。
如果读者采用AT24C32芯片,那么上述驱动文件是不可共用的,因为AT24C32的地址是两个字节,且页存储为32字节,共128页,总存储32Kbit,是AT24C02的16倍,存储空间结构完全不同。如果读者感兴趣,可以评论区留言,作者提供AT24C32相关的驱动文件。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)