ESP32開發之路(10)— ESP32的I2C通信讀寫AT24C02

ESP32開發之路(10)— ESP32的I2C通信讀寫AT24C02

一、前言

之前我們將ESP32的基本功能—WiFi都差不多試過了,進行了就來使用一下他的其他功能,比如I2C通信,I2C是一種典型的低速硬件通信協議,我想很多人的I2C通信都是從AT24C02開始的,所以我們ESP32的I2C通信也從AT24C02開始。
因爲某種原因,我手邊沒有單獨的AT24C02模塊,所以就把小熊派E53_SC1擴展板拿來用一下,因爲他上面有一個AT24C02,如下所示:
在這裏插入圖片描述
通過其地址設置引腳的接線我們知道,其地址應該爲0xA2(左移後),可實際上,三個地址設置引腳都接到了地,不知道是不是因爲改版的原因,所以在使用的時候最好從實際硬件去確認一下其器件地址。

二、參數配置

在使用IIC各種需要使用到一些參數,我們使用宏定義的方式去設置,首先,是IIC的讀寫控制:

#define WRITE_BIT 0x00          /*!< I2C master write */
#define READ_BIT 0x01           /*!< I2C master read */

然後是IIC的應答機制的設置:

#define ACK_CHECK_EN 0x1                    /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0                   /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0                         /*!< I2C ack value */
#define NACK_VAL 0x1                        /*!< I2C nack value */

接下來是IIC引腳的設置,ESP32由兩個IIC控制器,分別對應不同的引腳,我們設置爲如下,可以通過定義來選擇使用哪一個IIC控制器:

#if 1
#define IIC_CTRL_NUM I2C_NUM_1              /*!< I2C port number */
#define SDA_PIN_NUM 25                      /*!< gpio number for I2C data  */
#define SCL_PIN_NUM 26                      /*!< gpio number for I2C clock */
#else
#define IIC_CTRL_NUM I2C_NUM_0              /*!< I2C port number */
#define SDA_PIN_NUM 18                      /*!< gpio number for I2C data  */
#define SCL_PIN_NUM 19                      /*!< gpio number for I2C clock */
#endif

還有最重要的AT24C02的器件地址

#define AT24C02_DeviceAddr 0xA0             /* AT24C02的器件地址 */

三、編寫AT24C02控制函數

首先我們需要初始化IIC控制器,設置爲主模式,

/**
 * @brief i2c master initialization
 */
static esp_err_t i2c_master_init(void)
{
    int i2c_master_port = IIC_CTRL_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = SDA_PIN_NUM;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = SCL_PIN_NUM;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = 100000;     /* 標準模式(100 kbit/s) */
    i2c_param_config(i2c_master_port, &conf);
    return i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
}

然後是對AT24C02的寫入一個字節函數:

/* AT24C02寫入一個字節函數,第一個參數爲要寫入的值,第二個參數爲要寫入的地址*/
static esp_err_t at24c02_write(uint8_t data_wr, uint16_t WriteAddr)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, AT24C02_DeviceAddr | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, WriteAddr % 256, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, data_wr, ACK_CHECK_EN);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(IIC_CTRL_NUM, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

然後是讀取一個字節的函數:

/* AT24C02讀取一個字節函數,第一個參數爲要讀出值的存放指針,第二個參數爲要讀出的地址*/
static esp_err_t at24c02_read(uint8_t* data_rd, uint16_t ReadAddr)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, AT24C02_DeviceAddr | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, ReadAddr % 256, ACK_CHECK_EN);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, 0xA0 | READ_BIT, ACK_CHECK_EN);
    i2c_master_read_byte(cmd, data_rd, NACK_VAL);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(IIC_CTRL_NUM, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

四、讀寫AT24C02

接下來,編寫程序對AT24C02進行讀取

void app_main(void)
{
    uint8_t data_buf = 0xff;
    /* 打印Hello world! */
    printf("Hello world!\n");

    /* 初始化IIC控制器 */
    ESP_ERROR_CHECK(i2c_master_init());

    /* 讀取AT24C02裏的數據 */
    if(at24c02_read(&data_buf, 0x02) == ESP_OK)
        printf("Read at24c02 in 0x02, data = 0x%x \n",data_buf);
    else
        printf("Read at24c02 err \n");

    /* 向AT24C02寫入數據 */
    if(at24c02_write(0x55, 0x02) == ESP_OK)
        printf("Write 0x55 to at24c02 in 0x02 \n");
    else
        printf("Write at24c02 err \n");

    /* 讀取AT24C02裏的數據 */
    if(at24c02_read(&data_buf, 0x02) == ESP_OK)
        printf("Read at24c02 in 0x02, data = 0x%x \n",data_buf);
    else
        printf("Read at24c02 err \n");
}

編譯下載運行,結果如下,可以看到,讀寫數據成功
在這裏插入圖片描述
替換爲另一組IIC控制器,
在這裏插入圖片描述編譯下載運行,讀寫數據依然成功
在這裏插入圖片描述

五、代碼

下面貼上完整的app_main.c的代碼

#include <string.h>
#include <sys/param.h>
#include "driver/i2c.h"

#define GPIO_LED_NUM 2                      /* LED引腳編號 */

#define WRITE_BIT 0x00                      /*!< I2C master write */
#define READ_BIT 0x01                       /*!< I2C master read  */

#define ACK_CHECK_EN 0x1                    /*!< I2C master will check ack from slave     */
#define ACK_CHECK_DIS 0x0                   /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0                         /*!< I2C ack value  */
#define NACK_VAL 0x1                        /*!< I2C nack value */

#if 0
#define IIC_CTRL_NUM I2C_NUM_1              /*!< I2C port number */
#define SDA_PIN_NUM 25                      /*!< gpio number for I2C data  */
#define SCL_PIN_NUM 26                      /*!< gpio number for I2C clock */
#else
#define IIC_CTRL_NUM I2C_NUM_0              /*!< I2C port number */
#define SDA_PIN_NUM 18                      /*!< gpio number for I2C data  */
#define SCL_PIN_NUM 19                      /*!< gpio number for I2C clock */
#endif

#define AT24C02_DeviceAddr 0xA0             /* AT24C02的器件地址 */

/**
 * @brief i2c master initialization
 */
static esp_err_t i2c_master_init(void)
{
    int i2c_master_port = IIC_CTRL_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = SDA_PIN_NUM;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = SCL_PIN_NUM;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = 100000;     /* 標準模式(100 kbit/s) */
    i2c_param_config(i2c_master_port, &conf);
    return i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
}

/* AT24C02讀取一個字節函數,第一個參數爲要讀出值的存放指針,第二個參數爲要讀出的地址*/
static esp_err_t at24c02_read(uint8_t* data_rd, uint16_t ReadAddr)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, AT24C02_DeviceAddr | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, ReadAddr % 256, ACK_CHECK_EN);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, 0xA0 | READ_BIT, ACK_CHECK_EN);
    i2c_master_read_byte(cmd, data_rd, NACK_VAL);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(IIC_CTRL_NUM, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

/* AT24C02寫入一個字節函數,第一個參數爲要寫入的值,第二個參數爲要寫入的地址*/
static esp_err_t at24c02_write(uint8_t data_wr, uint16_t WriteAddr)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, AT24C02_DeviceAddr | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, WriteAddr % 256, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, data_wr, ACK_CHECK_EN);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(IIC_CTRL_NUM, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

void app_main(void)
{
    uint8_t data_buf = 0x00;
    /* 打印Hello world! */
    printf("Hello world!\n");

    /* 初始化IIC控制器 */
    ESP_ERROR_CHECK(i2c_master_init());

    /* 讀取AT24C02裏的數據 */
    if(at24c02_read(&data_buf, 0x03) == ESP_OK)
        printf("Read at24c02 in 0x03, data = 0x%x \n",data_buf);
    else
        printf("Read at24c02 err \n");

    /* 向AT24C02寫入數據 */
    if(at24c02_write(0x55, 0x03) == ESP_OK)
        printf("Write 0x55 to at24c02 in 0x03 \n");
    else
        printf("Write at24c02 err \n");

    /* 讀取AT24C02裏的數據 */
    if(at24c02_read(&data_buf, 0x03) == ESP_OK)
        printf("Read at24c02 in 0x03, data = 0x%x \n",data_buf);
    else
        printf("Read at24c02 err \n");

    /* 定義一個gpio配置結構體 初始化LED */
    gpio_config_t gpio_config_structure;

    /* 初始化gpio配置結構體*/
    gpio_config_structure.pin_bit_mask = (1ULL << GPIO_LED_NUM);/* 選擇gpio2 */
    gpio_config_structure.mode = GPIO_MODE_OUTPUT;              /* 輸出模式 */
    gpio_config_structure.pull_up_en = 0;                       /* 不上拉 */
    gpio_config_structure.pull_down_en = 0;                     /* 不下拉 */
    gpio_config_structure.intr_type = GPIO_PIN_INTR_DISABLE;    /* 禁止中斷 */ 

    /* 根據設定參數初始化並使能 */  
	gpio_config(&gpio_config_structure);
    /* 默認熄滅LED */
    gpio_set_level(GPIO_LED_NUM, 0);        /* 熄滅 */

    while(1)
    {
        gpio_set_level(GPIO_LED_NUM, 0);        /* 熄滅 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延時500ms*/
        gpio_set_level(GPIO_LED_NUM, 1);        /* 點亮 */
        vTaskDelay(500 / portTICK_PERIOD_MS);   /* 延時500ms*/
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章