#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#define MPU6050_ADDR 0x68
#define MPU6050_REG_SMPLRT_DIV 0x19
#define MPU6050_REG_CONFIG 0x1A
#define MPU6050_REG_GYRO_CONFIG 0x1B
#define MPU6050_REG_ACCEL_CONFIG 0x1C
#define MPU6050_REG_INT_ENABLE 0x38
#define MPU6050_REG_INT_STATUS 0x3A
// Define the interrupt flags
#define MPU6050_INT_DATA_READY 0x01
#define MPU6050_INT_MOTION_DETECT 0x40
#define AXEL_INT 2
#define ROW_DATA 10
#define ROW_CLK 9
#define COL_DATA 6
#define COL_CLK 7
#define RST 5
#define DATA_LATCH 4
#define OUTPUT_EN 8
#define LED_ROW_CNT 8
#define LED_COL_CNT 8
#define ANIMATION_DELAY 20
bool inverted = false;
LiquidCrystal_I2C lcd(0x27, 20, 4);
int16_t accel_x, accel_y, accel_z;
int16_t gyro_x, gyro_y, gyro_z;
const unsigned char LED_DATA[LED_ROW_CNT][LED_COL_CNT] = {
/****************Outer Squares******************/
{0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff},
{0x00, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x00},
{0x00, 0x00, 0x3c, 0x24, 0x24, 0x3c, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00},
/****************Outer Squares******************/
/****************Outer Squares inverse**********/
{0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x3c, 0x24, 0x24, 0x3c, 0x00, 0x00},
{0x00, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x00},
{0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff}
/****************Outer Squares inverse**********/
/****************Diagonals**********************/
// {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01},
// {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80},
/****************Diagonals**********************/
/********************CROSS**********************/
// {0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18},
/********************CROSS**********************/
/***********DIAGONAL CROSS**********************/
// {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81},
/***********DIAGONAL CROSS**********************/
/**********************A************************/
// {0x3c, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42},
/**********************A************************/
/**********************B************************/
// {0x7c, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c},
/**********************B************************/
/**********************c************************/
// {0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3c},
/**********************c************************/
/**********************D************************/
// {0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c},
/**********************D************************/
/**********************E************************/
// {0x7c, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x7c},
/**********************E************************/
/**********************F************************/
// {0x7c, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40}
/**********************F************************/
};
/*
const unsigned char PACMAN[2][LED_COL_CNT] = {
{0x3c, 0x7e, 0xde, 0xfe, 0xfe, 0xfe, 0x7e, 0x3c},
{0x3c, 0x7e, 0xdc, 0xf8, 0xf0, 0xf8, 0x7c, 0x3c}
};
*/
const unsigned char LED_COL[LED_COL_CNT] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe};
void mpu6050_interrupt() {
// Read the interrupt status register to determine which interrupt occurred
uint8_t int_status = readRegister(MPU6050_ADDR, MPU6050_REG_INT_STATUS);
// Check if the data-ready interrupt occurred
if (int_status & MPU6050_INT_DATA_READY) {
// Read the accelerometer and gyroscope data
accel_x = readSensor(MPU6050_ADDR, 0x3B);
accel_y = readSensor(MPU6050_ADDR, 0x3D);
accel_z = readSensor(MPU6050_ADDR, 0x3F);
gyro_x = readSensor(MPU6050_ADDR, 0x43);
gyro_y = readSensor(MPU6050_ADDR, 0x45);
gyro_z = readSensor(MPU6050_ADDR, 0x47);
lcd.print("DATA READY");
}
// Check if the motion-detect interrupt occurred
if (int_status & MPU6050_INT_MOTION_DETECT) {
lcd.print("MOTION DETECT");
}
}
void Pulse(const int pinN)
{
digitalWrite(pinN, LOW);
delayMicroseconds(1);
digitalWrite(pinN, HIGH);
delayMicroseconds(1);
}
void initializeMPU6050() {
// Initialize the MPU6050
writeRegister(MPU6050_ADDR, MPU6050_REG_SMPLRT_DIV, 0x07); // Set sample rate divider to 7 (1kHz / (7+1) = 125Hz)
writeRegister(MPU6050_ADDR, MPU6050_REG_CONFIG, 0x06); // Set low-pass filter to 5Hz
writeRegister(MPU6050_ADDR, MPU6050_REG_GYRO_CONFIG, 0x18); // Set full-scale range to +/-2000 degrees/sec
writeRegister(MPU6050_ADDR, MPU6050_REG_ACCEL_CONFIG, 0x01); // Set full-scale range to +/- 2g
writeRegister(MPU6050_ADDR, MPU6050_REG_INT_ENABLE, MPU6050_INT_DATA_READY | MPU6050_INT_MOTION_DETECT); // Enable data-ready and motion-detect interrupts
}
void writeRegister(uint8_t address, uint8_t reg, uint8_t value) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission(true);
}
This function writes a byte value to a register at a given I2C address on the bus. The Wire.beginTransmission() function starts communication with the specified I2C device at the given address. The Wire.write() function sends the register address followed by the value to be written. Finally, the Wire.endTransmission() function ends the transmission and releases the I2C bus. The true argument passed to endTransmission() causes a stop condition to be sent on the bus, signaling the end of the transmission.
Todor Petrov
readRegister too
Sure, here's the readRegister function:
C++
uint8_t readRegister(uint8_t address, uint8_t reg) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(address, (uint8_t)1, true);
return Wire.read();
}
This function reads a byte value from a register at a given I2C address on the bus. The Wire.beginTransmission() function starts communication with the specified I2C device at the given address. The Wire.write() function sends the register address to be read. The Wire.endTransmission(false) function ends the transmission without releasing the bus, so that the device can be immediately read from.
The Wire.requestFrom() function requests a certain number of bytes from the device at the given address, which is followed by the number of bytes requested and a boolean value true to indicate a stop condition. The function then returns the value of the byte that was read from the device.
Todor Petrov
readSensor too
Sure, here's the readSensor function:
C++
void readSensor(int16_t *ax, int16_t *ay, int16_t *az, int16_t *gx, int16_t *gy, int16_t *gz) {
Wire.beginTransmission(MPU6050_ADDRESS);
Wire.write(ACCEL_XOUT_H);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_ADDRESS, (uint8_t)14, true);
*ax = ((int16_t)Wire.read() << 8) | Wire.read();
*ay = ((int16_t)Wire.read() << 8) | Wire.read();
*az = ((int16_t)Wire.read() << 8) | Wire.read();
Wire.read(); // Discard temperature data
Wire.read();
Wire.read();
*gx = ((int16_t)Wire.read() << 8) | Wire.read();
*gy = ((int16_t)Wire.read() << 8) | Wire.read();
*gz = ((int16_t)Wire.read() << 8) | Wire.read();
}
This function reads the raw sensor data from the MPU6050. It starts by sending the address of the first accelerometer register to be read using Wire.write(ACCEL_XOUT_H). The Wire.endTransmission(false) function is used again to avoid releasing the I2C bus so that the device can be immediately read from.
Next, the function requests 14 bytes of data from the device using Wire.requestFrom(). This includes the accelerometer and gyro data for all three axes, but excludes the temperature data.
Finally, the function uses bitwise operations to combine the high and low bytes of each sensor data value into a signed 16-bit integer. The resulting values are stored in the ax, ay, az, gx, gy, and gz variables passed as pointers to the function.
Todor Petrov
can you show me readSensor function from mpu6050_interrupt()
Sure, here's an example of how you could use the readSensor function inside the mpu6050_interrupt function to read the sensor data when the interrupt is triggered:
C++
void mpu6050_interrupt() {
int16_t ax, ay, az, gx, gy, gz;
readSensor(&ax, &ay, &az, &gx, &gy, &gz);
// do something with the sensor data here
}
In this example, the readSensor function is called inside the mpu6050_interrupt function, and the resulting accelerometer and gyro data is stored in the ax, ay, az, gx, gy, and gz variables. You can then use these values to perform any calculations or actions you need to based on the sensor data.
Todor Petrov
can you show me readSensor function from mpu6050_interrupt() with this prototype accel_x = readSensor(MPU6050_ADDR, 0x3B);
Sure! Here's an example of how you could modify the readSensor function to return individual sensor readings, based on the provided register addresses:
c
#include <Wire.h>
#define MPU6050_ADDR 0x68
void writeRegister(uint8_t reg, uint8_t val) {
Wire.beginTransmission(MPU6050_ADDR);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
uint8_t readRegister(uint8_t reg) {
Wire.beginTransmission(MPU6050_ADDR);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_ADDR, 1);
if (Wire.available()) {
return Wire.read();
}
return 0;
}
int16_t readSensor(uint8_t addr, uint8_t regH, uint8_t regL) {
uint8_t high = readRegister(regH);
uint8_t low = readRegister(regL);
int16_t value = (high << 8) | low;
return value;
}
int16_t readSensor(uint8_t addr, uint8_t reg) {
return readSensor(addr, reg, reg + 1);
}
With this modified readSensor function, you can call it with the MPU6050_ADDR and the register address of the sensor reading you want to get. For example, to read the X-axis accelerometer reading, you can call readSensor(MPU6050_ADDR, 0x3B):
C++
void mpu6050_interrupt() {
int16_t accel_x = readSensor(MPU6050_ADDR, 0x3B);
// do something with the accelerometer reading here
}
In this example, the readSensor function is called inside the mpu6050_interrupt function to read the X-axis accelerometer reading from register address 0x3B, and the resulting value is stored in the accel_x variable. You can then use this value to perform any calculations or actions you need to based on the sensor data.
void writeRegister(uint8_t reg, uint8_t val) {
Wire.beginTransmission(MPU6050_ADDR);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
uint8_t readRegister(uint8_t address, uint8_t reg) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(address, (uint8_t)1, true);
return Wire.read();
}
uint8_t readRegister(uint8_t reg) {
Wire.beginTransmission(MPU6050_ADDR);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_ADDR, 1);
if (Wire.available()) {
return Wire.read();
}
return 0;
}
int16_t readSensor(uint8_t addr, uint8_t regH, uint8_t regL) {
uint8_t high = readRegister(regH);
uint8_t low = readRegister(regL);
int16_t value = (high << 8) | low;
return value;
}
int16_t readSensor(uint8_t addr, uint8_t reg) {
return readSensor(addr, reg, reg + 1);
}
void setup() {
pinMode(ROW_DATA, OUTPUT);
pinMode(ROW_CLK, OUTPUT);
pinMode(COL_DATA, OUTPUT);
pinMode(COL_CLK, OUTPUT);
pinMode(RST, OUTPUT);
pinMode(DATA_LATCH, OUTPUT);
pinMode(OUTPUT_EN, OUTPUT);
digitalWrite(ROW_DATA, HIGH);
digitalWrite(ROW_CLK, HIGH);
digitalWrite(COL_DATA, HIGH);
digitalWrite(COL_CLK, HIGH);
digitalWrite(RST, HIGH);
digitalWrite(DATA_LATCH, HIGH);
digitalWrite(OUTPUT_EN, LOW);
lcd.init();
lcd.backlight();
lcd.setCursor(1, 0);
Wire.begin(); // Start I2C communication
pinMode(AXEL_INT, INPUT_PULLUP); // Set interrupt pin as input with pull-up resistor
digitalWrite(AXEL_INT, HIGH);
initializeMPU6050();
attachInterrupt(digitalPinToInterrupt(MPU6050_INT_PIN), mpu6050_interrupt, FALLING);
lcd.print("MCU6050");
}
void loop() {
while(1)
{
for(int i = 0; i < LED_ROW_CNT; i++)
{
int s = ANIMATION_DELAY;
do{
for(int j = 0; j < LED_COL_CNT; j++)
{
//if(!inverted)
shiftOut(ROW_DATA, ROW_CLK, LSBFIRST, LED_DATA[i][j]);
//else
// shiftOut(ROW_DATA, ROW_CLK, LSBFIRST, ~LED_DATA[i][j]);
shiftOut(COL_DATA, COL_CLK, LSBFIRST, LED_COL[j]);
Pulse(DATA_LATCH);
}
s--;
}while(s > 0);
Pulse(RST);
Pulse(DATA_LATCH);
delay(125);
}
//inverted = !inverted;
}
/*
//PACKMAN
for(int i = 0; i < 2; i++)
{
int s = ANIMATION_DELAY;
do{
for(int j = 0; j < LED_COL_CNT; j++)
{
shiftOut(ROW_DATA, ROW_CLK, LSBFIRST, PACMAN[i][j]);
shiftOut(COL_DATA, COL_CLK, LSBFIRST, LED_COL[j]);
Pulse(DATA_LATCH);
}
s--;
}while(s > 0);
Pulse(RST);
Pulse(DATA_LATCH);
delay(150);
}
*/
}