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);

}

  

原文地址:https://www.cnblogs.com/SexyBoyHub/p/8946981.html

时间: 2024-07-30 08:18:36

ESP32学习笔记(四)之I2C总线的相关文章

Caliburn.Micro学习笔记(四)----IHandle&lt;T&gt;实现多语言功能

Caliburn.Micro学习笔记(四)----IHandle<T>实现多语言功能 说一下IHandle<T>实现多语言功能 因为Caliburn.Micro是基于MvvM的UI与codebehind分离, binding可以是双向的所以我们想动态的实现多语言切换很是方便今天我做一个小demo给大家提供一个思路 先看一下效果 点击英文  变成英文状态点chinese就会变成中文                          源码的下载地址在文章的最下边 多语言用的是资源文件建

代码管理工具 --- git的学习笔记四《重新整理git(1)》

1.创建版本库 mkdir  创建目录 cd  地址,到该地址下 pwd 显示当前目录 1.创建目录 $ mkdir startGit $ cd startGit $ pwd 显示当前目录 或者cd到桌面,然后再创建目录 2.初始化版本库 $ git init 初始化仓库 提示信息:Initialized empty Git repository in /Users/xingzai/Desktop/startGit/.git/ 建立一个空的git仓库在/Users/xingzai/Desktop

Linux学习笔记四:Linux的文件搜索命令

1.文件搜索命令  which 语法:which [命令名称] 范例:$which ls  列出ls命令所在目录 [[email protected] ~]$ which ls alias ls='ls --color=auto' /bin/ls 另外一个命令:whereis [名称名称],也可以列出命令所在目录. [[email protected] ~]$ whereis ls ls: /bin/ls /usr/share/man/man1/ls.1.gz /usr/share/man/ma

小猪的数据结构学习笔记(四)

小猪的数据结构学习笔记(四) 线性表之静态链表 --转载请注明出处:coder-pig 本章引言: 在二,三中中我们分别学习了顺序表中的线性表与单链表,线性表有点类似于 我们前面所学的数组,而单链表使用的最多的是指针,这里问个简单的问题, 如果是在以前没有指针的话,前辈先人们怎么实现单链表呢?大家思考下! 没有指针,那么用什么来代替呢?前辈先人们非常机智,想出了使用下标+游标的方式 来实现单链表的效果!也就是今天要讲的--静态链表! 当然你也可以直接跳过本章,因为有了单链表就没有必要用静态链表了

Swift学习笔记四:数组和字典

最近一个月都在专心做unity3d的斗地主游戏,从早到晚,最后总算是搞出来了,其中的心酸只有自己知道.最近才有功夫闲下来,还是学习学习之前的老本行--asp.net,现在用.net做项目流行MVC,而不是之前的三层,既然技术在更新,只能不断学习,以适应新的技术潮流! 创建MVC工程 1.打开Visual studio2012,新建MVC4工程 2.选择工程属性,创建MVC工程 3.生成工程的目录 App_Start:启动文件的配置信息,包括很重要的RouteConfig路由注册信息 Conten

NLTK学习笔记(四):自然语言处理的一些算法研究

自然语言处理中算法设计有两大部分:分而治之 和 转化 思想.一个是将大问题简化为小问题,另一个是将问题抽象化,向向已知转化.前者的例子:归并排序:后者的例子:判断相邻元素是否相同(与排序). 这次总结的自然语言中常用的一些基本算法,算是入个门了. 递归 使用递归速度上会受影响,但是便于理解算法深层嵌套对象.而一些函数式编程语言会将尾递归优化为迭代. 如果要计算n个词有多少种组合方式?按照阶乘定义:n! = n*(n-1)*...*1 def func(wordlist): length = le

Android学习笔记四:添加Source

问题描述 Source not foundThe JAR file D:\.....\sdk\platforms\android-20\android.jar has no source attachment. 问题原因及解决办法 1. 使用SDK Manager下载最新版本的Sources for Android SDK 一般文件下载目录默认在SDK下的sources文件中即 \adt-bundle-windows-x86_64-20130522\sdk\sources\android-20

【Unity 3D】学习笔记四十二:粒子特效

粒子特效 粒子特效的原理是将若干粒子无规则的组合在一起,来模拟火焰,爆炸,水滴,雾气等效果.要使用粒子特效首先要创建,在hierarchy视图中点击create--particle system即可 粒子发射器 粒子发射器是用于设定粒子的发射属性,比如说粒子的大小,数量和速度等.在创建完粒子对象后,在右侧inspector视图中便可以看到所有的粒子属性: emit:是否是使用粒子发射器. min size:粒子最小尺寸. max size:粒子最大尺寸. min energy:粒子的最小生命周期

WEB前端学习笔记 四

接上一篇,web学习笔记 四,在此感谢您对此篇笔记的认可,但转发时请注明文章出自网知博学. 2.0  html的语法格式 html的标签要写在尖括号中 :<> 在在英文输入法状态下,按住shift键然后再按它左侧的尖括号就可了, 先学习一个简单的h1标签,是个标题标签,在html中这样写: <h1>我在h1标签中,我就是标题</h1> 那么h1标签中所包裹的文字,就标记成标题了.通过浏览器的解析后在页面上显示出来的效果就是字体加粗,加黑,和word中的标题性质一样! 大

初探swift语言的学习笔记四(类对象,函数)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/29606137 转载请注明出处 假设认为文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! swift扩展了非常多功能和属性,有些也比較奇P.仅仅有慢慢学习,通过经验慢慢总结了. 以下将初步学习一下类的写法. 码工,最大爱好就是看码,而不是文字,太枯燥. // // computer.swift // swiftDemo // // C