/*
Blog-Artikel: Schttel-Wrfel mit LED Matrix und Bewegungssimulation
https://techpluscode.de/schuettel-wuerfel-mit-led-matrix-und-bewegungssimulation/
techpluscode.de
Copyright 2019 von Thomas Angielsky
*/
//Bibliothek fr die Ansteuerung der 8x8 LED-Matrix einbinden
//Include lib for the 8x8 LED matrix
#include "LedControl.h"
#include "Wire.h"
//int PinTiltX = 2; //Pin fr Tiltsensor X (if we use Tilt Sensor)
//int PinTiltY = 3; //Pin fr Tiltsensor Y
const int MPU_ADDR = 0x68; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.
int16_t accelerometer_x, accelerometer_y, accelerometer_z; // variables for accelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; // variables for temperature data
char tmp_str[7]; // temporary variable used in convert function
char* convert_int16_to_str(int16_t i) { // converts int16 to string. Moreover, resulting strings will have the same length in the debug monitor.
sprintf(tmp_str, "%6d", i);
return tmp_str;
}
//Pins der LED-Matrix
//Pins of the LED matrix
int PinCLK = 7;
int PinCS = 6;
int PinDIN = 5;
LedControl lc = LedControl(PinDIN, PinCLK, PinCS, 1);
//Koordinaten der Wrfelaugen in der LED-Matrix
//Coordinates of the Dice points in the LED matrix
int DicePic[8][6][2] =
{
{ //leere Matrix und Startposition:
{9,9}, //1. Punkt
{9,8}, //2. Punkt
{9,7}, //3. Punkt
{9,6}, //4. Punkt
{9,5}, //5. Punkt
{9,4} //6. Punkt
},
{ //1:
{4,4}, //1. Punkt
{-1,-1}, //2. Punkt
{-1,-1}, //3. Punkt
{-1,-1}, //4. Punkt
{-1,-1}, //5. Punkt
{-1,-1} //6. Punkt
},
{ //2:
{2,2}, //1. Punkt
{6,6}, //2. Punkt
{-1,-1}, //3. Punkt
{-1,-1}, //4. Punkt
{-1,-1}, //5. Punkt
{-1,-1} //6. Punkt
},
{ //3:
{2,6}, //1. Punkt
{6,2}, //2. Punkt
{4,4}, //3. Punkt
{-1,-1}, //4. Punkt
{-1,-1}, //5. Punkt
{-1,-1} //6. Punkt
},
{ //4:
{2,2}, //1. Punkt
{2,6}, //2. Punkt
{6,2}, //3. Punkt
{6,6}, //4. Punkt
{-1,-1}, //5. Punkt
{-1,-1} //6. Punkt
},
{ //5:
{2,2}, //1. Punkt
{2,6}, //2. Punkt
{6,2}, //3. Punkt
{6,6}, //4. Punkt
{4,4}, //5. Punkt
{-1,-1} //6. Punkt
},
{ //6:
{2,1}, //1. Punkt
{2,4}, //2. Punkt
{2,7}, //3. Punkt
{6,1}, //4. Punkt
{6,4}, //5. Punkt
{6,7} //6. Punkt
},
{ //Start:
{-1,-1}, //1. Punkt
{-1,-1}, //2. Punkt
{-1,-1}, //3. Punkt
{-1,-1}, //4. Punkt
{-1,-1}, //5. Punkt
{-1,-1} //6. Punkt
}
};
//Variablen der Wrfelaugen: Position, Richtung, Geschwindigkeit fr X und Y
//Variables of the dice: position, direction, speed for X and Y
float DiceXpos[6];
float DiceXdir[6];
volatile byte DiceXspeed[6];
float DiceYpos[6];
float DiceYdir[6];
volatile byte DiceYspeed[6];
int DiceValue;
unsigned long timestamp;
byte Mode;
int volatile shakes;
int ShakesPerSecond;
int step;
void InterruptChecks() {
//Schttel-Anzahl zhlen
//Count Shakes
shakes=shakes+1;
//Serial.println(millis());
timestamp=millis();
}
void SetSpeedX() {
if (Mode==0) {
//alle Wrfel in X beschleunigen
//Speed-up dice in X
for (int i = 0; i < 6; i++) {
if (DiceXspeed[i]<255) {DiceXspeed[i]=DiceXspeed[i]+5;}
}
}
InterruptChecks();
}
void SetSpeedY() {
if (Mode==0) {
//alle Wrfel in Y beschleunigen
//Speed-up dice in Y
for (int i = 0; i < 6; i++) {
if (DiceYspeed[i]<255) {DiceYspeed[i]=DiceYspeed[i]+5;}
}
}
InterruptChecks();
}
void ShowLed(int x, int y, bool onoff) {
//LED nur anzeigen, wenn im sichtbaren Bereich
//show only, when x/y in matrix
if ((x<8) and (y<8) and (x>=0) and (y>=0)) {
lc.setLed(0, x, y, onoff);
}
}
void ShowDot(int x, int y, bool onoff) {
//Wrfel-Auge anzeigen oder ausblenden
//Show or hide dice point
ShowLed(x-1, y-1, onoff);
ShowLed(x, y-1, onoff);
ShowLed(x-1, y, onoff);
ShowLed(x, y, onoff);
}
void ShowDicePic(int value) {
//Wurf anzeigen
//Show dice
boolean done;
//alle Punkte von der aktuellen Position aus zur Zielposition von DiceValue bewegen
//move all points from current position to destination of DiceValue
for (int i = 0; i < 6; i++) {
DiceXspeed[i]=100;
DiceYspeed[i]=100;
//Werte fr X berechnen
//Calc x values
DiceXdir[i]=0;
if (int(DiceXpos[i])>DicePic[value][i][0]) {DiceXdir[i]=-1;}
else if (int(DiceXpos[i])<DicePic[value][i][0]) {DiceXdir[i]=1;}
DiceYdir[i]=0;
if (int(DiceYpos[i])>DicePic[value][i][1]) {DiceYdir[i]=-1;}
else if (int(DiceYpos[i])<DicePic[value][i][1]) {DiceYdir[i]=1;}
}
//Serial.println(value);
//Serial.println("Bewegung Start // Start moving");
//Punkte bewegen
do {
//Serial.println("Bewegung // Moving");
for (int i = 0; i < 6; i++) {
if (int(DiceXpos[i])!=DicePic[value][i][0]) {
DoStep(DiceXpos[i],DiceXdir[i],DiceXspeed[i],false);
}
if (int(DiceYpos[i])!=DicePic[value][i][1]) {
DoStep(DiceYpos[i],DiceYdir[i],DiceYspeed[i],false);
}
}
lc.clearDisplay(0);
for (int i = 0; i < 6; i++) {
ShowDot(int(DiceXpos[i]), int(DiceYpos[i]), true);
}
delay(50);
//Sind alle Augen an ihrer Zielposition
//Dice points are on destition position
done=true;
for (int i = 0; i < 6; i++) {
if (int(DiceXpos[i])!=DicePic[value][i][0]) {done=false;}
if (int(DiceYpos[i])!=DicePic[value][i][1]) {done=false;}
}
} while (done==false);
//Serial.println("Bewegung Ende // End moving");
lc.clearDisplay(0);
for (int i = 0; i < 6; i++) {
ShowDot(DicePic[value][i][0],DicePic[value][i][1], true);
}
}
void DoStep(float &pos, float &dir, volatile byte &sp, bool check) {
pos=pos+float(sp)/255*dir;
if (check==true) {
if (pos>7) {
pos=7;
dir=dir*(-1);
}
if (pos<1) {
pos=1;
dir=dir*(-1);
}
}
// Geschwindigkeit wird pro Schritt langsamer
// Velocity decreases every step
if (sp>0) {sp=sp-1;}
}
void MoveDots() {
//alle Wrfel einen Schritt weiter bewegen
//move dice points one step further
for (int i = 0; i < 6; i++) {
//neue Koordinaten berechnen
//calc new coordinates
DoStep(DiceXpos[i],DiceXdir[i],DiceXspeed[i],true);
DoStep(DiceYpos[i],DiceYdir[i],DiceYspeed[i],true);
}
//Wrfel-Augen anzeigen
//show dice points
lc.clearDisplay(0);
for (int i = 0; i < 6; i++) {
ShowDot(int(DiceXpos[i]), int(DiceYpos[i]), true);
}
}
void setup() {
Serial.begin(9600);
Wire.begin();
Wire.beginTransmission(MPU_ADDR); // Begins a transmission to the I2C slave (GY-521 board)
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
//Der MAX7219 ist beim Starten im Power-Saving Modus,
//er muss aufgeweckt werden.
//The MAX7219 is in power-saving mode on startup,
//we have to do a wakeup call
lc.shutdown(0, false);
//Helligkeit auf einen Mittelwert
//Set the brightness to a medium values
lc.setIntensity(0, 8);
//und Display lschen
//and clear the display
lc.clearDisplay(0);
randomSeed(analogRead(0));
DiceValue=0;
for (int i = 0; i < 6; i++) {
DiceXpos[i]=DicePic[7][i][0];
DiceYpos[i]=DicePic[7][i][1];
DiceXdir[i]=random(3)-1;
DiceYdir[i]=random(3)-1;
DiceXspeed[i]=random(126)+120;
DiceYspeed[i]=random(126)+120;
}
//Pins einstellen
//Setup the pins
// pinMode(PinTiltX, INPUT_PULLUP); (for Tilt Sensor)
// pinMode(PinTiltY, INPUT_PULLUP);
// attachInterrupt(digitalPinToInterrupt(PinTiltX),SetSpeedX,CHANGE);
// attachInterrupt(digitalPinToInterrupt(PinTiltY),SetSpeedY,CHANGE);
lc.clearDisplay(0);
timestamp=millis();
Mode=1;
ShowDicePic(6);
delay(1000);
lc.clearDisplay(0);
Mode=0;
Serial.begin(9600);
step=0;
shakes=0;
}
void loop() {
Wire.beginTransmission(MPU_ADDR);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) [MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2, p.40]
Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
Wire.requestFrom(MPU_ADDR, 7*2, true); // request a total of 7*2=14 registers
gyro_z = Wire.read()<<8 | Wire.read();
accelerometer_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
//Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
Serial.println();
delay(1000);
delay(50);
step=step+1;
if (step>20) {
//1 sek ist vorbei
//1 sec is over
step=0;
ShakesPerSecond=shakes;
shakes=0;
}
if(gyro_z>7500||gyro_z<-3000)
{
MoveDots();
if (millis()-timestamp>2000) {
//seit 2 sek kein Schtteln mehr
//there is no shaking since 2 sec
Mode=1;
DiceValue=random(6)+1;
ShowDicePic(DiceValue);
}
if (ShakesPerSecond>5) {
//Es wird wieder geschttelt
//shaking again
Mode=0;
}
}
}
Comments