✨ Miganie diodami (Asembler 8051)

Pętle, podprogramy i tablice (wzorce świecenia)

1. Cel lekcji

W poprzednich lekcjach sterowaliśmy pojedynczą diodą i brzęczykiem. Teraz robimy krok w stronę „prawdziwego programu”: będziemy sterować wieloma diodami naraz (całym portem), tworzyć efekty świetlne i organizować kod przy pomocy pętli oraz podprogramów.

Dodatkowo wprowadzimy temat, który odróżnia „początkujący kod” od „sensownego projektu”: tablice (tabele wzorców) – zamiast wymyślać efekty na bieżąco, zapisujemy wzorce w pamięci programu i odtwarzamy je po kolei.

Po tej lekcji będziesz umiał: sterować portem bajtowo, robić „biegające światło”, używać pętli licznikowych, pisać czytelne procedury (opóźnienie, wyświetlenie wzorca) oraz czytać dane z tabeli w pamięci programu instrukcją MOVC.

2. Założenia sprzętowe (EdSim51)

Dla przejrzystości przyjmujemy, że diody LED są podłączone do portu P1: P1.0P1.7. Jeśli u Ciebie LED są na innym porcie, zamień tylko P1 na P2/P0.

Mapowanie LED w EdSim51 (ważne do tej lekcji):
Diody LED0–LED7 są podłączone do portu P1, odpowiednio: LED0→P1.0, LED1→P1.1, …, LED7→P1.7. W typowej konfiguracji EdSim51 diody są aktywne stanem niskim (active‑low):
0 na bicie zapala LED, a 1 ją gasi.
Dioda Pin 8051 Stan pinu Efekt
LED0P1.00LED świeci
LED1P1.10LED świeci
LED2P1.20LED świeci
LED3P1.30LED świeci
LED4P1.40LED świeci
LED5P1.50LED świeci
LED6P1.60LED świeci
LED7P1.70LED świeci
EdSim51 – diody LED i port
EdSim51 – diody LED i powiązanie z portem
1.png
Logika LED w tej pracowni: przyjmujemy active‑low (LED świeci dla 0). Dlatego w kodach poniżej stosujemy prostą zasadę: wzorzec tworzymy „logicznie” (1 = ma świecić), a tuż przed wyjściem wykonujemy CPL A, żeby odwrócić bity i dopasować je do LED active‑low.

3. Pętle w 8051 – dwa podstawowe style

3.1. Pętla nieskończona (program mikrokontrolera „zawsze działa”)

; Pętla nieskończona
LOOP:
    SJMP LOOP

3.2. Pętla z licznikiem (DJNZ)

Najważniejsze narzędzie do pętli: DJNZ. To jest „for” w asemblerze:

; R7 = licznik
MOV  R7, #10
L1: ; ... kod ...
    DJNZ R7, L1
Tip: jeśli chcesz mieć pętlę „x razy”, to ustaw licznik na x. W praktyce do efektów świetlnych najczęściej używa się R7 lub R6.

4. Podprogramy – po co i jak?

Podprogram (procedura) to fragment kodu, który wywołujesz wielokrotnie: np. opóźnienie, wyświetlenie wzorca, przejście do następnego kroku animacji. Dzięki temu kod:

Instrukcja Znaczenie Uwagi praktyczne
ACALL nazwa Wywołanie procedury (call) Adres powrotu trafia na stos (SP rośnie).
RET Powrót z procedury Zdejmuje adres powrotu ze stosu.
Uwaga o rejestrach: jeśli procedura używa np. R6/R7, a w głównym programie też ich używasz, możesz mieć konflikt. Na start ustalamy zasadę: DELAY używa R6 i R7, a program główny używa R5/R4.

5. Projekt: „Biegające światło” (bez tablic)

Zaczniemy od klasycznego efektu: zapala się jedna dioda i „idzie” w prawo. Zrobimy to bez tabel, korzystając z przesunięć bitowych.

5.1. Kluczowa technika: przesuwanie bitu

Jeśli w rejestrze A jest 0000 0001 (czyli 01h), to po przesunięciu w lewo otrzymasz 0000 0010 (czyli 02h), potem 04h, 08h itd.

5.2. Kod: biegające światło (RL A)

; =========================================
; Lekcja 5 – Program 1: Biegające światło (bez tablic)
; Port: P1
; =========================================

ORG 0000h

MAIN:
    MOV  A, #01h        ; start: tylko P1.0 = 1

LOOP:
    MOV  R4, A          ; zachowaj wzorzec logiczny
    CPL  A               ; odwróć bity (LED active-low)
    MOV  P1, A           ; wyślij na diody
    MOV  A, R4           ; przywróć wzorzec logiczny
    ACALL DELAY
    RL   A              ; przesuwaj zapaloną diodę w lewo (w kółko)
    SJMP LOOP

; --- opóźnienie ---
DELAY:
    MOV  R6, #60
D1: MOV  R7, #200
D2: DJNZ R7, D2
    DJNZ R6, D1
    RET

END
Ćwiczenie: Zamień RL A na RR A i zobacz, że efekt idzie w drugą stronę.

6. Tablice (tabele wzorców) – jak robią to „poważne” programy

Efekty świetlne często nie wynikają z prostego przesuwania bitu. Czasem chcesz niestandardowe wzorce: naprzemiennie, fala, rozszerzanie, mruganie w rytmie. Wtedy zapisujesz gotowe wartości w tabeli i odtwarzasz je po kolei.

6.1. Gdzie trzymamy tablicę?

Najwygodniej trzymać tablicę w pamięci programu (kodzie). W 8051 czyta się ją instrukcją: MOVC A, @A+DPTR.

Co robi MOVC?
1) DPTR wskazuje początek tabeli w pamięci programu,
2) A zawiera indeks (0, 1, 2…),
3) CPU odczytuje bajt z adresu (DPTR + A) i wpisuje go do A.

6.2. Minimalny wzór odczytu z tabeli

; DPTR = adres tabeli
MOV  DPTR, #TAB
MOV  A, #0          ; indeks
MOVC A, @A+DPTR     ; A = TAB[0]

7. Projekt: miganie według tabeli wzorców

Zrobimy efekt oparty o tablicę. Dzięki temu kod jest czysty: pętla bierze kolejny wzorzec i wyświetla go na P1.

7.1. Przykładowa tabela wzorców

Poniżej masz przykładowe wzorce (hex) zapisane „logicznie” (1 = ma świecić). Ponieważ LED są active‑low, kod odwraca je instrukcją CPL A przed wysłaniem na port.

Wzorzec (hex) Binarnie Co to daje na LED?
0AAh 1010 1010 naprzemiennie (co druga dioda)
055h 0101 0101 naprzemiennie (odwrócone)
0F0h 1111 0000 górne 4 diody
00Fh 0000 1111 dolne 4 diody
081h 1000 0001 skrajne diody

7.2. Kod: efekt z tablicy (MOVC + DPTR)

; =========================================
; Lekcja 5 – Program 2: Wzorce z tabeli (tablica w pamięci programu)
; Port: P1
; =========================================

ORG 0000h

MAIN:
    MOV  DPTR, #PATTERN_TAB   ; wskaźnik na tabelę w pamięci programu
    MOV  R5, #0               ; indeks wzorca (0..N-1)

NEXT:
    MOV  A, R5                ; A = indeks
    MOVC A, @A+DPTR           ; A = PATTERN_TAB[indeks]
    MOV  R4, A                ; zachowaj wzorzec logiczny
    CPL  A                       ; odwróć bity (LED active-low)
    MOV  P1, A                   ; wyślij na diody
    MOV  A, R4
    ACALL DELAY

    INC  R5                   ; indeks++
    CJNE R5, #PATTERN_LEN, NEXT   ; jeśli R5 != długość, to bierz następny

    MOV  R5, #0               ; wróć do początku tablicy
    SJMP NEXT

; --- opóźnienie ---
DELAY:
    MOV  R6, #60
D1: MOV  R7, #200
D2: DJNZ R7, D2
    DJNZ R6, D1
    RET

; --- tablica wzorców w pamięci programu ---
PATTERN_TAB:
    DB 0AAh, 055h, 0F0h, 00Fh, 081h, 042h, 024h, 018h
PATTERN_LEN EQU 8

END
Najczęstszy błąd: zapominanie, że MOVC czyta z pamięci programu, a nie z RAM. Dlatego musi być użyte: MOVC A, @A+DPTR (nie MOVX, nie MOV).

8. Mała „zaawansowana technika”: łatwa zmiana efektu bez zmiany kodu

Zauważ, że w Programie 2 możesz całkowicie zmienić efekt świecenia, modyfikując tylko: DB ... w tabeli. Kod sterujący zostaje identyczny. To jest bardzo ważna idea w programowaniu systemów wbudowanych: logika + dane.

Praktyka: Uczniowie mogą robić własne animacje LED tylko przez projektowanie tabeli (np. na kartce: binarnie → hex).

9. Jak to uruchomić w EdSim51 (checklista)

  1. Wklej program (Program 1 lub Program 2) do okna kodu.
  2. Upewnij się, że diody są na porcie P1 (albo zmień w kodzie P1→P2).
  3. Naciśnij Assemble, popraw ewentualne literówki w etykietach.
  4. Uruchom Run i obserwuj LED.
  5. Jeśli efekt jest „odwrotny”, odwróć wzorce w tabeli (np. 0AAh ↔ 055h).
EdSim51 – uruchomienie i obserwacja rejestrów
EdSim51 – uruchomienie programu i obserwacja rejestrów
Wstaw tu obraz 2.png (zrzut: Assemble/Run + podgląd P1, A, DPTR, R5).

10. Zadania dla ucznia

  1. Biegające światło: w Programie 1 dodaj, żeby co 8 kroków robiło „pauzę” (dłuższe opóźnienie).
  2. Nowy efekt tablicowy: stwórz tabelę 8 wartości, która robi „rozszerzanie od środka” (np. 18h → 3Ch → 7Eh → FFh → 7Eh → 3Ch → 18h → 00h).
  3. Zmiana kierunku: zrób dwie tabele – „lewo” i „prawo” – i przełączaj je co pełny cykl.
  4. Challenge: użyj dwóch różnych opóźnień: szybkie między wzorcami, a po pełnym cyklu długie.
Co dalej? W następnej lekcji naturalnym krokiem jest zrobienie dokładnych opóźnień na timerach (Timer0/Timer1) oraz generacja tonu na brzęczyku pasywnym.