Blog the XELFAER

Заметки *NIX

Светодиодное сердце на Atmega8 —

В сети достаточно много есть вариантов исполнения светодиодного сердца выполненного на основе микроконтроллеров, вот и я решил поделиться своей реализацией. Долго не доходили руки для написания статьи, то времени не хватает, то еще что то, но все же кому то точно пригодится даже если не сегодня, то в скором будущем.

С какой собственно целью делался данный проект: было преддверие 14 февраля и хотелось любимого человека поздравить чем-то таким необычным, сделанным своими руками, подарок в который при изготовлении вкладываешь часть себя. Можно было спокойно купить подарок, было бы даже с точки зрения финансов дешевле, но я считаю что истинен подарок тот который ты делаешь сам.

Чертежей не каких не было, все делалось по ходу работы, проблемы возникающие в процессе решались в ходе работы.
Просто подарить светящуюся платку конечно вариант, но не в моем случае. За основу была взята шкатулка из фанеры:
box
Так как в моих условия проживания и за неимением необходимых инструментов — шкатулку я заказал в магазине.
Для придания более благородного вида для неблагородной породы древесины из которого изготовлена шкатулка было решено использовать морилку. Честно признаюсь, не когда до этого не работал с ними, обычно дело ограничивалось использованием олифы. После поисков выбор остановил на спиртовой морилке под красное дерево Химэкспресс. Так как на тот момент были не благоприятные погодные условия, ее пришлось заказать в соседнем городе в магазине. Далее необходимо было подобрать лак, который нормально ляжет на дерево после использования морилки. После изучения данного вопроса в сети, выбор пал на мебельный лак НЦ-218.
Вроде бы для декорирования все есть и можно начинать обработку поверхности. После вскрытия морилкой поверхности шкатулки первым слоем, она почему то легла не сильно равномерно, я имел место немного сглупить и вскрыть ее второй раз, и тут меня ожидал «приятный» сюрприз — цвет превратился не под красное дерево, а уже больше напоминающее черное дерево. Уже позже выяснилось, что морилку можно было разбавить, но уже было поздно. Далее началось вскрытие лаком… Сразу оговорюсь почему выбрана связка спиртовая морилка+нитроцеллюлозный лак — время сушки изделия после обработки, так как все упиралось в сроки. Вскрывать нитролаком изделие еще то извращение занимательное занятие, лак при нанесении очень быстро сохнет и при его нанесении главное покрывать равномерно поверхность и не оставлять разводов ибо потом их будет не скрыть. Как опять же потом выяснилось, что можно было разбавить лак до рабочей вязкости разбавителем РМЛ или растворителем марки 646. Так как лак был густой, то нанесение его тампоном было очень тяжелым, поэтому наносил широкой кистью, а кромки — тонкой кисточкой для рисования. Все шкатулка покрывалась 6-ю слоями лака в 12 заходов так как необходимо было ее как то держать и покрывать равномерно все части. В данном случае если сравнивать — то использование лака на масляной основе проще и удобней по сравнению с нитролаком, так как масляный лак позволяет исправить подтеки, не равномерность нанесения, не такой едкий запах. Минус его использования — долго сохнет. После вскрытия лаком понял еще одну свою ошибку: необходимо было снять петли шкатулки перед вскрытием, но так как уже поезд уехал — пришлось их скручивать и отмывать от лака после вскрытия.

Теперь приступим к электронной начинке. Для этого потребуется:
1) Микроконтроллер ATmega8;
2) 22 SMD светодиода красных;
3) 22 SMD резистора 620 Ом;
4) 1 SMD резистор 10 кОм;
5) 1 SMD конденсатор 0.1 мкФ.
где: микроконтроллер ATmega8 необходим в корпусе TQFP, а все SMD детали типоразмера 0805.

Все разводилось изначально в программе Sprint Layout 5, а позже добавлена разводка выполненная в EagleCAD 6.6.0. Вот собственно как получилась разведенная плата в Sprint Layout:
113x72_heart_layout

и плата в EagleCAD:
heart_eaglecad

Так как размеры платы делались под размеры шкатулки, то по сторонам платы осталось свободное место, которое можно занять чем-нибудь полезным. Для более эстетичного вида добавим рисунки и надписи. Я выбрал любимые цветы своей второй половинки.
Так как нам необходимо добавить рисунки и надписи необходимо сделать шаблон в любом графическом редакторе.
Я делал 2 шаблона: один — непосредственно сама плата, а второй — надписи и рисунки. Вот так выглядит второй шаблон:
113x72_heart_text_image

В конечном варианте должно получится так:
113x72_heart_finish

Плата делалась методом пленочного фоторезиста, поэтому засветка фоторезиста производилась в 2 захода каждым шаблоном по очереди.
Запаивал я все обычным паяльником так как фена увы нет. На плате выведены контакты для программирования микроконтроллера, в которые подпаиваются провода. После программирования их соответственно выпаиваем, так как они больше нам не понадобятся.
Для питания всей схемы был задействован аккумулятор от телефона емкостью 1500 mAh и напряжением 3,7V(LGIP-400N). Можно было бы использовать и батарейку CR2032, но в моем случае пришлось отказаться от этого варианта, так как планировалось плату вклеить в корпус шкатулки и данной батарейки не хватило бы на длительный срок работы, а аккумулятор можно будет подзарядить той же универсальной зарядкой типа «Лягушка».
Самый интересный момент наступил, когда дело дошло до реализации запуска схемы при открытии шкатулки. Для этого требуется кнопка на размыкание, которую я только где не искал на радиорынках и в сети, но либо они были слишком большими по размерам либо только с фиксацией положения. Кнопку найти не удалось подходящую, поэтому пришлось переходить к другому варианту — использовать геркон. С ним стало легче, но не намного: цены на него немалые да и габариты оставляют желать лучшего, при этом геркон требуется то на размыкание. После долгих блужданий оный все-таки был найден. Для его установки был выбран глубокий паз в верхней крышке шкатулки с помощью бора бормашины. Для теста он был закреплен на бесцветный цапонлак. Магнит для размыкания геркона был куплен неодимовый, цилиндрической формы, подходящий по диаметру. Для крепления магнита было высверлено отверстие чуть меньше чем диаметр магнита, после чего отверстие было подогнано ровно по диаметру магнита и посажено на суперклей. Стоит сказать почему геркон был временно прикреплен на цапонлак: так как он работает за счет того что у него под действием магнита отгибается пластинка, то его необходимо было правильно выставить после установки магнита. После проверки место посадки геркона было залито бесцветным лаком, которым вскрывалась шкатулка.
reed_contact

Теперь осталось придать законченный вид внутренней части шкатулки. Для этого было решено ее обклеить тканью. Ткань была выбрана темного красного цвета — бархат. Обклеить ею оказалось не так просто так как она тонкая и при обрезке не получается ровный срез. После поиска информации в сети был найден вариант: сделаны картонные заготовки и непосредственно на них наклеена ткань, после чего все уже обклеенные части были приклеены к самой шкатулке.
box_bottom

Теперь можно приступить к написанию прошивки для микроконтроллера. Прошивка делалась на скорую руку и код ее оставляет желать лучшего. Выбор эффектов которые будут отображаться это дело творческое и ограничивается только фантазией разработчика и памятью самого микроконтроллера. Я реализовал те которые мне пришлись собственно по душе. Вот собственно код самой прошивки:

#include <avr/io.h>
#include <util/delay.h>

//включить все светодиоды
void full_leds_on()
{
        PORTD |= _BV(PD4);
        PORTB |= _BV(PB6);
        PORTD |= _BV(PD3);     
        PORTB |= _BV(PB7);
        PORTD |= _BV(PD2);
        PORTD |= _BV(PD5);
        PORTD |= _BV(PD1);
        PORTD |= _BV(PD6);
        PORTD |= _BV(PD0);
        PORTD |= _BV(PD7);
        PORTC |= _BV(PC5);
        PORTB |= _BV(PB0);
        PORTC |= _BV(PC4);
        PORTB |= _BV(PB1);
        PORTC |= _BV(PC3);
        PORTB |= _BV(PB2);
        PORTC |= _BV(PC2);
        PORTB |= _BV(PB3);
        PORTC |= _BV(PC1);
        PORTB |= _BV(PB4);
        PORTC |= _BV(PC0);
        PORTB |= _BV(PB5);
}

//выключить все светодиоды
void full_leds_off()
{
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB6);
        PORTD &= ~_BV(PD3);
        PORTB &= ~_BV(PB7);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD5);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD6);
        PORTD &= ~_BV(PD0);
        PORTD &= ~_BV(PD7);
        PORTC &= ~_BV(PC5);
        PORTB &= ~_BV(PB0);
        PORTC &= ~_BV(PC4);
        PORTB &= ~_BV(PB1);
        PORTC &= ~_BV(PC3);
        PORTB &= ~_BV(PB2);
        PORTC &= ~_BV(PC2);
        PORTB &= ~_BV(PB3);
        PORTC &= ~_BV(PC1);
        PORTB &= ~_BV(PB4);
        PORTC &= ~_BV(PC0);
        PORTB &= ~_BV(PB5);
}

//равномерное заполнение от верха к низу
void heart_one()
{
        PORTD |= _BV(PD4);
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTD |= _BV(PD3);     
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD |= _BV(PD2);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD |= _BV(PD1);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD |= _BV(PD0);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTC |= _BV(PC5);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTC |= _BV(PC4);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTC |= _BV(PC3);
        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTC |= _BV(PC2);
        PORTB |= _BV(PB3);
        _delay_ms(50);
        PORTC |= _BV(PC1);
        PORTB |= _BV(PB4);
        _delay_ms(50);
        PORTC |= _BV(PC0);
        PORTB |= _BV(PB5);
}

//равномерное заполнение от низа к верху
void heart_two()
{
        PORTC |= _BV(PC0);
        _delay_ms(50);
        PORTC |= _BV(PC1);
        PORTB |= _BV(PB5);
        _delay_ms(50);
        PORTC |= _BV(PC2);
        PORTB |= _BV(PB4);
        _delay_ms(50);
        PORTC |= _BV(PC3);
        PORTB |= _BV(PB3);
        _delay_ms(50);
        PORTC |= _BV(PC4);
        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTC |= _BV(PC5);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTB |= _BV(PB6);
        _delay_ms(50); 
}

//бегущий огонь по кругу по часовой стрелке
void heart_three()
{
        PORTD |= _BV(PD4);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        _delay_ms(50);
        PORTC &= ~_BV(PC5);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        _delay_ms(50);
        PORTC &= ~_BV(PC4);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        _delay_ms(50);
        PORTC &= ~_BV(PC3);
        _delay_ms(50);

        PORTC |= _BV(PC2);
        _delay_ms(50);
        PORTC &= ~_BV(PC2);
        _delay_ms(50);

        PORTC |= _BV(PC1);
        _delay_ms(50);
        PORTC &= ~_BV(PC1);
        _delay_ms(50);

        PORTC |= _BV(PC0);
        _delay_ms(50);
        PORTC &= ~_BV(PC0);
        _delay_ms(50);

        PORTB |= _BV(PB5);
        _delay_ms(50);
        PORTB &= ~_BV(PB5);
        _delay_ms(50);

        PORTB |= _BV(PB4);
        _delay_ms(50);
        PORTB &= ~_BV(PB4);
        _delay_ms(50);

        PORTB |= _BV(PB3);
        _delay_ms(50);
        PORTB &= ~_BV(PB3);
        _delay_ms(50);

        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTB &= ~_BV(PB2);
        _delay_ms(50);

        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTB &= ~_BV(PB1);
        _delay_ms(50);

        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);

        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);     
}

//бегущий огонь по кругу поротив часовой стрелки
void heart_four()
{
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);

        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTB &= ~_BV(PB1);
        _delay_ms(50);

        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTB &= ~_BV(PB2);
        _delay_ms(50);

        PORTB |= _BV(PB3);
        _delay_ms(50);
        PORTB &= ~_BV(PB3);
        _delay_ms(50);

        PORTB |= _BV(PB4);
        _delay_ms(50);
        PORTB &= ~_BV(PB4);
        _delay_ms(50);

        PORTB |= _BV(PB5);
        _delay_ms(50);
        PORTB &= ~_BV(PB5);
        _delay_ms(50);

        PORTC |= _BV(PC0);
        _delay_ms(50);
        PORTC &= ~_BV(PC0);
        _delay_ms(50);

        PORTC |= _BV(PC1);
        _delay_ms(50);
        PORTC &= ~_BV(PC1);
        _delay_ms(50);

        PORTC |= _BV(PC2);
        _delay_ms(50);
        PORTC &= ~_BV(PC2);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        _delay_ms(50);
        PORTC &= ~_BV(PC3);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        _delay_ms(50);
        PORTC &= ~_BV(PC4);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        _delay_ms(50);
        PORTC &= ~_BV(PC5);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        _delay_ms(50);

        PORTD |= _BV(PD3);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        _delay_ms(50);
}

//бегуший огонь с заполнением по часовой стрелке
void heart_five()
{
        PORTB |= _BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        _delay_ms(50);

        PORTC |= _BV(PC2);
        _delay_ms(50);

        PORTC |= _BV(PC1);
        _delay_ms(50);

        PORTC |= _BV(PC0);
        _delay_ms(50);

        PORTB |= _BV(PB5);
        _delay_ms(50);

        PORTB |= _BV(PB4);
        _delay_ms(50);

        PORTB |= _BV(PB3);
        _delay_ms(50);

        PORTB |= _BV(PB2);
        _delay_ms(50);

        PORTB |= _BV(PB1);
        _delay_ms(50);

        PORTB |= _BV(PB0);
        _delay_ms(50);

        PORTD |= _BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD5);
        _delay_ms(50);

        PORTB |= _BV(PB7);
        _delay_ms(50);
}

//бегуший огонь с заполнением против часовой стрелки
void heart_six()
{
        PORTB |= _BV(PB6);
        _delay_ms(50);

        PORTB |= _BV(PB7);
        _delay_ms(50);

        PORTD |= _BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD7);
        _delay_ms(50);

        PORTB |= _BV(PB0);
        _delay_ms(50);

        PORTB |= _BV(PB1);
        _delay_ms(50);

        PORTB |= _BV(PB2);
        _delay_ms(50);

        PORTB |= _BV(PB3);
        _delay_ms(50);

        PORTB |= _BV(PB4);
        _delay_ms(50);

        PORTB |= _BV(PB5);
        _delay_ms(50);

        PORTC |= _BV(PC0);
        _delay_ms(50);

        PORTC |= _BV(PC1);
        _delay_ms(50);

        PORTC |= _BV(PC2);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        _delay_ms(50);

        PORTD |= _BV(PD3);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        _delay_ms(50);

        PORTB |= _BV(PB6);
        _delay_ms(50);
}

//половинки сердца мигающие поочередно
void heart_seven()
{
        PORTB |= _BV(PB6);
        PORTD |= _BV(PD4);
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD2);
        PORTD |= _BV(PD1);
        PORTD |= _BV(PD0);
        PORTC |= _BV(PC5);
        PORTC |= _BV(PC4);
        PORTC |= _BV(PC3);
        PORTC |= _BV(PC2);
        PORTC |= _BV(PC1);
        PORTC |= _BV(PC0);
        _delay_ms(1000);
        full_leds_off();
        PORTC |= _BV(PC0);
        PORTB |= _BV(PB5);
        PORTB |= _BV(PB4);
        PORTB |= _BV(PB3);
        PORTB |= _BV(PB2);
        PORTB |= _BV(PB1);
        PORTB |= _BV(PB0);
        PORTD |= _BV(PD7);
        PORTD |= _BV(PD6);
        PORTD |= _BV(PD5);
        PORTB |= _BV(PB7);
        PORTB |= _BV(PB6);
        _delay_ms(1000);
        full_leds_off();
        PORTB |= _BV(PB6);
        PORTD |= _BV(PD4);
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD2);
        PORTD |= _BV(PD1);
        PORTD |= _BV(PD0);
        PORTC |= _BV(PC5);
        PORTC |= _BV(PC4);
        PORTC |= _BV(PC3);
        PORTC |= _BV(PC2);
        PORTC |= _BV(PC1);
        PORTC |= _BV(PC0);
        _delay_ms(1000);
        full_leds_off();
        PORTC |= _BV(PC0);
        PORTB |= _BV(PB5);
        PORTB |= _BV(PB4);
        PORTB |= _BV(PB3);
        PORTB |= _BV(PB2);
        PORTB |= _BV(PB1);
        PORTB |= _BV(PB0);
        PORTD |= _BV(PD7);
        PORTD |= _BV(PD6);
        PORTD |= _BV(PD5);
        PORTB |= _BV(PB7);
        PORTB |= _BV(PB6);
}

void heart_eight()
{
        //центральный - верх******* 
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);
        //*************************

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTC &= ~_BV(PC5);
        PORTB &= ~_BV(PB1);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTC &= ~_BV(PC4);
        PORTB &= ~_BV(PB2);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        PORTB |= _BV(PB3);
        _delay_ms(50);
        PORTC &= ~_BV(PC3);
        PORTB &= ~_BV(PB3);
        _delay_ms(50);

        PORTC |= _BV(PC2);
        PORTB |= _BV(PB4);
        _delay_ms(50);
        PORTC &= ~_BV(PC2);
        PORTB &= ~_BV(PB4);
        _delay_ms(50);

        PORTC |= _BV(PC1);
        PORTB |= _BV(PB5);
        _delay_ms(50);
        PORTC &= ~_BV(PC1);
        PORTB &= ~_BV(PB5);
        _delay_ms(50);

        //центр - низ**************
        PORTC |= _BV(PC0);
        _delay_ms(50);
        //*************************

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTC &= ~_BV(PC5);
        PORTB &= ~_BV(PB1);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTC &= ~_BV(PC4);
        PORTB &= ~_BV(PB2);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        PORTB |= _BV(PB3);
        _delay_ms(50);
        PORTC &= ~_BV(PC3);
        PORTB &= ~_BV(PB3);
        _delay_ms(50);

        PORTC |= _BV(PC2);
        PORTB |= _BV(PB4);
        _delay_ms(50);
        PORTC &= ~_BV(PC2);
        PORTB &= ~_BV(PB4);
        _delay_ms(50);

        PORTC |= _BV(PC1);
        PORTB |= _BV(PB5);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTC &= ~_BV(PC5);
        PORTB &= ~_BV(PB1);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTC &= ~_BV(PC4);
        PORTB &= ~_BV(PB2);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        PORTB |= _BV(PB3);
        _delay_ms(50);
        PORTC &= ~_BV(PC3);
        PORTB &= ~_BV(PB3);
        _delay_ms(50);

        PORTC |= _BV(PC2);
        PORTB |= _BV(PB4);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTC &= ~_BV(PC5);
        PORTB &= ~_BV(PB1);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        PORTB |= _BV(PB2);
        _delay_ms(50);
        PORTC &= ~_BV(PC4);
        PORTB &= ~_BV(PB2);
        _delay_ms(50);

        PORTC |= _BV(PC3);
        PORTB |= _BV(PB3);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        PORTC &= ~_BV(PC5);
        PORTB &= ~_BV(PB1);
        _delay_ms(50);

        PORTC |= _BV(PC4);
        PORTB |= _BV(PB2);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        PORTD &= ~_BV(PD0);
        PORTB &= ~_BV(PB0);
        _delay_ms(50);

        PORTC |= _BV(PC5);
        PORTB |= _BV(PB1);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        PORTD &= ~_BV(PD1);
        PORTD &= ~_BV(PD7);
        _delay_ms(50);

        PORTD |= _BV(PD0);
        PORTB |= _BV(PB0);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        PORTD &= ~_BV(PD2);
        PORTD &= ~_BV(PD6);
        _delay_ms(50);

        PORTD |= _BV(PD1);
        PORTD |= _BV(PD7);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        PORTD &= ~_BV(PD3);
        PORTD &= ~_BV(PD5);
        _delay_ms(50);

        PORTD |= _BV(PD2);
        PORTD |= _BV(PD6);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        PORTD &= ~_BV(PD4);
        PORTB &= ~_BV(PB7);
        _delay_ms(50);
       
        PORTD |= _BV(PD3);
        PORTD |= _BV(PD5);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
        PORTB &= ~_BV(PB6);
        _delay_ms(50);

        PORTD |= _BV(PD4);
        PORTB |= _BV(PB7);
        _delay_ms(50);
        //--
        PORTB |= _BV(PB6);
        _delay_ms(50);
}

int heart_brightness()
{
    PORTB=0x00;
    DDRB=0xFF;
 
    PORTC=0x00;
    DDRC=0xFF;

    PORTD=0x00;
    DDRD=0xFF;

    while(1)
    {
        int n,m,k,v;
        k=1;
        m=0;
        v=255;
       
        while(1)
        {
            PORTB=0xFF;
            PORTC=0xFF;
            PORTD=0xFF;
 
            for(n=0; n<=v; n++)
            {
                if(n==k)
                {
                    PORTD &= ~_BV(PD4);
                    PORTB &= ~_BV(PB6);
                    PORTD &= ~_BV(PD3);
                    PORTB &= ~_BV(PB7);
                    PORTD &= ~_BV(PD2);
                    PORTD &= ~_BV(PD5);
                    PORTD &= ~_BV(PD1);
                    PORTD &= ~_BV(PD6);
                    PORTD &= ~_BV(PD0);
                    PORTD &= ~_BV(PD7);
                    PORTC &= ~_BV(PC5);
                    PORTB &= ~_BV(PB0);
                    PORTC &= ~_BV(PC4);
                    PORTB &= ~_BV(PB1);
                    PORTC &= ~_BV(PC3);
                    PORTB &= ~_BV(PB2);
                    PORTC &= ~_BV(PC2);
                    PORTB &= ~_BV(PB3);
                    PORTC &= ~_BV(PC1);
                    PORTB &= ~_BV(PB4);
                    PORTC &= ~_BV(PC0);
                    PORTB &= ~_BV(PB5);
                }
            }
            m--;
            if(m<=5) {k++; m=0;}
            if(k==v) k=0;
        };
    };
}

int main(void)
{  
    //устанавливаем все порты на выход
    DDRB = 0xFF;
    DDRC = 0xFF;
    DDRD = 0xFF;
   
    while(1)
    {
        _delay_ms(1500);       
        heart_one();
            full_leds_off();
        heart_two();
            full_leds_off();
        heart_three();
            full_leds_off();
        heart_four();
            full_leds_off();
        heart_five();
            full_leds_off();
        heart_six();
            full_leds_off();
        heart_seven();
            full_leds_off();
        heart_eight();
            full_leds_off();
        heart_brightness();
    }
}

Компилируем наш получившийся файл дабы получить прошивку в hex:

avr-gcc -mmcu=atmega8 -I. -gdwarf-2 -DF_CPU=1000000UL -Os -o main.o main.c
avr-objcopy -O ihex main.o main.hex

Заливаем получившуюся прошивку в наш микроконтроллер и выставляем fuse(если их меняли):
hfuse: 0xFF
lfuse: 0xE1

Теперь осталось собрать все до кучи и проверить все в боевых условиях действии. Вот что получилось у меня в итоге:
box_1
box_2
box_3
box_4
box_6
box_7
box_5

И напоследок видео работы:

Скачать архив проекта: heart

© 2014 — 2015, XELFAER. Все права защищены. Использование материалов блога разрешается только при указании активной ссылки на статью.

Print Friendly

Рубрики: Linux | Microcontrollers | Radioelectronica


комментария 33

  1. atsybulin:

    Спасибо за классную идею. На её основе я сделал что-то похожее: https://vk.com/wall12877966_313

    • Красивая шкатулка. На мой взгляд, для такого подарка использование макетной платы не совсем правильно. По хорошему — нужно было вытравить плату, было бы на вид эстетичнее.

      • atsybulin:

        Я раньше этим никогда не занимался, а время поджимало, поэтому остановился на макетке, но в следующих проектах постараюсь попробовать с травлением.

  2. PiKa4u:

    Добрый день.
    У меня возникла проблема, прошил мегу 8-ю, но фьюзы отказались выставляться. Попробовал сунуть на плату и не один светодиод не загорелся, что это может быть?

    • Данная разводка печатной платы отличается от указанной в моей статье. Если не припаивали МК — давайте фото платы без него. Полярность светодиодов проверяли перед запайкой? Катод светодиодов должен припаиваться к общей шине, в данном случае — это окантовка сердца. Как вариант мультиметром прозвоните их на плате в режиме прозвонки цепи.

      • PiKa4u:

        Полярность проверял конечно, и перед запайкой и после, окантовка сердца является (-) и батарейка туда же подключена. Вот фото
        http://img.radiokot.ru/files/84857/o0hzr3kfq.JPG
        Собрано по этой статье https://www.drive2.ru/b/1444924/ , но Ваш вариант Я так понял, является первоисточником

        • Прошейте МК вне схемы, подпаяв провода к ножкам и подав на нее питание.

          • PiKa4u:

            Так и делаю, при помощи громова.
            Прошивал при помощи SinaProg 2.1. Судя по коду, что выдала программа, Я так понял, что она нифига не прошила, в чем может быть проблема?
            http://img.radiokot.ru/files/84857/o0kah0thy.PNG
            http://img.radiokot.ru/files/84857/o0kamsskb.PNG

          • Попробуйте прошить просто через avrdude + сразу прошить фьюзы полностью заводские:
            hfuse: 0xd9
            lfuse: 0xe1
            так как если шить указанные в статье (а у Вас пока не понятно что не работает) будет опасно, так как будет отключен бит SPIEN, и МК можно будет только через параллельный программатор прошить.

          • PiKa4u:

            "Попробуйте прошить просто через avrdude"
            Она у меня не работает, при нажатии кнопки прошить, пишет "Ошибка при запуске приложения (0xc000007b)" и после этого закрывается

          • PiKa4u:

            С ошибкой avrdude Я разобрался, но она не определяет программатор Громова

          • Вы уверены что программатор рабочий? Ранее им прошивали МК?

          • PiKa4u:

            Программатором громова Я прошивал программатор USBasp

          • Тогда как вариант попробовать прошить с помощью USBasp, если и с ним будет такой же результат — тогда скорее всего проблема с микроконтроллером.

          • PiKa4u:

            USBasp не работает на моем домашнем компе, а на завод щас не попадешь

  3. Bogdan88:

    Добрый день! Спасибо за плату и прошивку, скомпилировал для меги88, все работает. Вот только остался вопрос, не могу понять, heart_brightness длиться бесконечно? Как можно уменьшить количество его повторов?

    • Добрый.
      Да, функция heart_brightness длится бесконечно для создания эффекта бьющегося сердца. Ограничить можно количество повторов (можете изменить к примеру главный цикл, который задаст необходимое количество повторов этого эффекта внутри самой функции), но после — теряется эстетичность.

      • Bogdan88:

        Не могли бы вы привести пример, как это сделать? И не понятно, зачем в heart_brightness два бесконечных цикла? закомментировал один, все так же работало.

        • Так как используется бесконечный цикл в функции — необходимо его заменить на обычный (тот же for) для возможности выхода из него в котором задаете количество повторений.
          Относительно применения 2-ух бесконечных циклов в функции — уже и сам не припомню почему я так сделал, единственно помниться что на тот момент столкнулся с каким то глюком и этот эффект не работал как мне было нужно и был выбран просто рабочий вариант.

  4. BlYur:

    1) Не имеется ли принципиальной схемы устройства?

    2) Чем руководствовались при выборе номиналов резисторов? Может стОит выбрать номиналы поменьше?
    3) Геркон использовался группы Б?

    4) Как крепили провода к аккумулятору?

    • 1) Принципиальная схема доступна в архиве проекта EagleCAD.
      2) Номинал выбирался что бы визуально нормально воспринималось и не было сильного засвета + что бы была нормальная работа светодиода.
      3) Использовался переключающий геркон типа КЭМ-3(группа А) с размыкающимся контактом.
      4) Просто припаивались провода непосредственно к аккумулятору.

  5. BlYur:

    5) Фьюзы, как я понял, заводские?

  6. BlYur:

    int n,m,k,v;
            k=1;
            m=0;
            v=255;
           
                 for(n=0; n<=v; n++)
                {
                    if(n==k)
                    {
                        …
                    }
                }
                m—;
                if(m<=5) {k++; m=0;}
                if(k==v) k=0;

    Какой смысл в переменной "m" и в  m—; if(m<=5) {k++; m=0;} ??? 

Добавить комментарий