1. 程式人生 > >ESP32學習筆記(四)之I2C總線

ESP32學習筆記(四)之I2C總線

oid 操作系統 parameter ica basis condition 技術分享 col rto

上一篇帖子我們了解了一下ESP32運行多任務的操作以及現象,其實也就是一個實時操作系統。那麽,這篇帖子我們就結合“LM75a”溫度傳感器來學習一下ESP32的IIC總線吧。


首先我們通過esp32_technical_referance發現,esp32的I2C總線具有以下特性

? 支持主機模式以及從機模式
? 支持多主機多從機通信
? 支持標準模式(100 kbit/s)
? 支持快速模式(400 kbit/s)
? 支持7-bit 以及10-bit 尋址
? 支持關閉SCL 時鐘實現連續數據傳輸
? 支持可編程數字噪聲濾波功能


ESP32的I2C控制器可以工作於Master 模式或者Slave 模式,我們這裏只以Master模式為例。


技術分享圖片




上圖為ESP32 I2C Master模式的基本架構,包含了32X8 Bit的RAM,16 個命令寄存器(cmd0 ~ cmd15) 以及一個CMD_Controller,2個總線控制器,2個總線濾波器以及一個數據移位寄存器。

看起來挺復雜的樣子,其實實際操作起來,只有命令寄存器跟我們直接接觸得最多吧,個人感覺,嗯。

具體跟寄存器相關的就介紹到這裏,感興趣的朋友可以自行查看esp32_technical_referance,那麽接下來就該談怎麽操作以及實驗了。

首先,調用庫函數,初始化I2C總線(類似於stm32那樣)

技術分享圖片


這個初始化結構體看起來也挺簡單
初始化模式 :Master
IO口引腳 :ESP32具有兩個I2C,分別映射到的引腳為18 19 25 26。我們這裏選擇I2C0,也就是I2C_NUM_0
,對應18 19號引腳。
總線上拉使能 :enable
總線速度 :100K

調用初始化i2c_param_config()函數把初始化好的結構體參數傳回去,這裏特別要註意的是第一個參數選擇的是I2C0還是選擇I2C1,前者對應I2C_NUM_0,後者對應I2C_NUM_0。
然後調用i2c_driver_install ()安裝I2C驅動。

初始化完成之後開始寫I2C的讀寫函數。在寫這兩個函數之前,先看看兩幅圖



技術分享圖片

技術分享圖片




這兩張是官方API Reference裏面關於讀寫操作的指導圖,圖片非常詳細的介紹了ESP32 I2C讀寫操作需要調用哪些函數以及每個函數有什麽作用,因此,不具體談每個函數的用法了,不明白的朋友可以看看去官方API Reference。然後再結合圖片來看一下這兩個函數具體怎麽寫。





技術分享圖片



技術分享圖片

OK,讀寫函數也有了,那麽接下來說說Lm75a
LM75a是I2C總線接口的溫度傳感器,可以精確到0.125攝氏度,精度高而且很便宜。我們要用到的是其內部一共有5個寄存器,看得見的其實只有四個

技術分享圖片

假如我沒有理解錯誤手冊的話,這幾個寄存器是通過一個指針寄存器來索引訪問的,因此可以看到這四個寄存器地址排列的這麽整齊。
我們要用到其實只有Temp這個寄存器,這是用來保存溫度值的。

技術分享圖片

然後這是從機地址選擇,我把他們都接了GND,因此Slave_ADDR為 0x48

最後就是計算溫度的公式,看手冊,不多說,這裏分零下跟零上,我一般忽略零下的情況(不解釋)


技術分享圖片


好了,傳感器也介紹完了,可以開始撰寫任務函數了

技術分享圖片

函數容易理解,需要註意的是中間那一段是計算溫度值的函數,具體看不懂的可以私信我。

最後主函數裏面初始化總線,創建任務就行了

技術分享圖片


加上必要的調試頭文件以及刪除官方例程多余的東西
技術分享圖片

效果如下,成功讀取到了溫度:victory:

技術分享圖片

enjoy youself~~

結尾附上源碼

/* i2c - Example

   For other examples please check:
   https://github.com/espressif/esp-idf/tree/master/examples

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "driver/i2c.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "sdkconfig.h"

#include "esp_log.h"
#include "esp_spi_flash.h"
#include "esp_system.h"



#define SCL_PIN          19               /*!< gpio number for I2C master clock */
#define SDA_PIN          18               /*!< gpio number for I2C master data  */
#define ESP_SLAVE_ADDR  0x48


#define WRITE_BIT                          I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT                           I2C_MASTER_READ  /*!< 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 */


uint8_t Temp[2];

/**
 * @brief test code to read esp-i2c-slave
 *        We need to fill the buffer of esp slave device, then master can read them out.
 *
 * _______________________________________________________________________________________
 * | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop |
 * --------|--------------------------|----------------------|--------------------|------|
 *
 */
static esp_err_t i2c_read(i2c_port_t i2c_num, uint8_t* data_rd, size_t size)
{
    if (size == 0) {
        return ESP_OK;
    }
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
    if (size > 1) {
        i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
    }
    i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

/**
 * @brief Test code to write esp-i2c-slave
 *        Master device write data to slave(both esp32),
 *        the data will be stored in slave buffer.
 *        We can read them out from slave buffer.
 *
 * ___________________________________________________________________
 * | start | slave_addr + wr_bit + ack | write n bytes + ack  | stop |
 * --------|---------------------------|----------------------|------|
 *
 */
static esp_err_t i2c_write(i2c_port_t i2c_num, uint8_t* data_wr, size_t size)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
    i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}




void LM75a_test(void *pvParameter)
{
    uint16_t Temp_Sum;
    uint8_t n,i,Tem_Reg = 0x00;
    float Temp_ALL;
    char buffer[20];
    
    while(1){    
        i2c_write(I2C_NUM_0, &Tem_Reg, sizeof(Tem_Reg));
        i2c_read(I2C_NUM_0, (uint8_t *)Temp,sizeof(Temp));
       
        Temp_Sum = Temp[0];                   //count  LM75a
        Temp_Sum <<= 8;
        Temp_Sum |= Temp[1];
        Temp_Sum >>= 5;
        Temp_ALL = (float)Temp_Sum * 0.125;
       
        n=sprintf (buffer, "%f",Temp_ALL);
        printf("The temp is: ");
        for(i = 0; i < n; i++)
            printf("%c",buffer[i]);
        printf("  C");
        printf("\n");
        vTaskDelay(1000 / portTICK_PERIOD_MS);

    }
}   



/**
 * @brief i2c master initialization
 */
static void i2c_master_init()
{
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = SDA_PIN;
    conf.scl_io_num = SCL_PIN;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = 100000;
    i2c_param_config(I2C_NUM_0, &conf);

    i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
}




void app_main()
{

    i2c_master_init();
    xTaskCreate(LM75a_test, "LM75a_test", 1024 * 2, NULL, 9, NULL);

}

  



ESP32學習筆記(四)之I2C總線