Fundamental:
I2C communication protocol uses two wires to share information. One is used for the clock signal (SCL) and the other is used to send and receive data (SDA).
The ESP32 supports I2C communication through its two I2C bus interfaces that can serve as I2C master or slave, depending on the user’s configuration.
Accordingly to the ESP32 datasheet, the I2C interfaces of the ESP32 supports:
1. Standard mode (100 Kbit/s)
2. Fast mode (400 Kbit/s)
3. Up to 5 MHz, yet constrained by SDA pull-up strength
4. 7-bit/10-bit addressing mode
5. Dual addressing mode. Users can program command registers to control I²C interfaces, so that they have more flexibility
Purpose:
We’ll take a look at the I2C communication protocol with the ESP32 using Arduino IDE 2
This very simple sketch scans the I2C-bus for devices. If a device is found, it is reported to the Arduino serial monitor and to driver mpu6050 of I2C Bus for some information.
MPU6050 introduce:
The MPU-6050 IMU (Inertial Measurement Unit) is a 3-axis accelerometer and 3-axis gyroscope sensor. The accelerometer measures the gravitational acceleration and the gyroscope measures the rotational velocity. Additionally, this module also measures temperature. This sensor is ideal to determine the orientation of a moving object.
Circuit:
MPU6050_library_install:
YouTube Video:
#include <Wire.h>
#include "MPU6050_6Axis_MotionApps20.h"
#include <BluetoothSerial.h>
//--------- Flag structure --------------------------------------
typedef struct _vFlag
{
uint8_t BTFlag = 0;
uint8_t DC_Flag = 0;
uint8_t CANFlag = 0;
uint8_t I2C_Flag = 0;
uint8_t BMP180Flag = 0;
uint8_t MPU6050Flag = 0;
uint8_t JSONFlag = 0;
uint8_t Radar_L_Flag = 0;
uint8_t Radar_R_Flag = 0;
uint8_t sensor_Flag = 0;
uint8_t sensor1_Flag = 0;
uint8_t initial_Flag = 0;
uint8_t Tone_Flag = -1;
uint8_t IR_RECV_Flag=0;
uint8_t IR_SEND_Flag=0;
uint8_t FunctionFlag = 3;
uint8_t SendFlag = 0;
uint8_t BMPCnt = 0;
} vFlag;
vFlag *flag_Ptr;
vFlag flag;
//----- mpu6050 ------------------
//#define OUTPUT_READABLE_QUATERNION
//#define OUTPUT_READABLE_EULER
#define OUTPUT_READABLE_YAWPITCHROLL
//#define OUTPUT_READABLE_REALACCEL
//#define OUTPUT_READABLE_WORLDACCEL
//#define OUTPUT_TEAPOT
#define INTERRUPT_PIN 32
MPU6050 mpu;
BluetoothSerial SerialBT;
// MPU control/status vars
bool dmpReady = false;
uint8_t mpuIntStatus;
uint8_t devStatus;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 gy; // [x, y, z] gyro sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00, '\r', '\n' };
int16_t ax, ay, az;
int16_t gx, gy1, gz;
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
//----------uart--------------
#define LINE_BUFFER_LENGTH 64
//--------- uart structure --------------------------------------
typedef struct _vUart
{
char c;
int lineIndex = 0;
int line1Index = 0;
int BTlineIndex = 0;
bool lineIsComment;
bool lineSemiColon;
//char *line;
char line[128];
//char line1[128];
char BTline[20];
//char R_line[20];
//char L_line[20];
String inputString;
String BTinputString;
String S1inputString;
int V[16];
char ctemp[30];
char I2C_Data[80];
int DC_Spped = 50;
float Voltage[16];
int Buffer[128];
int StartCnt = 0;
int ReadCnt = 0;
int sensorValue = 0;
} vUart;
vUart *Uart_Ptr;
vUart Uart;
//-------------------------------------------------
void setup()
{
Serial.begin(9600);
Serial.println(F("init"));
SerialBT.begin("BT_Node12");// BTName為藍芽廣播名稱
Wire.begin(); //--i2c scanner
//Wire.begin(21 , 22);//SCL DSDA
Wire.setClock(400000); // 400千赫I2C時鐘。如果有編譯困難,請註釋這一行
//-------mpu6050----------------------
mpu.initialize();
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// load and configure the DMP
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(101);
mpu.setYGyroOffset(-15);
mpu.setZGyroOffset(-5);
mpu.setZAccelOffset(1318);
if (devStatus == 0)
{
// Calibration Time: generate offsets and
/**mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
Serial.println();
mpu.PrintActiveOffsets();**/
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
//對應到MPU6050 INIT腳
pinMode(32, INPUT);
//attachInterrupt(32, dmpDataReady, RISING);
//Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
Serial.println(F(")..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
}
else
{
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
}
//-----------------------------------------
void loop()
{
Serial.print(F("Main at core:"));
Serial.println(xPortGetCoreID());
while(1)
{
while (Serial.available() > 0)
{
Uart.c = Serial.read();
if ((Uart.c == '\n') || (Uart.c == '\r'))
{ // End of line reached
if (Uart.lineIndex > 0)
{ // Line is complete. Then execute!
Uart.line[Uart.lineIndex] = '\0'; // Terminate string
//Serial.println( F("Debug") );
//Serial.println( Uart.inputString );
processCommand(Uart.line); // do something with the command
//傳輸給藍芽
Uart.lineIndex = 0;
Uart.inputString = "";
}
else
{
// Empty or comment line. Skip block.
}
Uart.lineIsComment = false;
Uart.lineSemiColon = false;
Serial.println(F("ok>"));
}
else
{
//Serial.println( c );
if ((Uart.lineIsComment) || (Uart.lineSemiColon))
{
if (Uart.c == ')')
Uart.lineIsComment = false; // End of comment. Resume line.
}
else
{
if (Uart.c == '/')
{ // Block delete not supported. Ignore character.
}
else if (Uart.c == '~')
{ // Enable comments flag and ignore all characters until ')' or EOL.
Uart.lineIsComment = true;
}
else if (Uart.c == ';')
{
Uart.lineSemiColon = true;
}
else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
{
Serial.println("ERROR - lineBuffer overflow");
Uart.lineIsComment = false;
Uart.lineSemiColon = false;
}
else if (Uart.c >= 'a' && Uart.c <= 'z')
{ // Upcase lowercase
Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
Uart.lineIndex = Uart.lineIndex + 1;
Uart.inputString += (char)(Uart.c - 'a' + 'A');
}
else
{
Uart.line[Uart.lineIndex] = Uart.c;
Uart.lineIndex = Uart.lineIndex + 1;
Uart.inputString += Uart.c;
}
}
}
} //while (Serial.available() > 0)
while (SerialBT.available())
{
//讀取藍芽資料
String BTdata = SerialBT.readString();
//顯示在序列視窗
Serial.println(BTdata);
//char charBuf[BTdata.length() + 1];
//BTdata.toCharArray(charBuf, BTdata.length());
BTprocessCommand(BTdata); // do something with the command
//processCommand(charBuf); // do something with the command
}//while (BT.available())
if(flag.I2C_Flag == 1)
{
vI2C_0_Task();
}
if(flag.MPU6050Flag == 1)
{
vMPU6050Task();
}
}
}
void BTprocessCommand(String data)
{
}
//----------------------------------------
void processCommand(char *data)
{
int len, xlen, ylen, zlen, alen;
int tempDIO;
String stemp;
len = Uart.inputString.length();
//---------------------------------------
if (strstr(data, "VER") != NULL)
{
Serial.println(F("ESP32_20230710"));
}
//-------------- I2C --------------------
if (strstr(data, "I2C_SCAN") != NULL)
{
flag.I2C_Flag = 1;
Serial.println(F("I2C_SCAN"));
}
if (strstr(data, "I2C_SCAN_OFF")!= NULL)
{
flag.I2C_Flag = 0;
Serial.println(F("I2C_SCAN_OFF"));
}
//
if (strstr(data, "MPU6050_ON")!= NULL)
{
flag.MPU6050Flag = 1;
Serial.println(F("MPU6050_ON"));
}
if (strstr(data, "MPU6050_OFF")!= NULL)
{
flag.MPU6050Flag = 0;
Serial.println(F("MPU6050_OFF"));
}
}
//-----------------------------------------
void vI2C_0_Task()
{
byte count = 0;
Serial.println(F("I2C scanner. Scanning ..."));
for (byte i = 1; i < 127; i++) //---scan address
{
Wire.beginTransmission(i);
if (Wire.endTransmission() == 0)
{
Serial.print("Found_address:" + String(count + 1) + "_");
Serial.print(i, DEC);
Serial.print("_(0x");
Serial.print(i, HEX);
Serial.println(F(")"));
count++;
delay(5);
}
else
{
continue;
}
}
Serial.println(F("Done."));
Serial.print(F("Found: "));
Serial.print(count, DEC);
Serial.println(F(" device(s)."));
flag.I2C_Flag = 0;
}
//-------------------------------------------
void vMPU6050Task()
{
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer))
{ // Get the Latest packet
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
//mpu.getMotion6(&ax, &ay, &az, &gx, &gy1, &gz);
Serial.print("ypr\t");
Serial.print(ypr[0] * 180 / M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180 / M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180 / M_PI);
//Serial.println(ypr[1] * 180/M_PI + 180);
#endif
}
}
沒有留言:
張貼留言