niedziela, 27 marca 2011

DIY: Serce LED z ATmega8 by peter507

Autor: peter507
Redakcja: Dondu


Prezentowany układ posiada 22 czerwone diody LED, każda sterowana niezależnie z jednego portu mikrokontrolera ATmega8. Diody na płytce ułożone są w kształt serca.






Program sterujący zawiera pięć sekwencji świecenia diod, wszystkie przedstawione są na załączonym filmie.

Wykorzystany został również pin PC6 procesora który fabrycznie ustawiony jest jako RESET. Po zaprogramowaniu kostki fusebitami musimy wyłączyć sprzętowy RESET, co uniemożliwi nam ponowne zaprogramowanie tego procesora przy użyciu zwykłego programatora.

Płytka PCB stanowi jednocześnie obudowę układu. W trackie wytrawiania na dole pozostawiony został pasek miedzi o szerokości ok. 2cm. Następnie wytrawiony został kawałek laminatu z takim samym paskiem.






Obie części zostały zlutowane pod kątem dzięki czemu powstała praktyczna podstawka, na której jednocześnie znajduje się bateria 9V z której zasilany jest, cały układ.







Płytka została chemicznie pocynowania, dla lepszej estetyki, oraz aby miedź z czasem się nie utleniła.

Atmega8 taktowana jest wewnętrznym zegarem o wartości 1MHz . Zasilana jest poprzez stabilizator 7805 i kondensatory filtrujące.

Płytka wykonana została w Eagle. „Polygon” w tym przypadku znajduje się na VCC ponieważ wszystkie diody na stałe zasilone są z 5V, zaś sterowane „masą” z mikrokontrolera. Przy nodze VCC został dodany kondensator SMD 100nF.

Poniższy rysunek przedstawia schemat urządzenia.


Schemat

Płytka PCB: DIY-Serce-LED-plytka-PCB.pdf (kopia)




Poniższy plik zawiera kod programu:
program.c
#include <avr/io.h>
#include <util/delay.h>


#define DIODE1 (1<<PC5)  //definicja pinu do którego podłączona jest dioda
#define DIODE1_OFF PORTC |= DIODE1 //definicja włączania diody (stan wysoki)
#define DIODE1_ON PORTC &= ~ DIODE1 //definicja wyłączania diody (stan niski)

#define DIODE2 (1<<PC6)
#define DIODE2_OFF PORTC |= DIODE2
#define DIODE2_ON PORTC &= ~ DIODE2

#define DIODE3 (1<<PD0)
#define DIODE3_OFF PORTD |= DIODE3
#define DIODE3_ON PORTD &= ~ DIODE3

#define DIODE4 (1<<PD1)
#define DIODE4_OFF PORTD |= DIODE4
#define DIODE4_ON PORTD &= ~ DIODE4

#define DIODE5 (1<<PD2)
#define DIODE5_OFF PORTD |= DIODE5
#define DIODE5_ON PORTD &= ~ DIODE5

#define DIODE6 (1<<PD3)
#define DIODE6_OFF PORTD |= DIODE6
#define DIODE6_ON PORTD &= ~ DIODE6

#define DIODE7 (1<<PD4)
#define DIODE7_OFF PORTD |= DIODE7
#define DIODE7_ON PORTD &= ~ DIODE7

#define DIODE8 (1<<PB6)
#define DIODE8_OFF PORTB |= DIODE8
#define DIODE8_ON PORTB &= ~ DIODE8

#define DIODE9 (1<<PB7)
#define DIODE9_OFF PORTB |= DIODE9
#define DIODE9_ON PORTB &= ~ DIODE9

#define DIODE10 (1<<PD5)
#define DIODE10_OFF PORTD |= DIODE10
#define DIODE10_ON PORTD &= ~ DIODE10

#define DIODE11 (1<<PD6)
#define DIODE11_OFF PORTD |= DIODE11
#define DIODE11_ON PORTD &= ~ DIODE11

#define DIODE12 (1<<PB0)
#define DIODE12_OFF PORTB |= DIODE12
#define DIODE12_ON PORTB &= ~ DIODE12

#define DIODE13 (1<<PB1)
#define DIODE13_OFF PORTB |= DIODE13
#define DIODE13_ON PORTB &= ~ DIODE13

#define DIODE14 (1<<PB2)
#define DIODE14_OFF PORTB |= DIODE14
#define DIODE14_ON PORTB &= ~ DIODE14

#define DIODE15 (1<<PB3)
#define DIODE15_OFF PORTB |= DIODE15
#define DIODE15_ON PORTB &= ~ DIODE15

#define DIODE16 (1<<PB4)
#define DIODE16_OFF PORTB |= DIODE16
#define DIODE16_ON PORTB &= ~ DIODE16

#define DIODE17 (1<<PB5)
#define DIODE17_OFF PORTB |= DIODE17
#define DIODE17_ON PORTB &= ~ DIODE17

#define DIODE18 (1<<PC0)
#define DIODE18_OFF PORTC |= DIODE18
#define DIODE18_ON PORTC &= ~ DIODE18

#define DIODE19 (1<<PC1)
#define DIODE19_OFF PORTC |= DIODE19
#define DIODE19_ON PORTC &= ~ DIODE19

#define DIODE20 (1<<PC2)
#define DIODE20_OFF PORTC |= DIODE20
#define DIODE20_ON PORTC &= ~ DIODE20

#define DIODE21 (1<<PC3)
#define DIODE21_OFF PORTC |= DIODE21
#define DIODE21_ON PORTC &= ~ DIODE21

#define DIODE22 (1<<PC4)
#define DIODE22_OFF PORTC |= DIODE22
#define DIODE22_ON PORTC &= ~ DIODE22

#define DELAY_SEQ1 70 //markrodefinicje czasów opoznienia pomiedy wlaczaniem kolejnych diod
#define DELAY_SEQ2 70 //oddzielne dla kazdej sekwencji
#define DELAY_SEQ3 70
#define DELAY_SEQ4 70
#define DELAY_SEQ5 70

void all_off (void);
void all_on (void);

int main(void)
{

 DDRC |= DIODE1;  // kierunek pinu PB1 - wyjściowy (0)
 DDRC |= DIODE2;
 DDRD |= DIODE3;
 DDRD |= DIODE4;
 DDRD |= DIODE5;
 DDRD |= DIODE6;
 DDRD |= DIODE7;
 DDRB |= DIODE8;
 DDRB |= DIODE9;
 DDRD |= DIODE10;
 DDRD |= DIODE11;
 DDRB |= DIODE12;
 DDRB |= DIODE13;
 DDRB |= DIODE14;
 DDRB |= DIODE15;
 DDRB |= DIODE16;
 DDRB |= DIODE17;
 DDRC |= DIODE18;
 DDRC |= DIODE19;
 DDRC |= DIODE20;
 DDRC |= DIODE21;
 DDRC |= DIODE22;


 all_off();   //wyłączenie wszystkich diod


 while(1)
 {

//------PIERWSZA SEKWENCJA--------
//zapalanie diod od srodka serca do dołu
  _delay_ms(500);
  DIODE2_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE22_ON;

  DIODE3_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE21_ON;

  DIODE4_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE20_ON;

  DIODE1_ON;

  DIODE5_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE19_ON;

  DIODE6_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE18_ON;

  DIODE7_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE17_ON;

  DIODE8_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE16_ON;

  DIODE9_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE15_ON;

  DIODE10_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE14_ON;

  DIODE11_ON;
  _delay_ms(DELAY_SEQ1);
  DIODE13_ON;

  _delay_ms(DELAY_SEQ1);
  DIODE12_ON;

  _delay_ms(1000);
  all_off();

//------DRUGA SEKWENCJA------
//mignięcie podwójne sercem

  all_on();
  _delay_ms(1000);
  all_off();
  _delay_ms(500);
  all_on();
  _delay_ms(1000);

//wygaszanie serca od dołu do góry
  DIODE12_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE11_OFF;
  DIODE13_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE10_OFF;
  DIODE14_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE9_OFF;
  DIODE15_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE8_OFF;
  DIODE16_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE7_OFF;
  DIODE17_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE6_OFF;
  DIODE18_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE5_OFF;
  DIODE19_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE4_OFF;
  DIODE20_OFF;
  DIODE1_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE3_OFF;
  DIODE21_OFF;
  _delay_ms(DELAY_SEQ2);
  DIODE2_OFF;
  DIODE22_OFF;

  _delay_ms(500);   //opóznienie pomiędzy sekwencjami
//--------TRZECIA SEKWENCJA-----
//podwójne przejscie przez zgaszone serce jednej zapalonej diody.

 for (int i = 0; i < 2; i++)
 {
  DIODE1_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE1_OFF;
  DIODE2_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE2_OFF;
  DIODE3_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE3_OFF;
  DIODE4_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE4_OFF;
  DIODE5_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE5_OFF;
  DIODE6_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE6_OFF;
  DIODE7_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE7_OFF;
  DIODE8_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE8_OFF;
  DIODE9_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE9_OFF;
  DIODE10_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE10_OFF;
  DIODE11_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE11_OFF;
  DIODE12_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE12_OFF;
  DIODE13_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE13_OFF;
  DIODE14_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE14_OFF;
  DIODE15_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE15_OFF;
  DIODE16_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE16_OFF;
  DIODE17_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE17_OFF;
  DIODE18_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE18_OFF;
  DIODE19_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE19_OFF;
  DIODE20_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE20_OFF;
  DIODE21_ON;
  _delay_ms(DELAY_SEQ3);
  DIODE21_OFF;
  DIODE22_ON;
  _delay_ms(100);
  DIODE22_OFF;
 }


//-------CZWARTA SEKWENCJA-------
//rozswietlanie serca po kolei kazda dioda
 _delay_ms(300);  //opóznienie pomiędzy sekwencjami

 DIODE1_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE2_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE3_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE4_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE5_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE6_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE7_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE8_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE9_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE10_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE11_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE12_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE13_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE14_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE15_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE16_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE17_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE18_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE19_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE20_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE21_ON;
 _delay_ms(DELAY_SEQ4);
 DIODE22_ON;


//wedrujaca jedna wygaszona dioda wokol serca
 for (int i = 0; i <2; i++)
 {
  DIODE1_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE1_ON;
  DIODE2_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE2_ON;
  DIODE3_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE3_ON;
  DIODE4_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE4_ON;
  DIODE5_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE5_ON;
  DIODE6_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE6_ON;
  DIODE7_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE7_ON;
  DIODE8_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE8_ON;
  DIODE9_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE9_ON;
  DIODE10_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE10_ON;
  DIODE11_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE11_ON;
  DIODE12_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE12_ON;
  DIODE13_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE13_ON;
  DIODE14_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE14_ON;
  DIODE15_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE15_ON;
  DIODE16_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE16_ON;
  DIODE17_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE17_ON;
  DIODE18_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE18_ON;
  DIODE19_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE19_ON;
  DIODE20_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE20_ON;
  DIODE21_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE21_ON;
  DIODE22_OFF;
  _delay_ms(DELAY_SEQ4);
  DIODE22_ON;
 }


//----------SEKWENCJA PIĄTA-----------
//wygaszenie serca po jednej diodzie

 DIODE1_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE2_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE3_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE4_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE5_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE6_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE7_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE8_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE9_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE10_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE11_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE12_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE13_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE14_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE15_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE16_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE17_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE18_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE19_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE20_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE21_OFF;
 _delay_ms(DELAY_SEQ5);
 DIODE22_OFF;

 }
}

void all_off (void)  //funkcja wyłączająca wszystkie diody LED
{

 DIODE1_OFF;
 DIODE2_OFF;
 DIODE3_OFF;
 DIODE4_OFF;
 DIODE5_OFF;
 DIODE6_OFF;
 DIODE7_OFF;
 DIODE8_OFF;
 DIODE9_OFF;
 DIODE10_OFF;
 DIODE11_OFF;

 DIODE12_OFF;
 DIODE13_OFF;
 DIODE14_OFF;
 DIODE15_OFF;
 DIODE16_OFF;
 DIODE17_OFF;
 DIODE18_OFF;
 DIODE19_OFF;
 DIODE20_OFF;
 DIODE21_OFF;
 DIODE22_OFF;


}

void all_on (void) //funkcja włączająca wszystkie diody LED
{

 DIODE1_ON;
 DIODE2_ON;
 DIODE3_ON;
 DIODE4_ON;
 DIODE5_ON;
 DIODE6_ON;
 DIODE7_ON;
 DIODE8_ON;
 DIODE9_ON;
 DIODE10_ON;
 DIODE11_ON;

 DIODE12_ON;
 DIODE13_ON;
 DIODE14_ON;
 DIODE15_ON;
 DIODE16_ON;
 DIODE17_ON;
 DIODE18_ON;
 DIODE19_ON;
 DIODE20_ON;
 DIODE21_ON;
 DIODE22_ON;

}

Do pobrania spakowany projekt wraz z plikiem HEX: Serduszko.zip (kopia)





Uwagi redakcji

Na początek wyjaśnienie dot. uwag w komentarzu do niniejszego artykułu. Część projektów jest wzorowana na innych opublikowanych w sieci. Ten projekt wzorowany jest na innym: Prezent walentynkowy - serce LED Jednakże całość wykonana przez autora od podstaw, nie można więc mówić o plagiacie.

Niestety mamy sporo uwag technicznych:

1. Autor w swojej wersji płytki PCB dodał polygon, którego stosowanie zawsze warto wykonać. Niestety popełnił poważny błąd polegający na tym, że zamiast rozlać masę (polygon GND) rozlał ... Vcc. Dla tego projektu może nie mieć to w ogóle znaczenia, ale musieliśmy to wypunktować. Przeróbka PCB będzie wymagała nieco poprawek.

2. Na schemacie w zakresie regulatora napięcia, autor zastosował kondensatory elektrolityczne. Niestety na zdjęciach PCB zamiast nich są wstawione kondensatory ceramiczne.

3. Zasilanie z baterii 9V ma zaletę w postaci w miarę małej baterii o dużej pojemności, ale jest nieekonomiczne z powodu zbyt wysokiego napięcia, które odkłada się na regulatorze napięcia 7805 powodując niepotrzebne straty energii, wypuszczanej do atmosfery w postaci ciepła. W takich przypadkach należy używać baterii o mniejszym napięciu w połączeniu z regulatorem napięcia LDO: Regulatory napięcia vs wydzielane ciepło, czyli: Grzeje się!

Innym rozwiązaniem, jest zasilenie całego układu z baterii o odpowiednio niskim napięciu bez stosowania regulatora napięcia, wykorzystując jedynie prosty filtr RC na zasilaniu mikrokontrolera. Takie rozwiązanie jest możliwe dlatego, że autor zastosował włączanie diod LED poprzez stan niski na pinie mikrokontrolera. W związku z tym, wydzielone filtrem RC zasilanie mikrokontrolera nie uczestniczy w dostarczaniu prądu diodom, przez co nie będzie zakłócane.

Jeszcze innym rozwiązaniem jest zbudowanie przetwornicy impulsowej, których jest sporo różnych i w miarę przyzwoitych cenach. Część z nich pozwala wyssać z baterii znacznie więcej energii pomimo spadku napięcia poniżej progu działania mikrokontrolera.

4. Program zasługuje na całkowitą zmianę, poprzez użycie tablic przechowywanych w pamięci programu (FLASH). To znacząco wpłynie na jego czytelność i wielkość zajmowanej pamięci.

-----

Istotna jest także kwestia obciążenia pinów mikrokontrolera. Autor zastosował czerwone diody które prawdopodobnie mają napięcie przewodzenia około Vf=2V. Ponieważ na schemacie nie podał wartości rezystorów, stąd ze zdjęć ustaliliśmy, że są to rezystory 1kΩ. W związku z tym prąd pojedynczej diody wynosi If = (5V - 2V )/ 1kΩ = 3mA

Taki prąd wytrzyma oczywiście pojedynczy pin mikrokontrolera. Dla całego portu będzie to łącznie 8 x 3mA = 24mA, czyli także bez problemu.

Diod jest łącznie 22, stąd I = 22 * 3mA = 66mA, czyli także ograniczenia mikrokontrolera pod tym kątem nie są przekraczane.

Piszemy jednak o tym dlatego, by osoby, które skorzystają z projektu były świadome dlaczego rezystory diod są aż tak duże. Więcej w temacie obciążeń pinów prądami: Mikrokontroler vs prądy pinów

10 komentarzy:

  1. Super pomysł na prezent, a zblizają się Walentynki :)))

    OdpowiedzUsuń
  2. Projekt zatrważająco podobny do mojego:
    http://www.elektroda.pl/rtvforum/viewtopic.php?t=1924602&highlight=prezent+walentynkowy+serce+led&sid=

    OdpowiedzUsuń
    Odpowiedzi
    1. Podobny, i co z tego ? Płytka i program zaprojektowany od początku ;)

      Usuń
    2. No ale trzeba było chociaż wspomnieć, że się wzorowałeś na tym projekcie, a tak jest co najmniej niesmak.

      Usuń
  3. dla mnie REWELACJA - wykonanie PCB jak za DOBRYCH czasów (80's), ode mnie 8 pkt za wielkie zaangażowane

    OdpowiedzUsuń
  4. Wykonanie programu nieco kiepskie - przydały by się pętle do sterowania diodami a nie każdą sterować osobną linijką

    OdpowiedzUsuń
  5. Pomysł rzeczywiście jest ściągnięty i projekt dało by się zrobić lepiej, ale każdy robi tak jak umie a z własnego doświadczenia wiem, że autor zdrowo musiał napracować się przy jego wykonaniu.

    OdpowiedzUsuń
  6. A można prosić o plik wsadowy do tego serduszka ? :(

    OdpowiedzUsuń
    Odpowiedzi
    1. Wedle życzenia :-)
      Dodałem pliki do pobrania pod listingiem kodu źródłowego.

      Usuń
  7. Najważniejsze, że ma komu to dać :) MM

    OdpowiedzUsuń