#include <Wire.h>
#include <MPU6050_tockn.h>
#include <LedControl.h>
MPU6050 mpu(Wire);
// MAX7219: DIN = 11, CLK = 13, CS = 10
LedControl lc = LedControl(11, 13, 10, 2);
const int buzzer = A0;
// 10 minut = 600s = 600000ms
// 64 donaga bo‘lamiz → 9375ms (9.3s) da 1 dona tushadi
unsigned long dropInterval = 9375;
unsigned long lastDrop = 0;
// Qum holati
byte gridTop[8][8];
byte gridBottom[8][8];
void resetSand() {
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
gridTop[y][x] = 1;
gridBottom[y][x] = 0;
}
}
lc.clearDisplay(0);
lc.clearDisplay(1);
lastDrop = millis();
}
void drawMatrix() {
for (int y = 0; y < 8; y++)
for (int x = 0; x < 8; x++)
lc.setLed(0, y, x, gridTop[y][x]);
for (int y = 0; y < 8; y++)
for (int x = 0; x < 8; x++)
lc.setLed(1, y, x, gridBottom[y][x]);
}
// Bitta qum hujayrasi pastga tushadi
void dropSand() {
for (int y = 7; y >= 0; y--) {
for (int x = 0; x < 8; x++) {
if (gridTop[y][x] == 1) {
gridTop[y][x] = 0;
gridBottom[0][x] = 1;
tone(buzzer, 600, 40);
return;
}
}
}
}
// Pastdagi qumni joylashtirish
void settleBottom() {
for (int y = 6; y >= 0; y--) {
for (int x = 0; x < 8; x++) {
if (gridBottom[y][x] == 1 && gridBottom[y + 1][x] == 0) {
gridBottom[y][x] = 0;
gridBottom[y + 1][x] = 1;
}
}
}
}
// MPU orientatsiya aniqlash (Y o‘qi bo‘yicha)
bool isUpsideDown() {
int angleY = mpu.getAngleY();
return angleY > 50; // teskari bo‘lsa TRUE
}
void setup() {
Wire.begin();
mpu.begin();
mpu.calcGyroOffsets(true);
lc.shutdown(0, false);
lc.shutdown(1, false);
lc.setIntensity(0, 5);
lc.setIntensity(1, 5);
pinMode(buzzer, OUTPUT);
resetSand();
drawMatrix();
}
void loop() {
mpu.update();
if (!isUpsideDown()) {
// Qum pastga oqadi
if (millis() - lastDrop >= dropInterval) {
dropSand();
lastDrop = millis();
}
settleBottom();
drawMatrix();
}
else {
// Teskari aylantirilsa → qayta to‘ladi
resetSand();
drawMatrix();
tone(buzzer, 450, 200);
delay(1200);
}
delay(100);
}