LED Sand Clock
A fun project to build an electronic sand clock with ATtiny85 from scratch.
There are 4 direction for the "sand" to fall
It consists of 3 modules:
Display, Control unit and Sensor.
Controls:
Schematics:
Page logic
Display
You can see two 4011C (4x NAND Gate) on the top and CD4040BE (12-Stage Ripple-Carry Binary Counter/Divider) on the right side.
30 LEDs are divided in 3 pages. Pins 1-10 of the binary counter controls the group position. Combination of the pins 11 and 12 controls the page number. 00 - first page, 01 - second and 10 - third.
Sensor
Code:
Global variables:
int resetPin = 1;
int lightOnPin = 2;
int buttonPin = 3; // pin for the change mode button
int sensorPin = A2; // pin for th edirection sensor
int sensorValue = 0; // variable to store the value coming from the sensor
int dotSpeed = 8; // move dot every X loop
int loopCounter = 0; // count every game loop (max 1023 then reset)
int display_mode = 1; // 1-15 number of displayed dots or tests
int cur_number_of_dots = 1;
const byte MAX_NUMBER_OF_DOTS = 30;
unsigned int dots[MAX_NUMBER_OF_DOTS] = { // positions of the dots
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
};
/**
* 1
* 2 4
* 3
*/
unsigned int top_direction;
char compas[5] = "*NESW";
* 1
* 2 4
* 3
*/
unsigned int top_direction;
char compas[5] = "*NESW";
const byte NUMBER_OF_POSITIONS = 30;
unsigned int screenMap[NUMBER_OF_POSITIONS] = {
B00000001+2048,B00000001+1024,B00000010+1024,B00000100+2048,B00000100+1024, // 1, 2, 3, 4, 5
B00000001,B00000010+2048,B00000010,B00000100, // 6, 7, 8, 9
B00001000+2048,B00001000,B00001000+1024, // 10,11,12
B00010000+2048,B00010000+1024, // 13,14
B00010000, // 15
B00100000, // 16
B00100000+2048,B00100000+1024, // 17,18
B01000000+2048,B01000000,B01000000+1024, // 19,20,21
B00000000+512,B00000000+256+2048,B00000000+256,B10000000, // 22,23,24,25
B00000000+512+2048,B00000000+512+1024,B00000000+256+1024,B10000000+2048,B10000000+1024, // 26,27,28,29,30
};
unsigned int position;
How to print the dots:
void sandClockMode() {
int groupA = 0;
int groupB = 0;
int groupC = 0;
for (int i = 0; i < cur_number_of_dots; i++) {
position = dots[i];
if (!(loopCounter % dotSpeed)) {
position = findNewPosWithGravity(position);
}
dots[i] = position;
if (screenMap[position-1] > 2048) {
groupA = groupA | screenMap[position-1];
} else if (screenMap[position-1] > 1024) {
groupB = groupB | screenMap[position-1];
} else {
groupC = groupC | screenMap[position-1];
}
}
printDot(groupA);
printDot(groupB);
printDot(groupC);
}
Sensor code:
int readSensor() {sensorValue = analogRead(sensorPin);// 0 - undefined, 1 - N, 2 - E, 3 - S, 4 - Wif (sensorValue == 0 ) {topDirection = 0;} else if (sensorValue > 900) {topDirection = 3;} else if (sensorValue > 400) {topDirection = 4;} else if (sensorValue > 200) {topDirection = 1;} else {topDirection = 2;}return topDirection;}
How to move dots:
/**
* Find the new position with gravity sensor
* @param int pos
* @return int
*/
int findNewPosWithGravity(int pos) {
dir = getDirection();
if (pos == 1) {
if (dir == 1) {
pos = 6;
} else if (dir == 2) {
if (!isPositionFree(2)) {
pos = 6;
} else {
pos = 2;
}
}
} else if (pos == 2) {
if (dir == 1) {
if (!isPositionFree(10)) {
if (!isPositionFree(6)) {
pos = 7;
} else {
pos = 6;
}
} else {
pos = 10;
}
}
... and so on...
How to check if position is free
/**
* Find out it the given position is free
* @param int pos
* @return bool
*/
bool isPositionFree(int pos) {
for (int i = 0; i < cur_number_of_dots; i++) {
if (dots[i] == pos) {
return false;
}
}
return true;
}
Labels: ATtiny85, Electronic, Fun