当前位置: 首页 > article >正文

【ESP32】Arduino开发 | I2C控制器+I2C主从收发例程

有关I2C控制器的详细介绍放在了IDF开发的文章中,跳转栏目目录可以找到对应的文章。

1. API

        Arduino启动时就已经实例化了两个I2C设备类,分别对应Wire和Wire1对象。

1.1 初始化

bool begin(int sda, int scl, uint32_t frequency=0); // returns true, if successful init of i2c bus
bool begin(uint8_t slaveAddr, int sda, int scl, uint32_t frequency);
// Explicit Overload for Arduino MainStream API compatibility
inline bool begin()
{
    return begin(-1, -1, static_cast<uint32_t>(0));
}
inline bool begin(uint8_t addr)
{
    return begin(addr, -1, -1, 0);
}
inline bool begin(int addr)
{
    return begin(static_cast<uint8_t>(addr), -1, -1, 0);
}

        初始化函数有好几个重载,最简单的就是什么参数都不传,这样会初始化一个默认的I2C主机,管脚、速率这些都是使用默认的;默认SDA管脚为21,SCL管脚为22;默认速率为100kHz。如果第一个参数填从机地址的话,就可以初始化I2C从机,后面的参数也是传不传都行,不传的话就用默认的。

        但要注意的是,如果使用Wire1的话,是没有默认管脚的,一定要指定

1.2 写数据

size_t write(uint8_t);
size_t write(const uint8_t *, size_t);
inline size_t write(const char * s)
{
    return write((uint8_t*) s, strlen(s));
}
inline size_t write(unsigned long n)
{
    return write((uint8_t)n);
}
inline size_t write(long n)
{
    return write((uint8_t)n);
}
inline size_t write(unsigned int n)
{
    return write((uint8_t)n);
}
inline size_t write(int n)
{
    return write((uint8_t)n);
}

         写数据的函数是主机从机都通用的,也是有很多重载可选,最常见的就是传数组和数组长度;当然,如果发的是字符串的话,就不用传长度了,有对应的重载。因为Wire类是继承Print类的,因此写数据也可以调print、printf、println这类的函数,实现更灵活的编程。

        调用这个函数并不会立刻把数据发送出去,而是拷贝到缓存中,稍后再发送。

1.3 读数据

virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
virtual size_t readBytes(uint8_t *buffer, size_t length)
{
    return readBytes((char *) buffer, length);
}
size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length)
{
    return readBytesUntil(terminator, (char *) buffer, length);
}
virtual String readString();
String readStringUntil(char terminator);

        读数据的函数主要在Stream这个类中,读数组可以调readBytes,传入接收数组和数组长度;如果读字符串可以调readString,程序会一直读,直到字符串的终止符出现为止。

1.4 主机启动发送

void beginTransmission(uint16_t address);
void beginTransmission(uint8_t address);
void beginTransmission(int address);

        传入从机的地址,这个函数主要就是做一个初始化而已。

1.5 主机结束发送

uint8_t endTransmission(bool sendStop);
uint8_t endTransmission(void);

         sendStop参数表示是否发送停止信号。在调用了这个函数之后,主机才会发起真正的I2C通信

1.6 主机请求从机数据

size_t requestFrom(uint16_t address, size_t size, bool sendStop);
uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop);
uint8_t requestFrom(uint16_t address, uint8_t size, uint8_t sendStop);
size_t requestFrom(uint8_t address, size_t len, bool stopBit);
uint8_t requestFrom(uint16_t address, uint8_t size);
uint8_t requestFrom(uint8_t address, uint8_t size, uint8_t sendStop);
uint8_t requestFrom(uint8_t address, uint8_t size);
uint8_t requestFrom(int address, int size, int sendStop);
uint8_t requestFrom(int address, int size);
  • address:从机地址;
  • size:要获取的数据量;
  • sendStop:是否发送停止信号。

1.7 从机注册接收回调

void onReceive( void (*)(int) );

        当从机接收到数据时会调用设置的回调函数,函数的参数为接收到的数据数量。

1.8 从机注册请求回调

void onRequest( void (*)(void) );

        当从机收到了主机的读请求时,会调用设置的回调函数。

2. 例程

        例程中初始化一个I2C主机,SDA管脚为17,SCL管脚为18,速率为400kHz;一个I2C从机,SDA管脚为21,SCL管脚为22,速率为400kHz。主机向从机写一次数据,之后主机再从从机读一次数据,每次间隔1秒。

#include <Arduino.h>
#include <Wire.h>

const char *message = "Hello, World!";

void onRequest()
{
    Wire1.write(message);
    Serial.println("[Slave] Send message");
}

void onReceive(int len)
{
    Serial.printf("[Slave] Receive message: ");
    while (Wire1.available()) {
        Serial.write(Wire1.read());
    }
    Serial.println();
}

void setup()
{
    Serial.begin(115200);
    /* 初始化I2C主机 */
    Wire.begin(17, 18, 400000);
    /* 初始化I2C从机 */
    Wire1.begin(0x58, 21, 22, 400000);
    Wire1.onReceive(onReceive);
    Wire1.onRequest(onRequest);
}

void loop()
{
    /* 主机写从机 */
    Wire.beginTransmission(0x58);
    Wire.write(message);
    Wire.endTransmission(true);
    Serial.println("[Master] Send message");
    delay(1000);

    /* 主机读从机 */
    uint8_t read_len = Wire.requestFrom(0x58, strlen(message));
    if (read_len) {
        uint8_t read_buf[128] = {0};
        Wire.readBytes(read_buf, 128);
        Serial.printf("[Master] Receive message: %s\r\n", read_buf);
    }
    delay(1000);
}

        程序输出log如下:


http://www.kler.cn/news/324353.html

相关文章:

  • 2024华为OD机试E卷-构成正方形的数量-(C++/Java/Python)
  • Redis 实现分布式锁时需要考虑的问题
  • 使用 Frida Hook Android App
  • Linux文件IO(十一)-复制文件描述符与截断文件
  • 大数据复习知识点2
  • Deep Learning for Video Anomaly Detection: A Review 深度学习视频异常检测综述阅读
  • flink设置保存点和恢复保存点
  • 详细分析Mybatis中的动态Sql(附Demo)
  • JWT的基础与使用
  • C/CPP中的编程技巧及其概念
  • 【零散技术】Odoo PDF 打印问题问题合集
  • 《AI办公类工具表格处理系列之二——Excell-AI》
  • C++那些事之变量模版
  • 大厂面试真题-说一下Mybatis的缓存
  • 【分布式微服务云原生】详细介绍下dubbo和springcloud所能支持的微服务特性,为啥能支持的技术原理,以及适用的业务场景,并对两者各方面做个详细的比较
  • Qt/C++ 解决调用国密SM3,SM4加密解密字符串HEX,BASE64格式转换和PKCS5Padding字符串填充相关问题
  • Java线程基础
  • SQL CREATE TABLE 语句
  • TypeScript概念讲解
  • DePIN 代表项目 CESS 受邀出席国会山活动,向议员展示创新 DePIN 技术
  • 阿里rtc云端录制TypeScript版NODE运行
  • HarmonyOS安全能力介绍
  • 240927-各种卷积最清晰易懂blender动画展示
  • Spark 的 Skew Join 详解
  • Spring Boot 2.4.3 + Java 8 升级为 Java 21 + Spring Boot 3.2.0
  • ubuntu 不用每次输入sudo的四种方式
  • 基于python+django+vue的电影数据分析及可视化系统
  • 滚雪球学MySQL[6.1讲]:数据备份与恢复
  • 初始MYSQL数据库(6)—— 事务
  • 什么东西可以当做GC Root,跨代引用如何处理?