stm32cubemx I2C读取AT24C16

本文对如何使用stm32cube生成I2C工程不作说明,仅对在对AT24Cxx系列的使用时作出易忽略的说明;

1、at24cxx页面结构:

stm32cubemx I2C读取AT24C16_第1张图片

从该图可以看出16K(bit)共有128个页,每页由16byte构成。16k = 128 * 16 * 8;

特别注意:除at24c01和at24c02的页由8个byte构成,其它的都是由16byte构成。(这关系到对芯片的连续读写)

2.at24cxx的设备地址:

stm32cubemx I2C读取AT24C16_第2张图片

A:作为设备地址的一部分;P:作为页地址的一部分;

对于大多数人来说都知道I2c设备具有一个设备地址,并且在一条总线上是唯一。若要在一个I2C总线上挂多个AT24CXX系列芯片,则需要A2,A1,A0作为设备地址的一部分,设备地址的最低位作为是读(1)写(0)。

对于在一条总线挂载的设备数:看有几个位用作设备地址。


例:AT24C04: 有两位用作设备地址(A2,A1),一位用作页地址(P0).则可挂载的设备数为2^2 = 4个。

       AT24C16:没有用作设备地址的位,三位用作页地址(P0,P1,P2)。则仅可挂载设备数为2^0= 1个。


可能有人会考虑若A0,A1,A2用作地址了,那实际硬件接线该怎么接呢?

直接按照AT24C02的接就OK了.都接地。

3、页面连续读写:

stm32cubemx I2C读取AT24C16_第3张图片

注意:连续写并不是可以一直连续的写N个数据,而是写一页的数据(AT24C02只能连续写8byte的数据,其它的可以连续写16byte的数据。);

当从某个地址连续写多个数据时,要确定这个地址在某一页的偏移量,从而确定该页中最多还可以连续写多少byte数据。

以AT24C16为例;

比如在0x0025读写,则该位置的偏移量为:0x0025 & 0x000FF = 0x0005, 即该页还可以写  = 每页的字节数 - 偏移量 = 0x0F - 0x05  = 0x0A 即在该页还可以连续写10byte数据;

4、地址问题:

由于在传输过程中,地址数据是一个8位的地址,只能按该8位地址寻址的数据有2^8=256byte数据,

对于容量大于256byte容量的设备,我们还有设备ID中的页地址位可以使用。

例:以AT24C16为例 :

比如我们要访问(写)第0x0456的这一byte数据0x55:

(1)、开始信号:

(2)、设备号(高4位为:1101 p p p r/w), 此时设备号应设置为:0xA4;

(3)、地址:0x56;

(4)、数据:0x55;

(5)、结束;

5、时间控制:


每完成一次写操作后要进行一定的延时,让芯片去处理数据;从该图看,保险的时间为5ms.


例子:

#include "at24c16.h"
#include "i2c.h"

#define E2PROM_SIZE 0x0800    //2k byte 16bit
#define E2PROM_BASE_ID    0xA0

#define E2PROM_WRITE 0x00
#define E2PROM_READ     0x01

#define E2PROM_BASE_WID E2PROM_BASE_ID + E2PROM_WRITE
#define E2PROM_BASE_RID E2PROM_BASE_ID + E2PROM_READ

#define E2PROM_PAGE_MASK    0x000F
uint8_t writeAT24C16(uint16_t addr, uint8_t *data, uint16_t len)
{
    uint8_t wNum = 0;
    uint16_t lenLeft = len;
    uint8_t deviceId ;
    uint8_t *p = data;
    
    /*is the address overfolw*/
    if(addr + len >= E2PROM_SIZE)
        return 1;
    
    /*calculate the current write position to know how many word can write continully*/
    wNum = 16 - addr & E2PROM_PAGE_MASK;
    if(wNum == 0)
        wNum = 16;
    wNum = lenLeft>=wNum ? wNum : lenLeft;
    
    /*transmit the date to e2prom*/
    while(lenLeft)
    {
        /*calculate the device id*/
        deviceId = (addr >> 8)<=0 ?  E2PROM_BASE_WID : (E2PROM_BASE_WID | (uint8_t)((addr>>7)&0x0E));
        
        if( HAL_I2C_Mem_Write(&hi2c1, deviceId, addr&0x00FF, 
                              I2C_MEMADD_SIZE_8BIT, p, wNum, 0x20) != HAL_OK)
        {
            printf("I2S Write error!\r\n");
            HAL_Delay(5);
            continue;
        }            
        addr += wNum;
        lenLeft -= wNum;
        p += wNum;
        wNum = lenLeft > 16 ? 16 : lenLeft;    

        HAL_Delay(5);
    }
    
    return HAL_OK;
}

uint8_t readAT24C16(uint16_t addr, uint8_t *data, uint16_t len)
{
    uint8_t rNum = 0;
    uint16_t lenLeft = len;
    uint8_t deviceId ;
    uint8_t *p = data;

    /*is the address overfolw*/
    if(addr + len >= E2PROM_SIZE)
        return 1;
    
    /*calculate the current write position to know how many word can write continully*/
    rNum = 16 - addr & E2PROM_PAGE_MASK;
    if(rNum == 0)
        rNum = 16;
    rNum = lenLeft>=rNum ? rNum : lenLeft;
    
    /*transmit the date to e2prom*/    
    while(lenLeft)
    {
        /*calculate the device id*/
        deviceId = (addr >> 8)<=0 ?  E2PROM_BASE_RID : (E2PROM_BASE_RID | (uint8_t)((addr>>7)&0x0E));
        
        if( HAL_I2C_Mem_Read(&hi2c1, deviceId, addr&0x00FF, 
                            I2C_MEMADD_SIZE_8BIT, p, rNum, 20) != HAL_OK)
        {
            printf("I2S Read error!\r\n");
            continue;
        }            
        addr += rNum;
        lenLeft -= rNum;
        p += rNum;
        rNum = lenLeft > 16 ? 16 : lenLeft;    
    }
    
    return HAL_OK;    
}


void vE2romTest()
{
    uint8_t WriteBuffer[BufferSize],ReadBuffer[BufferSize];
    uint16_t i;
    printf("\r\n***************I2C Example*******************************\r\n");
    for(i=0; i<256; i++)
            WriteBuffer[i]=i;    /* WriteBuffer init */
    /* wrinte date to EEPROM */
    if(!writeAT24C16(0x05,WriteBuffer,BufferSize))
            printf("\r\n EEPROM 24C16 Write Test OK \r\n");
    else
            printf("\r\n EEPROM 24C16 Write Test False \r\n");
    
    /* read date from EEPROM */
    readAT24C16(0x05,ReadBuffer, BufferSize);
    for(i=0; i<256; i++)
            printf("0x%02X  ",ReadBuffer[i]);

    if(memcmp(WriteBuffer,ReadBuffer,BufferSize) == 0 ) /* check date */
            printf("\r\n EEPROM 24C16 Read Test OK\r\n");
    else
            printf("\r\n EEPROM 24C16 Read Test False\r\n");
}


测试结果:

stm32cubemx I2C读取AT24C16_第4张图片


你可能感兴趣的:(stm32,hal)