ESP32 Arduino IIC(使用Wire库驱动ADXL345传感器)

目录

1.IIC总线

1.1 IIC概述

1.2 IIC通信协议

2.Wire类库

2.1 常用函数

2.1.1 begin()

2.1.2 requestFrom( )

2.1.3 beginTransmission( )

2.1.4 endTransmission( )

2.1.5 write( )

2.1.6 read()

3.ADXL345

3.1 数据手册下载

3.2 模块引脚定义

3.3 示例代码

3.3.1 写寄存器

3.3.2 读寄存器

3.3.3 模块初始化

 3.3.4 读取X、Y、Z轴数据

3.3.5 寄存器宏定义

3.3.6 频率及量程枚举

3.3.7 读多次取平均值

3.3.8 计算角度

4.Adafruit_ADXL345驱动库

4.1 特点

 4.2 开始使用


1.IIC总线

1.1 IIC概述

        IIC总线是一个多向控制总线,多个器件(从机)可以同时挂载到一个主机控制的一条总线上,每个连接在总线上的设备都是通过唯一的地址和其他器件通信。

        与串口的一对一通信方式不同,总线通信通常有主机(Master)和从机(Slave)之分。通信时,主机负责启动和终止数据传送,同时还要输出时钟信号;从机会被主机寻址,并且响应主机的通信请求。

主机就是负责整个系统的任务协调与分配,从机一般是通过接收主机的指令从而完成某些特定的任务,主机和从机之间通过总线连接,进行数据通讯。

        串口通信双方需要事先约定同样的波特率才能正常进行通信。而在IIC通信中,通信速率的控制由主机完成,主机会通过SCL引脚输出时钟信号供总线上的所有从机使用。 同时,IIC是一种半双工通信方式,即总线上的设备通过SDA引脚传输通信数据,数据的发送和接收由主机控制,切换进行。

        IIC上的所有通信都是由主机发起的,总线上的设备都应该有各自的地址。主机可以通过这些地址向总线上的任一设备发起连接,从机响应请求并建立连接后,便可进行数据传输。IIC总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输

  • 软件IIC:软件IIC通信指的是用单片机的两个I/O端口模拟出来的IIC,用软件控制管脚状态以模拟IIC通信波形,软件模拟寄存器的工作方式。
  • 硬件IIC:一块硬件电路,硬件IIC对应芯片上的IIC外设,有相应IIC驱动电路,其所使用的IIC管脚也是专用的,硬件(固件)IIC是直接调用内部寄存器进行配置。

硬件IIC的效率要远高于软件的,而软件IIC由于不受管脚限制,接口比较灵活。

1.2 IIC通信协议

物理拓扑结构标题


        IIC总线是由数据线SDA和时钟线SCL以及GND构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbs以上。

  • 时钟线SCL:在通信过程起到控制作用。
  • 数据线SDA:用来一位一位的传送数据。

        通信原理是通过对SCL和SDA线高低电平时序的控制,来产生IIC总线协议所需要的信号,从而进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。

2.Wire类库

对于IIC总线的使用,Arduino IDE自带了一个第三方类库Wire。

2.1 常用函数

2.1.1 begin()

begin()函数有4个重载:

// 如果i2c总线初始化成功,返回true
bool begin(int sda, int scl, uint32_t frequency=0); 
bool begin(uint8_t slaveAddr, int sda, int scl, uint32_t frequency);
// Arduino主流API的显式重载兼容性
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);
}
  • 功能:初始化IIC连接,并作为主机或者从机设备加入IIC总线。
  • 参数:address 一个7位的从机地址。不填,设备将以主机形式加入IIC总线。
  • 参数:sda 数据线对应引脚,不填则默认为8。
  • 参数:scl 时钟线对应引脚,不填则默认为9。
  • 参数:frequency 频率,不填则默认为100,000。
  • 返回值:是否初始化成功。

2.1.2 requestFrom( )

requestFrom()函数有8个重载:

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);
  • 功能:主机向从机发送数据请求信号。使用 requestFrom() 后,从机端可以使用 onRequest() 注册一个事件用以响应主机的请求;主机可以通过available() 和 read() 函数读取这些数据。
  • 参数:address 从机地址。
  • 参数:size 读取数据字节大小。
  • 参数:sendStop 当其值为true时,将发送一个停止信息,释放IIC总线;当为false时,将发送一个重新开始信息,并继续保持IIC总线的有效连接。
  • 返回值:出问题返回0。

2.1.3 beginTransmission( )

void beginTransmission(uint16_t address);
  • 功能:设定传输数据到指定地址的从机设备。随后可以使用 write() 函数发送数据,并搭配endTransmission()函数结束数据传输。
  • 参数:address,要发送的从机的7位地址。
  • 返回值:无。

2.1.4 endTransmission( )

uint8_t endTransmission(bool sendStop);
uint8_t endTransmission(void);
  • 功能:结束数据传输。
  • 参数:stop, boolean型值,当其值为true时将发送一一个停止信息,释放IIC总线,当没有填写stop参数时,等效使用true;当为false时,将发送一个重新开始信息,并继续保持IIC总线的有效连接。
  • 返回值:byte型值,表示本次传输的状态,取值为:0,成功;1,数据过长,超出发送缓冲区;2,在地址发送时接收到NACK信号,3,在数据发送时接收到NACK信号;4,其他错误。

2.1.5 write( )

write()有6个重载:

size_t TwoWire::write(uint8_t data);
size_t TwoWire::write(const uint8_t *data, size_t quantity);
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)
{
    eturn write((uint8_t)n);
}
inline size_t write(int n)
{
    return write((uint8_t)n);
}
  • 功能:当为主机状态时,主机将要发送的数据加入发送队列;当为从机状态时,从机发送数据至发起请求的主机
  • 参数:data    要发送的数据。
  • 参数:length    传输的字节数。
  • 返回值:byte型值,返回输入的字节数。

2.1.6 read()

int read(void);
  • 功能:读取1字节的数据。在主机中,当使用 requestFrom() 函数发送数据请求信号后,需要使用 read() 函数来获取数据;在从机中需要使用该函数读取主机发送来的数据。
  • 参数:无。
  • 返回值:读到的字节数据。

3.ADXL345

3.1 数据手册下载

ADXL345模块中文版数据手册下载

ADXL345模块英文版数据手册下载

3.2 模块引脚定义

ADXL345模块实物图
  • GND:电源地(供电负极)
  • VCC:供电正极
  • CS:片选
  • INT1:中断1
  • INT2:中断2
  • SDO:SPI数据输出/IIC地址设定
  • SDA:SPI数据I/O、IIC数据线(兼容5V电平)
  • SCL:SPI时钟线、IIC时钟线(兼容5V电平)

接线使用GND、VCC、SDA、SCL即可。

3.3 示例代码

初始化后调用读取XYZ轴数据的函数即可。

3.3.1 写寄存器

/**
 * @brief  ADXL345写寄存器
 * @param  addr 寄存器地址
 * @param  val 要写的值
 * @retval None
 */
void ADXL345_write_reg(uint8_t addr, uint8_t val)
{
    Wire.beginTransmission(ADXL345_DEFAULT_ADDRESS);
    Wire.write(addr);
    Wire.write(val);
    Wire.endTransmission(true);
}

3.3.2 读寄存器

/**
 * @brief  ADXL345读寄存器
 * @param  addr 寄存器地址
 * @retval 读取到的寄存器值
 */
uint8_t ADXL345_read_reg(uint8_t addr)
{
    uint8_t temp = 0;

    Wire.beginTransmission(ADXL345_DEFAULT_ADDRESS);
    Wire.write(addr);
    Wire.endTransmission(true);

    Wire.requestFrom(ADXL345_DEFAULT_ADDRESS, 1);
    temp = Wire.read();

    return temp;
}

3.3.3 模块初始化

/**
 * @brief  ADXL345初始化
 * @param  None
 * @retval ID正确返回0,错误返回1
 */
uint8_t adxl345_init(void)
{
  Wire.begin(SDA, SCL);

  // Serial.printf("%x",ADXL345_read_reg(ADXL345_REG_DEVID));
  if (ADXL345_read_reg(ADXL345_REG_DEVID) == 0xE5) // 检测设备ID
  {
    Serial.println("检测到ADXL345芯片!");
    // 低电平中断输出,13位全分辨率,输出数据右对齐,16g量程
    ADXL345_write_reg(ADXL345_REG_DATA_FORMAT, ADXL345_RANGE_16_G);
    // 数据输出速度为100Hz
    ADXL345_write_reg(ADXL345_REG_BW_RATE, ADXL345_DATARATE_100_HZ);
    // 链接使能,测量模式,省电特性
    ADXL345_write_reg(ADXL345_REG_POWER_CTL, 0x08);
    // 不使用中断
    ADXL345_write_reg(ADXL345_REG_INT_ENABLE, 0x80);
    ADXL345_write_reg(ADXL345_REG_OFSX, 0x00);
    ADXL345_write_reg(ADXL345_REG_OFSY, 0x00);
    ADXL345_write_reg(ADXL345_REG_OFSZ, 0x05);
    return 0;
  }
  return 1;
}

 3.3.4 读取X、Y、Z轴数据

/**
 * @brief  ADXL345读取数据
 * @param  None
 * @retval None
 */
void ADXL345_read_data(short *x, short *y, short *z)
{
    uint8_t buf[6];
    uint8_t i;

    Wire.beginTransmission(ADXL345_DEFAULT_ADDRESS);
    Wire.write(ADXL345_REG_DATAX0);
    Wire.endTransmission(true);

    Wire.requestFrom(ADXL345_DEFAULT_ADDRESS, 6);

    for (i = 0; i < 6; i++)
    {
        buf[i] = Wire.read(); // 读取一个字节,不继续再读,发送NACK
    }

    *x = (short)(((uint16_t)buf[1] << 8) + buf[0]); // 合成数据
    *y = (short)(((uint16_t)buf[3] << 8) + buf[2]);
    *z = (short)(((uint16_t)buf[5] << 8) + buf[4]);

}

3.3.5 寄存器宏定义

/*=========================================================================
    I2C ADDRESS/BITS
    -----------------------------------------------------------------------*/
#define ADXL345_DEFAULT_ADDRESS (0x53)  ///< Assumes ALT address pin low
/*=========================================================================*/

/*=========================================================================
    REGISTERS
    -----------------------------------------------------------------------*/
#define ADXL345_REG_DEVID (0x00)        ///< Device ID
#define ADXL345_REG_THRESH_TAP (0x1D)   ///< Tap threshold
#define ADXL345_REG_OFSX (0x1E)         ///< X-axis offset
#define ADXL345_REG_OFSY (0x1F)         ///< Y-axis offset
#define ADXL345_REG_OFSZ (0x20)         ///< Z-axis offset
#define ADXL345_REG_DUR (0x21)          ///< Tap duration
#define ADXL345_REG_LATENT (0x22)       ///< Tap latency
#define ADXL345_REG_WINDOW (0x23)       ///< Tap window
#define ADXL345_REG_THRESH_ACT (0x24)   ///< Activity threshold
#define ADXL345_REG_THRESH_INACT (0x25) ///< Inactivity threshold
#define ADXL345_REG_TIME_INACT (0x26)   ///< Inactivity time
#define ADXL345_REG_ACT_INACT_CTL \
    (0x27)                                ///< Axis enable control for activity and inactivity detection
#define ADXL345_REG_THRESH_FF (0x28)      ///< Free-fall threshold
#define ADXL345_REG_TIME_FF (0x29)        ///< Free-fall time
#define ADXL345_REG_TAP_AXES (0x2A)       ///< Axis control for single/double tap
#define ADXL345_REG_ACT_TAP_STATUS (0x2B) ///< Source for single/double tap
#define ADXL345_REG_BW_RATE (0x2C)        ///< Data rate and power mode control
#define ADXL345_REG_POWER_CTL (0x2D)      ///< Power-saving features control
#define ADXL345_REG_INT_ENABLE (0x2E)     ///< Interrupt enable control
#define ADXL345_REG_INT_MAP (0x2F)        ///< Interrupt mapping control
#define ADXL345_REG_INT_SOURCE (0x30)     ///< Source of interrupts
#define ADXL345_REG_DATA_FORMAT (0x31)    ///< Data format control
#define ADXL345_REG_DATAX0 (0x32)         ///< X-axis data 0
#define ADXL345_REG_DATAX1 (0x33)         ///< X-axis data 1
#define ADXL345_REG_DATAY0 (0x34)         ///< Y-axis data 0
#define ADXL345_REG_DATAY1 (0x35)         ///< Y-axis data 1
#define ADXL345_REG_DATAZ0 (0x36)         ///< Z-axis data 0
#define ADXL345_REG_DATAZ1 (0x37)         ///< Z-axis data 1
#define ADXL345_REG_FIFO_CTL (0x38)       ///< FIFO control
#define ADXL345_REG_FIFO_STATUS (0x39)    ///< FIFO status
/*=========================================================================*/

3.3.6 频率及量程枚举

/**
 * @brief Used with register 0x2C (ADXL345_REG_BW_RATE) to set bandwidth

*/
typedef enum {
  ADXL345_DATARATE_3200_HZ = 0b1111, ///< 1600Hz Bandwidth   140uA IDD
  ADXL345_DATARATE_1600_HZ = 0b1110, ///<  800Hz Bandwidth    90uA IDD
  ADXL345_DATARATE_800_HZ = 0b1101,  ///<  400Hz Bandwidth   140uA IDD
  ADXL345_DATARATE_400_HZ = 0b1100,  ///<  200Hz Bandwidth   140uA IDD
  ADXL345_DATARATE_200_HZ = 0b1011,  ///<  100Hz Bandwidth   140uA IDD
  ADXL345_DATARATE_100_HZ = 0b1010,  ///<   50Hz Bandwidth   140uA IDD
  ADXL345_DATARATE_50_HZ = 0b1001,   ///<   25Hz Bandwidth    90uA IDD
  ADXL345_DATARATE_25_HZ = 0b1000,   ///< 12.5Hz Bandwidth    60uA IDD
  ADXL345_DATARATE_12_5_HZ = 0b0111, ///< 6.25Hz Bandwidth    50uA IDD
  ADXL345_DATARATE_6_25HZ = 0b0110,  ///< 3.13Hz Bandwidth    45uA IDD
  ADXL345_DATARATE_3_13_HZ = 0b0101, ///< 1.56Hz Bandwidth    40uA IDD
  ADXL345_DATARATE_1_56_HZ = 0b0100, ///< 0.78Hz Bandwidth    34uA IDD
  ADXL345_DATARATE_0_78_HZ = 0b0011, ///< 0.39Hz Bandwidth    23uA IDD
  ADXL345_DATARATE_0_39_HZ = 0b0010, ///< 0.20Hz Bandwidth    23uA IDD
  ADXL345_DATARATE_0_20_HZ = 0b0001, ///< 0.10Hz Bandwidth    23uA IDD
  ADXL345_DATARATE_0_10_HZ =
      0b0000 ///< 0.05Hz Bandwidth    23uA IDD (default value)
} dataRate_t;

/**
 * @brief  Used with register 0x31 (ADXL345_REG_DATA_FORMAT) to set g range
 *
 */
typedef enum {
  ADXL345_RANGE_16_G = 0b11, ///< +/- 16g
  ADXL345_RANGE_8_G = 0b10,  ///< +/- 8g
  ADXL345_RANGE_4_G = 0b01,  ///< +/- 4g
  ADXL345_RANGE_2_G = 0b00   ///< +/- 2g (default value)
} range_t;

3.3.7 读多次取平均值

/**
 * @brief  ADXL345连读读取几次取平均值
 * @param  None
 * @retval None
 */
void ADXL345_read_average(short *x, short *y, short *z, uint8_t times)
{
  uint8_t i;
  short tx, ty, tz;
  *x = 0;
  *y = 0;
  *z = 0;
  if (times) // 读取次数不为0
  {
    for (i = 0; i < times; i++) // 连续读取times次
    {
      ADXL345_read_data(&tx, &ty, &tz);
      *x += tx;
      *y += ty;
      *z += tz;
      delay(5);
    }
    *x /= times;
    *y /= times;
    *z /= times;
  }
}

3.3.8 计算角度

/**
 * @brief  ADXL345计算角度
 * @param  None
 * @retval None
 */
void get_angle(float *x_angle, float *y_angle, float *z_angle)
{
  short ax, ay, az;
  ADXL345_read_average(&ax, &ay, &az, 10);
  *x_angle = atan(ax / sqrt((az * az + ay * ay))) * 180 / 3.14;
  *y_angle = atan(ay / sqrt((ax * ax + az * az))) * 180 / 3.14;
  *z_angle = atan(sqrt((ax * ax + ay * ay) / az)) * 180 / 3.14;
}

4.Adafruit_ADXL345驱动库

本文用于学习如何使用Wire库驱动ADXL345模块。

这是一个专为Arduino设计的库,用于与 ADXL345 三轴加速度传感器进行通信。通过使用这款库,您可以轻松地获取传感器的数据,并在您的项目中实现各种有趣的功能。

Adafruit_ADXL345 库提供了易于使用的 API,可以让您在 Arduino 中快速地集成 ADXL345 传感器并处理数据。这个库支持 I2C 和 SPI 两种通信协议,可以根据您的硬件需求选择合适的接口。

4.1 特点

Adafruit_ADXL345 库具有以下特点:

  • 支持 I2C 和 SPI 通信协议
  • 高度封装的 API,简化了与 ADXL345 的交互
  • 可配置传感器的工作模式和范围,满足不同应用场景的需求
  • 提供丰富的示例代码,帮助您快速上手

4.2 开始使用

要开始使用 Adafruit_ADXL345 库,请按照以下步骤操作:

  1. 下载并安装 Arduino IDE(vscode platformIO同理)。
  2. 在 Arduino IDE 的 "Sketch" 菜单中选择 "Include Library" > "Manage Libraries...",然后搜索 "Adafruit_ADXL345" 并安装。
  3. platformIO需搜索安装 "Adafruit Unified Sensor"及"Adafruit Buslo" Library,这是 Adafruit_ADXL345 库的基础框架。Arduino IDE会提醒安装依赖库。
  4. 将 ADXL345 传感器连接到 Arduino 板子,并根据所选通信协议接通 I2C 或 SPI 引脚。
  5. 打开 Arduino IDE 中的一个示例程序(例如 "BasicRead"),修改其中的相关参数并上传至 Arduino 板子。

现在,您已经成功集成了 ADXL345 传感器并开始读取数据!

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ESP32 Arduino中提供了IIC(Inter-Integrated Circuit)接口的支持。IIC是一种串行通信协议,用于在芯片之间进行数据传输。在ESP32上,IIC接口可以作为主机使用。\[3\]你可以使用SPI中的相关函数来进行IIC通信。例如,你可以使用SPI.transfer()函数来发送和接收数据。示例代码如下: ```cpp #include <Wire.h> void setup() { Wire.begin(); // 初始化IIC接口 Serial.begin(115200); } void loop() { Wire.beginTransmission(0x50); // 设置要通信的设备地址 Wire.write(0x01); // 发送要写入的数据 Wire.endTransmission(); // 结束传输 Wire.requestFrom(0x50, 1); // 请求从设备读取数据 if (Wire.available()) { byte data = Wire.read(); // 读取数据 Serial.println(data); // 打印数据 } delay(1000); } ``` 在这个例子中,我们使用Wire来进行IIC通信。首先,我们使用Wire.begin()函数初始化IIC接口。然后,在循环中,我们使用Wire.beginTransmission()函数设置要通信的设备地址,使用Wire.write()函数发送要写入的数据,最后使用Wire.endTransmission()函数结束传输。接着,我们使用Wire.requestFrom()函数请求从设备读取数据,并使用Wire.available()函数检查是否有数据可用。如果有数据可用,我们使用Wire.read()函数读取数据,并使用Serial.println()函数打印数据。最后,我们使用delay()函数延迟一段时间。 这是一个简单的ESP32 Arduino使用IIC接口的示例。你可以根据自己的需求进行修改和扩展。 #### 引用[.reference_title] - *1* *2* [玩转 ESP32 + Arduino (六) 硬件定时器, IIC, SPI](https://blog.csdn.net/finedayforu/article/details/108464949)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [ESP32 Arduino (八) IIc和SPI](https://blog.csdn.net/DOF526570/article/details/128910827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值