ESP32学习笔记之I2C总线

Posted 当然我也在扯淡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ESP32学习笔记之I2C总线相关的知识,希望对你有一定的参考价值。

上一篇帖子我们了解了一下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总线的主要内容,如果未能解决你的问题,请参考以下文章

ESP32学习笔记(17)——I2C接口使用

STM32学习笔记—I2C通信

IIC总线协议——esp32学习笔记

ESP32-C3学习笔记:ESP32 C3 IIC总线驱动光照强度传感器(基于ESP-IDF Eclipse)

ESP3212.I2C LCD1602液晶显示实验(LiquidCrystal_I2C库)

ESP3212.I2C LCD1602液晶显示实验(LiquidCrystal_I2C库)