stm32cubemx I2C讀取AT24C16

本文對如何使用stm32cube生成I2C工程不作說明,僅對在對AT24Cxx系列的使用時作出易忽略的說明;

1、at24cxx頁面結構:

從該圖可以看出16K(bit)共有128個頁,每頁由16byte構成。16k = 128 * 16 * 8;

特別注意:除at24c01和at24c02的頁由8個byte構成,其它的都是由16byte構成。(這關係到對芯片的連續讀寫)

2.at24cxx的設備地址:

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、頁面連續讀寫:

注意:連續寫並不是可以一直連續的寫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");
}


測試結果:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章