Вспомнился мне на днях этот пост про изделие 18\12 на Хабре. Забавно. Из почти что ничего получаем классную игрушку. Решил вот сделать в подарок девушке свою версию, только Spring Sun Edition:)
Забавный контакт в верней части изделия по ссылке явно намекает на отличие символического изображения сердца и сходство его же с иным органом.
Устройство.
Железо подверглось небольшим изменениям. МК поставил ATMEGA8515L. Толстоват он, конечно, просто единственный в закромах родины с достаточным количеством GPIO и напряжением питания нашелся только он. Диодов стало больше. При цене 20 коп. за резистор и 1р за диод, потратив целых 9.60 можно удвоить разрешение. Пробовал в прошивке гасить половину диодов — да, с шестнадцатью смотрится эффектней. Избавился за одно от таймаута включения железно и навсегда — выключателем. Ток через диоды ограничил резисторами на 10 Ом. Навскидку 16 диодов напрямую МК точно не одобрит. К тому же у этой модели ток по питанию ограничен 200мА. Питается все чудо от двух CR2032. 3V для ATMEGA8515L более чем хватит. Два потому, что я не люблю часто менять батарейки, зачем других заставлять?:) А так хватит и одной. Для наглядности схема:
Изделие с обратной стороны:
Прошивка.
Автор прошлого изделия немного удивил какой-то странной инициализацией-переинициализацией. Надеюсь, он возражать не станет, и только обрадуется, что его код не пропал даром и кому-то пригодился. Жаль нет аккаунта, я бы у него поинтересовался с удовольствием, зачем он переключает порты на вход в непрерывном цикле. Про неиспользуемый обработчик прерывания догадываюсь, что он хотел задействовать еще какую-то кнопку (или выводить контроллер из спящего режима, но потом спохватился, что на плате нет кварца и CPU погаснет до следующего включения питания), но торопясь сделал небрежно. В общем эти кляксы не сложно стереть, удалив лишнее и написав инициализацию портов заново.
Так же адаптировал его код 16 диодов, заменил порты, убрал уход в спячку по таймауту и реализовал показ нескольких картинок с интервалом в несколько секунд. Я сделал солнышко, смайлик, сердечко и звезду. Но можно что угодно. Памяти там хоть отбавляй остается, хотя в моем контроллере ОЗУ вдвое меньше, чем по ссылке в начале. Можно хоть целую стробогалерею вшить.
К ноге, моя блоха!
Выводить разъем для перепрошивки — испортить внешний вид. Поэтому поступим по хардкору — подпаяем по 0.2 мм проволочке ко всем нужным ногам корпуса (TQFP44, ага). А потом проволочки присоединим к программатору. Сразу прошу прощения у читателя, настолько увлекся процессом, что забыл сфоткать. Не паять же их туда заново только ради фотки:) Прошло все на удивление гладко. Надо только не забыть вынуть батарейки перед прошивкой и подключть внешнее питание в 5В. Дело в том, что при питании в 3В мой программатор отлично все читает из МК, но вот прошивать туда ничего не хочет. А пользуюсь я каким-то левым, совместимым с Atmel STK-500 монстром. Умеет прошивать и через ISP и через HVP. Второе может спасти, если сильно напутать во фьюзах. Вот он, волшебный:
Принцип действия игрушки. (Для тех, кто еще не догадался)
На удивление прост. Картинка представлена прямоугольником, высотой в 16 (в моей версии) столбцов. С интервалом в 5 мс диоды загораются в соответствии с каждым следующим столбцом. Когда машешь устройством — каждый следующий столбец загорается на новом месте, а из-за инертности глаза все сливается в одну картинку.
Технология.
Плату делал ЛУТом, красил из болончика сперва грунтовкой, затем краской ABRO (фиговая краска, только заборы на могилах красить). По обезжиренной 646 растворителем поверхности. Флюс ФКСп, припой ПОС-61. Отмывал остатки флюса спиртом. Для тех кто не в теме, спирт в аптеках продавать запретили, зато вместо этого теперь продают антибактериальные преператы, на которых сказано: «Состав: спирт этиловый 92,5%». Просто диву даешься в этой стране. Я покупаю «Антисептин».
Название на плате для разнообразия не лудил, а для защиты от почернения покрыл фоторезистом. Мне эта мерзость после покупки лазерного принтера как страшный сон. На защитные покрытия идет) Готовую плату не выкладываю по двум причинам:
1. Все таки моя девушка достойна уникального подарка.
2. Контроллер явно слишком толст, туда можно поставить что-то в несколько раз слабее.
3. И вы должны приложить фантазию, это увлекательнее, чем клонировать проект. Идею описал автор 18\12.
По опыту пришел к тому, что текстолит лучше всего резать ножницами по металу. И ровнее получается и быстрее и проще. Края потом подравниваются напильником. Лобзик с ножовкой по всем параметрам проигрывают.
Список деталей.
1. Текстолит односторонний — 30р;
2. МК ATMEGA8515L — 45р;
3. Резисторы SMD 1206, 10 Ом — 16х20коп;
4. Светодиоды SMD, FYLS-1206SRC — 16×1р;
5. Колодки под CR2032 — 2х15р;
6. Переключатель — 5р.
7. Резисторы SMD 1206, 10 кОм — 20коп;
8. Грунтовка и краска в балончике ~100р за баллон;
9. Конденсаторы 22 пФ SMD 1206 — 2х20коп;
10. Элемент питания CR2032 — 2X20р;
11. Удовольствие от проделанной работы — бесценно.
Доработка и усовершенствования.
1. Подобрать получше краску.
2. Разжиться более подходящим МК.
3. Можно адаптировать игрушку под RGB светодиоды.
4. Купить полиуретановый или акриловый лак. Незащищенные дорожки на плате — плохо.
5. Похимичить с акселерометром. Добиться независимости от скорости и направления взмаха.
Насчет последнего. Не могу никак найти микросхем акселерометров по адекватной цене. Как найду — сразу же возьмусь за изучение.
О, и да, чуть не забыл, оно работает!
Видео весьма плохо передает весь эффект, но принцип понять можно.
Исходный код сего чуда для WinAVR-GCC:
#include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #define LINETIME 5 // Интервал между линиями #define STROBETIME 3 // Время показа каждого строба в срабатываниях таймера :) unsigned char count = 0; unsigned char strobe = 0; #define MAXSTROBE 3 void Init() { // IO PORTS DDRC = 0xFF; PORTC = 0x00; DDRA = 0xFF; PORTA = 0x00; // TC1 (16bit) TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10); TIMSK |= (1 << TOIE1); } void ShowLine (unsigned int line) { PORTC = 0x00; PORTA = 0x00; if(line & _BV(0)) PORTC |= _BV(0); if(line & _BV(1)) PORTC |= _BV(1); if(line & _BV(2)) PORTC |= _BV(2); if(line & _BV(3)) PORTC |= _BV(3); if(line & _BV(4)) PORTC |= _BV(4); if(line & _BV(5)) PORTC |= _BV(5); if(line & _BV(6)) PORTC |= _BV(6); if(line & _BV(7)) PORTC |= _BV(7); if(line & _BV(8)) PORTA |= _BV(7); if(line & _BV(9)) PORTA |= _BV(6); if(line & _BV(10)) PORTA |= _BV(5); if(line & _BV(11)) PORTA |= _BV(4); if(line & _BV(12)) PORTA |= _BV(3); if(line & _BV(13)) PORTA |= _BV(2); if(line & _BV(14)) PORTA |= _BV(1); if(line & _BV(15)) PORTA |= _BV(0); _delay_ms(LINETIME); } int main(void) { Init(); sei(); for (;;) { switch (strobe) { case 0: ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000100000000); ShowLine(0b0000000100000000); ShowLine(0b0100000100000100); ShowLine(0b0010000100001000); ShowLine(0b0001000000010000); ShowLine(0b0000001110000000); ShowLine(0b0000011111000000); ShowLine(0b1111011111101111); ShowLine(0b0000011111000000); ShowLine(0b0000001110000000); ShowLine(0b0001000000010000); ShowLine(0b0010000100001000); ShowLine(0b0100000100000100); ShowLine(0b0000000100000000); ShowLine(0b0000000100000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); break; case 1: ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000001111000000); ShowLine(0b0001111001111000); ShowLine(0b0111000000001110); ShowLine(0b1100000000000011); ShowLine(0b0000000000000000); ShowLine(0b0000000110000000); ShowLine(0b0000000110000000); ShowLine(0b0000000110000000); ShowLine(0b0000000110000000); ShowLine(0b0000000000000000); ShowLine(0b0011100000011100); ShowLine(0b0011100000011100); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); break; case 2: ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000010000000000); ShowLine(0b0000011000000100); ShowLine(0b0000011100001100); ShowLine(0b0000011110111000); ShowLine(0b0000011111110000); ShowLine(0b0001111111110000); ShowLine(0b1111111111100000); ShowLine(0b0001111111110000); ShowLine(0b0000011111111000); ShowLine(0b0000011100111000); ShowLine(0b0000011000001100); ShowLine(0b0000011000000100); ShowLine(0b0000010000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); break; case 3: ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000111100000000); ShowLine(0b0011111111000000); ShowLine(0b1111111111110000); ShowLine(0b0011111111111100); ShowLine(0b0000111111111111); ShowLine(0b0011111111111100); ShowLine(0b1111111111110000); ShowLine(0b0011111111000000); ShowLine(0b0000111100000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); ShowLine(0b0000000000000000); break; } } }; ISR (TIMER1_OVF_vect) { count++; if (count >= STROBETIME) { count = 0; strobe++; if (strobe >= (MAXSTROBE + 1)) strobe = 0; } }
А всех милых дам, читающих этот пост, с первыми днями весны и 8 марта.
0 комментариев на «“Весенняя открытка — стробоскоп”»
Отличный проект! Спасибо!
Присоединяюсь к поздравлениям 🙂