- Цена: 53,23р.
Недавно снова ударился в настольные игры, но столкнулся с такой проблемой, что маленькие кубики из лап больших дядек норовят улететь куда угодно помимо стола. Поэтому родилась идея сделать электронный вариант, но в классическом «семидырочном» исполнении.
Сделать решено было 2 кубика параллельно (чего уж размениваться?). Чтобы «дрыгать» 14-ю светодиодами, использовал 74HC595. За мозги взял ATtiny13A, его возможностей хватит за глаза. Светодиоды использовал недавно полученные прозрачные красные, они имеют яркое направленное свечение.
Схему накидал на листочке, потом перенес в старый добрый Sprint-Layout
Далее классика: ФЛУТ, лужение «жидким оловом» от Rexant (очень уж удобно), пайка, цапон-лак в 3 слоя.
Для прошивки Тиньки были выведены пины вокруг неё. Далее подключил UNO как программатор, запустил Arduino IDE и стал осваивать программную часть.
Прошивка получилась коротенькая, без использования индусского shiftOut занимает всего 50% от 1К памяти. Разумеется используется псевдо-рандом, берущий значения от тактов МК, но для генерации случайного числа этого вполне достаточно. При прошивке, сразу после компиляции, надо на UNO нажимать reset, иначе выдается ошибка.
Код с комментариями, может кому-то пригодится:
#include <avr/io.h>
#include <util/delay.h>
#define latchPin 1//8
#define clockPin 2//12
#define dataPin 0//11
char tik=0,tik2=3; //счётчик для генератора случайных чисел
#define RAND_MAX 5 //максимальное число
word myArr1[] = {0b0000000010000000,0b0000000000000010,0b1000000000000000,0b0000001000000000,0b0000010000000000,0b0100000000000000,0b0000000000000100,0b0000000001000000}; // массив для бегущей точки
byte dice[] = {0b00010000,0b10000100,0b10010100,0b11000110,0b11010110,0b11101110};
unsigned char display[2];
void write_display(unsigned char *data, unsigned char nbytes)
{
unsigned char mask,i;
for(i = 0; i < nbytes; i++)
{
mask = 0x80;
for(char k = 0; k < 8; k++)
{
// Сравниваем каждый бит с единицей
if(data[i] & mask)
{
PORTB |= (1 << PB0); // DATA 1
PORTB |= (1 << PB2); // CLK 1
PORTB &= ~(1 << PB2); // CLK 0
}
else
{
PORTB &= ~(1 << PB0); // DATA 0
PORTB |= (1 << PB2); // CLK 1
PORTB &= ~(1 << PB2); // CLK 0
}
mask = mask >> 1; // Сдвигаем биты
}
}
// Защелкиваем регистр
PORTB |= (1 << PB1);
PORTB &= ~(1 << PB1);
}
int main( void )
{
DDRB |= (1<<latchPin);
DDRB |= (1<<clockPin);
DDRB |= (1<<dataPin);
DDRB &= ~(1<<4);
display[0] = dice[0];
display[1] = dice[0];
write_display(display,2);
while(1)
{
tik++; //таймер для настройки генератора случайных чисел.
if(tik>RAND_MAX){tik=0;}
tik2—;
if(tik2<0){tik2=RAND_MAX;}
for (byte i=RAND_MAX; i>tik; i—){
tik2—;
if(tik2<0){tik2=RAND_MAX;}
}
if(!(PINB&(1<<4))) //Если нажата, то…
{
_delay_ms(100); //задержка для защиты от дребезга
while(!(PINB&(1<<4))); //Ждем, когда отпустят кнопку
for (byte i=0; i<8;i++){
display[0] = myArr1[i]>>8;
display[1] = myArr1[i];
write_display(display,2);
_delay_ms(100);
}
display[0] = dice[tik];
display[1] = dice[tik2];
write_display(display,2);
_delay_ms(100);
}}}
Переключатель оказался пока никак не задействован (планировал сделать 1d6/2d6), возможно в будущем придумаю какую-нибудь функцию и для него, как и еще для одной свободной ноги.
Собрал всё в любимой мной распаячной коробке, размер подошел отлично, даже не пришлось плату крепить на стойки (зажимается и держится коробочным саморезом). В корпусе тоже не стал делать отверстий, через него диоды смотрятся гораздо лучше и кнопка срабатывает нажатием на корпус. С автономным питанием не стал заморачиваться, вывел mini-USB, а дальше хош — от розетки, хош — от банки силы.
Кнопку в будущем можно повесить сенсорную, однако тут переделывать уже смысла не было.
Вот как это выглядит (получилось размыто, но суть понятна):
В планах перевести проект на SMD, тиньку в SOP8-корпусе. Не знаю как всё это буду паять, но всё уже заказано 🙂 А вместо кучи резисторов использовать 9-пиновую DIP-«гребенку».