STM32MX配置AT24C02 EEPROM详细教程

————————————————————————————————————
⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。
⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动,包括ADC、UART、RS485、EEPROM(IIC)、FLASH(SPI)等等。
⏩本篇文章对STM32CUBEMX配置RRPROM(AT24C02)做一个详细的使用教程。
⏩感谢你的阅读,不对的地方欢迎指正。
————————————————————————————————————

EEPROM

  • AT24C02工作原理
  • 实验环境
  • MX配置
  • 驱动代码
  • 测试结果
  • AT24C02工作原理

    引脚封装

    SCL 串行时钟
    AT24C02串行时钟输入管脚用于产生器件所有数据发送或接收的时钟,这是一个输入管脚。
    SDA 串行数据/地址
    AT24C02 双向串行数据/地址管脚用于器件所有数据的发送或接收,SDA 是一个开漏输出管脚,可与其它开漏输出或集电极开路输出进行线或(wire-OR)。
    A0、A1、A2 器件地址输入端
    这些输入脚用于多个器件级联时设置器件地址,当这些脚悬空时默认值为0。当使用AT24C02 时最大可级联8个器件。如果只有一个AT24C02被总线寻址,这三个地址输入脚(A0、A1、A2 )可悬空或连接到Vss or GND。
    WP 写保护
    如果WP管脚连接到Vcc,所有的内容都被写保护只能读。当WP管脚连接到Vss or GND 或悬空允许器件进行正常的读/写操作。

    具体原理可以参考
    AT24C02芯片使用介绍

    实验环境

  • USB转串口
  • AT24C02
  • STM32H723ZGT6开发板
  • 硬件连接:

    我这里接的是PB8和PB9

    MX配置

    板子、时钟、调试之类的配置就不说了,具体可以看看这篇:
    STM32CUBEMX配置ADC(多通道轮询)(STM32H7)–保姆级教程
    这里只说一下IIC的具体配置
    根据你的连接自己配置

    我的引脚是PB8,PB9

    驱动代码

    at24C02.h
    我使用两个共用体去存储浮点型和整形的数据,这是最简单的方法。

    #ifndef AT24C02_H_
    #define AT24C02_H_
    
    #include "stm32H7xx_hal.h" //HAL库文件声明
    
    #define        AT24C02_ADDR_WRITE          0xA0    // 写命令
    #define        AT24C02_ADDR_READ           0xA1    // 读命令
    
    #define ADDR_24LCxx_Write 0xA0 //AT24C02写地址
    #define ADDR_24LCxx_Read 0xA1  //AT24C02读地址
    #define BufferSize 256         //读写缓冲区大小
    
    union float_union{
    	float float_write_dat;        // 浮点数占4个字节
    	double double_write_dat;    // 双精度浮点数占8个字节
    	uint8_t buf[8];                // 定义 8个字节 的空间
    };
    union int_union{
    	int int_dat; //整型数占四个字节
    	uint8_t buf[4];    //定义4个字节的空间	
    };
    
    uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* dat);  //AT24C02任意地址写一个字节数据
    uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* read_buf);//AT24C02任意地址读一个字节数据
    uint8_t At24c02_Write_Amount_Byte(uint16_t addr, uint8_t* dat, uint16_t size);// AT24C02任意地址连续写多个字节数据
    uint8_t At24c02_Read_Amount_Byte(uint16_t addr, uint8_t* recv_buf, uint16_t size);//AT24C02任意地址连续读多个字节数据
    #endif
    

    at24c02.c

    #include "at24c02.h"
    #include "i2c.h"
    /**
     * @brief        AT24C02任意地址写一个字节数据
     * @param        addr —— 写数据的地址(0-255)
     * @param        dat  —— 存放写入数据的地址
     * @retval       成功 —— HAL_OK
    */
    uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* dat)
    {
        HAL_StatusTypeDef result;
        result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, 1, 0xFFFF);
        HAL_Delay(5);    // 写一个字节,延迟一段时间,不能连续写
        return result;
    }
     
    /**
     * @brief        AT24C02任意地址读一个字节数据
     * @param        addr —— 读数据的地址(0-255)
     * @param        read_buf —— 存放读取数据的地址
     * @retval       成功 —— HAL_OK
    */
    uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* read_buf)
    {
        return HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, addr, I2C_MEMADD_SIZE_8BIT, read_buf, 1, 0xFFFF);
    }
     
    /**
     * @brief        AT24C02任意地址连续写多个字节数据
     * @param        addr —— 写数据的地址(0-255)
     * @param        dat  —— 存放写入数据的地址
     * @retval       成功 —— HAL_OK
    */
    uint8_t At24c02_Write_Amount_Byte(uint16_t addr, uint8_t* dat, uint16_t size)
    {
        uint8_t i = 0;
        uint16_t cnt = 0;        // 写入字节计数
        HAL_StatusTypeDef result;    // 返回是否写入成功
     
        /* 对于起始地址,有两种情况,分别判断 */
        if(0 == addr % 8)
        {
            /* 起始地址刚好是页开始地址 */
            /* 对于写入的字节数,有两种情况,分别判断 */
            if(size <= 8)
            {
                // 写入的字节数不大于一页,直接写入
                result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, size, 0xFFFF);
                HAL_Delay(20);    // 写完八个字节(最多八个字节),延迟久一点
                return result;
            }
            else
            {
                // 写入的字节数大于一页,先将整页循环写入
                for(i = 0; i < size/8; i++)
                {
                    HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], 8, 0xFFFF);
                    // 一次写入了八个字节,延迟久一点
                    HAL_Delay(20);    // 写完八个字节,延迟久一点
                    addr += 8;
                    cnt += 8;
                }
                // 将剩余的字节写入
                result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], size - cnt, 0xFFFF);
                HAL_Delay(20);    // 写完八个字节(最多八个字节),延迟久一点
                return result;
            }
        }
        else
        {
            /* 起始地址偏离页开始地址 */
            /* 对于写入的字节数,有两种情况,分别判断 */
            if(size <= (8 - addr%8))
            {
                /* 在该页可以写完 */
                result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, size, 0xFFFF);
                HAL_Delay(20);    // 写完八个字节(最多八个字节),延迟久一点
                return result;
            }
            else
            {
                /* 该页写不完 */
                // 先将该页写完
                cnt += 8 - addr%8;
                HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, dat, cnt, 0xFFFF);
                HAL_Delay(20);    // 写完八个字节(最多八个字节),延迟久一点
                addr += cnt;
     
                // 循环写整页数据
                for(i = 0;i < (size - cnt)/8; i++)
                {
                    HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], 8, 0xFFFF);
                    HAL_Delay(20);    // 写完八个字节,延迟久一点
                    addr += 8;
                    cnt += 8;
                }
                // 将剩下的字节写入
                result = HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, &dat[cnt], size - cnt, 0xFFFF);
                HAL_Delay(20);    // 写完八个字节(最多八个字节),延迟久一点
                return result;
            }            
        }
    }
     
    /**
     * @brief        AT24C02任意地址连续读多个字节数据
     * @param        addr —— 读数据的地址(0-255)
     * @param        dat  —— 存放读出数据的地址
     * @retval       成功 —— HAL_OK
    */
    uint8_t At24c02_Read_Amount_Byte(uint16_t addr, uint8_t* recv_buf, uint16_t size)
    {
        return HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, addr, I2C_MEMADD_SIZE_8BIT, recv_buf, size, 0xFFFF);
    }
    
    
    

    main.c

    //AT24C02
    uint8_t WriteBuffer[BufferSize] = {0};//AT24C02写缓冲区
    uint8_t ReadBuffer[BufferSize] = {0}; //AT24C02读缓冲区
    
    //测试
        // 单个字节 读写测试
        uint8_t simple_write_dat = 0xa5;    // 一个字节
        uint8_t simple_recv_buf = 0;
     
        if(HAL_OK == At24c02_Write_Byte(10, &simple_write_dat)){
            printf("Simple data write success \r\n");
        } else {
            printf("Simple data write fail \r\n");
        }
        
        HAL_Delay(50);      // 写一次和读一次之间需要短暂的延时
        
        if(HAL_OK == At24c02_Read_Byte(10, &simple_recv_buf)){
            printf("Simple data read success, recv_buf = 0x%02X \r\n", simple_recv_buf);
        } else {
            printf("Simple data read fail \r\n");
        }
        printf("--------------------- \r\n");
        // 单个字节读写 测试结束
        
        // 浮点数 读写测试
        union float_union send_float_data;    // 用来发送
        union float_union rev_float_data;     // 用来接收
        union int_union   send_int_data;      //发送
    		union int_union   rev_int_data;       //接收
        // 先测试第一个 浮点数
        send_float_data.float_write_dat = 3.1415f;
        if(HAL_OK == At24c02_Write_Amount_Byte(20, send_float_data.buf, 4)){
            printf("Float data write success \r\n");
        } else {
            printf("Float data write fail \r\n");
        }
        HAL_Delay(50);
        if(HAL_OK == At24c02_Read_Amount_Byte(20, rev_float_data.buf, 4)){
            // 默认输出六位小数
            printf("Float data read success, recv_buf = %f \r\n", rev_float_data.float_write_dat);
        } else {
            printf("Float data read fail \r\n");
        }
        // 测试第二个 双精度浮点数
        send_float_data.double_write_dat = 3.1415f;
        if(HAL_OK == At24c02_Write_Amount_Byte(20, send_float_data.buf, 8)){
            printf("Double data write success \r\n");
        } else {
            printf("Double data write fail \r\n");
        }
        HAL_Delay(50);
        if(HAL_OK == At24c02_Read_Amount_Byte(20, rev_float_data.buf, 8)){
            // 最多15位小数
            printf("Double data read success, recv_buf = %.15f \r\n", rev_float_data.double_write_dat);
        } else {
            printf("Double data read fail \r\n");
        }
        printf("--------------------- \r\n");
        // 浮点数读写测试 测试结束
    		// 测试第三个 整形数
    		send_int_data.int_dat = 2147483647;
        if(HAL_OK == At24c02_Write_Amount_Byte(30,send_int_data.buf, 4)){
            printf("int data write success \r\n");
        } else {
            printf("int data write fail \r\n");
        }
        HAL_Delay(50);
        if(HAL_OK == At24c02_Read_Amount_Byte(30, rev_int_data.buf, 4)){
            printf("int data read success, recv_buf = %d \r\n", rev_int_data.int_dat);
        } else {
            printf("int data read fail \r\n");
        }
        printf("--------------------- \r\n");
        // 整型数读写测试 测试结束
        // 连续数据读写测试
        uint8_t write_dat[22] = {0};        // 22个字节
        uint8_t recv_buf[22] = {0};
        
        printf("正在往数组中填充数据... \r\n");
        for(int i = 0; i < 22; i++){
            write_dat[i] = i;
            printf("%02X ", write_dat[i]);
        }
        printf("\r\n 数组中数据填充完毕... \r\n");
        
        if(HAL_OK == At24c02_Write_Amount_Byte(0, write_dat, 22)){
            printf("24c02 write success \r\n");
        } else {
            printf("24c02 write fail \r\n");
        }
        
        HAL_Delay(50);      // 写一次和读一次之间需要短暂的延时
        
        if(HAL_OK == At24c02_Read_Amount_Byte(0, recv_buf, 22)){
            printf("read success \r\n");
            for(int i = 0; i < 22; i++) {
                printf("0x%02X ", recv_buf[i]);
            }
        } else {
            printf("read fail\r\n");
        }
        // 连续数据读写 测试结束
    
    
    

    测试结果


    可以看到存取单个字节、多个字节、浮点数、双精度浮点数、整型数都没有问题。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32MX配置AT24C02 EEPROM详细教程

    发表评论