|
|
Część 3 - wyświetlacz siedmiosegmentowy.
W celu wykonania ćwiczenia należy wykonać połączenia jak
na rysunku. Na rysunku
nie zaznaczono rezystorów ograniczających prąd, ale nie wolno o nich zapomnieć
w układzie.
Przykład 3.1.ASM
NAME P03_01_ASM_SRC
$INCLUDE (ATMEL/REG8252.INC)
P03_01_ASM SEGMENT CODE
RSEG P03_01_ASM
WYSW EQU P0
W1 EQU P2.0
W2 EQU P2.1
W3 EQU P2.2
W4 EQU P2.3
CLR W1
MOV WYSW, #0
SJMP $
END
Przykład 3.1.C
#include <ATMEL\REG8252.H>
#define WYSW P0
sbit W1 = P2^0;
sbit W2 = P2^1;
sbit W3 = P2^2;
sbit W4 = P2^3;
void main(void)
{
W1 = 0;
WYSW = 0;
while(1);
}
Przykład 3.1.BAS
WYSW alias p0
w1 alias p2.0
w2 alias p2.1
w3 alias p2.2
w4 alias p2.3
w1 = 0
wysw = 0
do
loop
end
Omówienie:
Powyższy program powoduje zaświecenie wszystkich segmentów wyświetlacza
W1. Ustawienie stanu niskiego na linii P2.0 (W1) wprowadza tranzystor
w stan nasycenia i na anodę wyświetlacza W1 podane jest napięcie zasilania.
Następnie wszystkie linie portu P0 są ustawiane w stan niski. Powoduje
to włączenie wszystkich segmentów wyświetlacza W1.
Przykład 3.2
W tym przykładzie zajmiemy się wyświetleniem na wyświetlaczu
kolejno cyfr kodu szesnastkowego (0..F). Sposób połączenia poszczególnych
segmentów wyświetlacza z wyprowadzeniami mikrokontrolera przedstawia rysunek.
Tabela kodów sterujących wyświetlaczem siedmiosegmentowym:
Tabela 3.1
|
Wyświetlana cyfra
|
Liczba dziesiętnie
|
Liczba szesnastkowo
|
Liczba dwójkowo
|
|
0
|
192
|
C0
|
11000000
|
|
1
|
249
|
F9
|
11111001
|
|
2
|
164
|
A4
|
10100100
|
|
3
|
176
|
B0
|
10110000
|
|
4
|
153
|
99
|
10011001
|
|
5
|
146
|
92
|
10010010
|
|
6
|
130
|
82
|
10000010
|
|
7
|
248
|
F8
|
11111000
|
|
8
|
128
|
80
|
10000000
|
|
9
|
144
|
90
|
10010000
|
|
A
|
136
|
88
|
10001000
|
|
B
|
131
|
83
|
10000011
|
|
C
|
198
|
C6
|
11000110
|
|
D
|
161
|
A1
|
10100001
|
|
E
|
134
|
86
|
10000110
|
|
F
|
142
|
8E
|
10001110
|
Przykład 3.2.ASM
NAME P03_02_ASM_SRC
$INCLUDE (ATMEL/REG8252.INC)
P03_02_ASM SEGMENT CODE
RSEG P03_02_ASM
_0 EQU 0C0h
_1 EQU 0F9h
_2 EQU 0A4h
_3 EQU 0B0h
_4 EQU 099h
_5 EQU 092h
_6 EQU 082h
_7 EQU 0F8h
_8 EQU 080h
_9 EQU 090h
_A EQU 088h
_B EQU 083h
_C EQU 0C6h
_D EQU 0A1h
_E EQU 086h
_F EQU 08Eh
WYSW EQU P0
W1 EQU P2.0
W2 EQU P2.1
W3 EQU P2.2
W4 EQU P2.3
CLR W1
START:
MOV WYSW,#_0
ACALL CZEKAJ
MOV WYSW,#_1
ACALL CZEKAJ
MOV WYSW,#_2
ACALL CZEKAJ
MOV WYSW,#_3
ACALL CZEKAJ
MOV WYSW,#_4
ACALL CZEKAJ
MOV WYSW,#_5
ACALL CZEKAJ
MOV WYSW,#_6
ACALL CZEKAJ
MOV WYSW,#_7
ACALL CZEKAJ
MOV WYSW,#_8
ACALL CZEKAJ
MOV WYSW,#_9
ACALL CZEKAJ
MOV WYSW,#_A
ACALL CZEKAJ
MOV WYSW,#_B
ACALL CZEKAJ
MOV WYSW,#_C
ACALL CZEKAJ
MOV WYSW,#_D
ACALL CZEKAJ
MOV WYSW,#_E
ACALL CZEKAJ
MOV WYSW,#_F
ACALL CZEKAJ
SJMP START
CZEKAJ:
MOV R1,#255
L2:
MOV R0,#255
L1:
DJNZ R0,L1
DJNZ R1,L2
RET
END
Przykład 3.2.C
#include <ATMEL\REG8252.H>
#define WYSW P0
#define _0 192
#define _1 249
#define _2 164
#define _3 176
#define _4 153
#define _5 146
#define _6 130
#define _7 248
#define _8 128
#define _9 144
#define _A 136
#define _B 131
#define _C 198
#define _D 161
#define _E 134
#define _F 142
sbit W1 = P2^0;
sbit W2 = P2^1;
sbit W3 = P2^2;
sbit W4 = P2^3;
void czekaj(void)
{
char x,y;
for (x = 255; x > 0; --x)
for (y = 255; y > 0; --y);
}
void main(void)
{
W1 = 0;
while(1)
{
WYSW = _0;
czekaj();
WYSW = _1;
czekaj();
WYSW = _2;
czekaj();
WYSW = _3;
czekaj();
WYSW = _4;
czekaj();
WYSW = _5;
czekaj();
WYSW = _6;
czekaj();
WYSW = _7;
czekaj();
WYSW = _8;
czekaj();
WYSW = _9;
czekaj();
WYSW = _A;
czekaj();
WYSW = _B;
czekaj();
WYSW = _C;
czekaj();
WYSW = _D;
czekaj();
WYSW = _E;
czekaj();
WYSW = _F;
czekaj();
}
}
Przykład 3.2.BAS
Wysw Alias P0
W1 Alias P2.0
_0 Alias 192
_1 Alias 249
_2 Alias 164
_3 Alias 176
_4 Alias 153
_5 Alias 146
_6 Alias 130
_7 Alias 248
_8 Alias 128
_9 Alias 144
_a Alias 136
_b Alias 131
_c Alias 198
_d Alias 161
_e Alias 134
_f Alias 142
Reset W1
Do
Wysw = _0
Waitms 250
Wysw = _1
Waitms 250
Wysw = _2
Waitms 250
Wysw = _3
Waitms 250
Wysw = _4
Waitms 250
Wysw = _5
Waitms 250
Wysw = _6
Waitms 250
Wysw = _7
Waitms 250
Wysw = _8
Waitms 250
Wysw = _9
Waitms 250
Wysw = _a
Waitms 250
Wysw = _b
Waitms 250
Wysw = _c
Waitms 250
Wysw = _d
Waitms 250
Wysw = _e
Waitms 250
Wysw = _f
Waitms 250
Loop
End
Każdy program spełnia swoje zadanie, jednak napisany jest
bardzo rozwlekle i nieestetycznie. To samo zadanie można zrealizować znacznie
bardziej estetycznie. Porównajmy jednak wcześniej rozmiary kodu wynikowego
tych programów:
- BASCOM - 197 bajtów
- C - 127 bajtów
- asembler - 93 bajty
Tym razem program w Bascomie zajmuje nieco ponad 2 razy więcej niż jego
odpowiednik w asemblerze.
Przykład 3.3.ASM
NAME P03_03_ASM_SRC
$INCLUDE (ATMEL/REG8252.INC)
P03_03_ASM SEGMENT CODE
RSEG P03_03_ASM
WYSW EQU P0
W1 EQU P2.0
CLR W1
START:
MOV DPTR,#ZNAKI
PETLA:
CLR A
MOVC A,@A+DPTR
JZ START
MOV WYSW,A
INC DPTR
ACALL CZEKAJ
SJMP PETLA
CZEKAJ:
MOV R1,#255
L2:
MOV R0,#255
L1:
DJNZ R0,L1
DJNZ R1,L2
RET
ZNAKI:
DB 192,249,164,176,153,146,130,248,128,144,136,131,198,161,134,142,0
END
Przykład 3.3.C
#include <ATMEL\REG8252.H>
#define WYSW P0
char code znaki[17] = {192,249,164,176,153,146,130,248,128,144,136,131,198,161,134,142,0};
sbit W1 = P2^0;
void czekaj(void)
{
char x,y;
for (x = 255; x > 0; --x)
for (y = 255; y > 0; --y);
}
void main(void)
{
W1 = 0;
while(1)
{
code char * pznaki = &znaki;
while(*pznaki)
{
WYSW = *pznaki;
pznaki++;
czekaj();
}
}
}
Przykład 3.3.BAS
Wysw Alias P0
W1 Alias P2.0
Dim I As Byte
Reset W1
Do
For I = 0 To 15
Wysw = Lookup(i , Znaki)
Waitms 250
Next I
Loop
Znaki:
Data 192 , 249 , 164 , 176 , 153 , 146 , 130 , 248 , 128 , 144 , 136 ,
131 , 198 , 161 , 134 , 142
End
Powyższy program realizuje dokładnie to samo zadanie, jak
program poprzedni, jednak zrealizowany został z użyciem pętli i umieszczeniem
kodów cyfr w tablicy. Zapis programu stał się przez to znacznie krótszy
i bardziej estetyczny. Najbardziej czytelny i łatwy do zrozumienia jest
program napisany w Bascomie. Do pobrania elementu tablicy służy tylko
jedno polecenie - "LOOKUP". Natomiast w języku C konieczne było
zastosowanie łącznie trzech poleceń. W pierwszej kolejności zadeklarowano
zmienną wskaˇnikową "pznaki" i przypisano do niej przy użyciu
operatora adresu "&" adres tablicy "znaki". Następnie
pobrano element tablicy przy użyciu instrukcji "WYSW = *pznaki".
Na końcu konieczne było zinkrementowanie wskaˇnika, aby wskazywał na kolejny
element tablicy. Jak widać pobranie elementu z tablicy w języku C jest
dosyć skomplikowane w porównaniu z Bascomem. Pyzatym, wskaˇniki są jednym
z trudniejszych do zrozumienia elementów języka C dla początkujących.
Najbardziej skomplikowana sprawa jest w asemblerze. Do zrealizowania rozpatrywanego
przez nas zadania zastosowano aż osiem instrukcji:
START:
MOV DPTR,#ZNAKI
PETLA:
CLR A
MOVC A,@A+DPTR
JZ START
MOV WYSW,A
INC DPTR
ACALL CZEKAJ
SJMP PETLA
Instrukcja "MOV DPTR,#ZNAKI" odpowiada przypisaniu
do wskaˇnika adresu pierwszego elementu mikrokontrolerze tablicy. W mikrokontrolerze
8051 jedynym rejestrem, który można zastosować jako 16-bitowy wskaˇnik
jest rejestr DPTR. W nowszych wersjach mikrokontrolera 8051, w tym w wersji
89S8252, występują dwa wskaˇniki DPTR. Jednakże ze względu na konieczność
zachowania 100% kompatybilności kodu z 8051 możliwe jest w danej chwili
użycie tylko jednego wskaˇnika DPTR. W zależności od rodzaju mikrokontrolera
przełączanie aktywnego danej chwili wskaˇnika jest realizowane w różny
sposób. Aby nasze przykłady można było zastosować w dowolnym mikrokontrolerze
nie będziemy korzystać z tego udogodnienia.
Instrukcja "CLR A" jest konieczna, ponieważ adres komórki pamięci
programu pobieranej za pomocą instrukcji "MOVC A, @A+DPTR" jest
sumą zawartości akumulatora i wskaˇnika DPTR. W przypadku niewyzerowania
akumulatora przy powtarzaniu pętli adres byłby obliczony błędnie. Instrukcja
"JZ START" sprawdza, czy osiągnięty został koniec tablicy. Jeśli
tak, to następuje opuszczenie pętli. Następnie pobrany element tablicy
zostaje wysłany do portu P0. Przed powtórzeniem pętli musimy jeszcze zwiększyć
adres następnego elementu tablicy do pobrania o 1.
Wiemy już, jak się przedstawia stopień komplikacji programu
w zależności od użytego języka. Sprawdˇmy teraz ilość miejsca zajmowanego
w pamięci przez każdy program.
- Bascom - 185 bajtów (197 bajtów bez wykorzystania pętli i tablicy)
- C - 82 bajty (127 bajtów)
- Asembler - 42 bajty (93 bajty)
Zgodnie z oczekiwaniami asembler wypada najlepiej. Także
w porównaniu do poprzedniego przykładu bez pętli i tablicy w asemblerze
zyskujemy największą oszczędność pamięci programu.
Przejdˇmy teraz do ciekawszego zagadnienia, mianowicie do
multipleksowanego sterowania wyświetlaczem. Aby zaoszczędzić porty mikrokontrolera,
bardzo często stosowane jest sterowanie multipleksowane. Oznacza to, że
katody odpowiednich segmentów są połączone razem do wyprowadzeń sterujących,
a anody są sterowane osobno. Zapalając odpowiednio szybko poszczególne
segmenty otrzymujemy wrażenie świecenia się wszystkich wyświetlaczy.
Przykład 3.4.ASM
NAME P03_04_ASM_SRC
$INCLUDE (ATMEL/REG8252.INC)
P03_04_ASM SEGMENT CODE
RSEG P03_04_ASM
WYSW EQU P0
W1 EQU P2.0
W2 EQU P2.1
W3 EQU P2.2
W4 EQU P2.3
MOV DPTR,#ZNAKI
PETLA:
CLR W1
MOV A,#9
MOVC A,@A+DPTR
MOV WYSW,A
ACALL CZEKAJ
SETB W1
CLR W2
MOV A,#8
MOVC A,@A+DPTR
MOV WYSW,A
ACALL CZEKAJ
SETB W2
CLR W3
MOV A,#7
MOVC A,@A+DPTR
MOV WYSW,A
ACALL CZEKAJ
SETB W3
CLR W4
MOV A,#6
MOVC A,@A+DPTR
MOV WYSW,A
ACALL CZEKAJ
SETB W4
SJMP PETLA
CZEKAJ:
MOV R1,#255
L2:
MOV R0,#255
L1:
DJNZ R0,L1
DJNZ R1,L2
RET
ZNAKI:
DB 192,249,164,176,153,146,130,248,128,144,136,131,198,161,134,142,0
END
Przykład 3.4.C
#include <ATMEL\REG8252.H>
#define WYSW P0
char code znaki[17] = {192,249,164,176,153,146,130,248,128,144,136,131,198,161,134,142,0};
sbit W1 = P2^0;
sbit W2 = P2^1;
sbit W3 = P2^2;
sbit W4 = P2^3;
void czekaj(void)
{
char x,y;
for (x = 255; x > 0; --x)
for (y = 255; y > 0; --y);
}
void main(void)
{
code char * pznaki;
pznaki = &znaki;
while(1)
{
W1 = 0;
WYSW = (*(znaki + 4));
czekaj();
W1 = 1;
W2 = 0;
WYSW = (*(znaki + 3));
czekaj();
W2 = 1;
W3 = 0;
WYSW = (*(znaki + 2));
czekaj();
W3 = 1;
W4 = 0;
WYSW = (*(znaki + 1));
czekaj();
W4 = 1;
}
}
Przykład 3.4.BAS
Wysw Alias P0
W1 Alias P2.0
W2 Alias P2.1
W3 Alias P2.2
W4 Alias P2.3
Do
Reset W1
Wysw = Lookup(0 , Znaki)
Waitms 100
Set W1
Reset W2
Wysw = Lookup(1 , Znaki)
Waitms 100
Set W2
Reset W3
Wysw = Lookup(2 , Znaki)
Waitms 100
Set W3
Reset W4
Wysw = Lookup(3 , Znaki)
Waitms 100
Set W4
Loop
Znaki:
Data 192 , 249 , 164 , 176 , 153 , 146 , 130 , 248 , 128 , 144 , 136 ,
131 , 198 , 161 , 134 , 142
End
Efektem działania powyższego programu jest wyświetlanie
cyfr na kolejnych wyświetlaczach od prawej do lewej strony. Celowo zastosowano
duże opóˇnienie w przełączaniu wyświetlaczy, aby lepiej uzmysłowić zasadę
sterowania multipleksowanego. Przy tak dużym opóˇnieniu dokładnie widać
kolejno zapalane segmenty. Następny przykład zawiera już normalne opóˇnienie.
Przykład 3.5.ASM
NAME P03_05_ASM_SRC
$INCLUDE (ATMEL/REG8252.INC)
P03_05_ASM SEGMENT CODE
RSEG P03_05_ASM
WYSW EQU P0
W1 EQU P2.0
W2 EQU P2.1
W3 EQU P2.2
W4 EQU P2.3
MOV DPTR,#ZNAKI
PETLA:
CLR W1
MOV A,#9
MOVC A,@A+DPTR
MOV WYSW,A
MOV A,#5
ACALL CZEKAJ
SETB W1
CLR W2
MOV A,#8
MOVC A,@A+DPTR
MOV WYSW,A
MOV A,#5
ACALL CZEKAJ
SETB W2
CLR W3
MOV A,#7
MOVC A,@A+DPTR
MOV WYSW,A
MOV A,#5
ACALL CZEKAJ
SETB W3
CLR W4
MOV A,#6
MOVC A,@A+DPTR
MOV WYSW,A
MOV A,#5
ACALL CZEKAJ
SETB W4
SJMP PETLA
CZEKAJ:
MOV R0,A
L20:
MOV R6,#248
L22:
DJNZ R6,L22
MOV R6,#248
L21:
DJNZ R6,L21
DJNZ R0,L20
RET
ZNAKI:
DB 192,249,164,176,153,146,130,248,128,144,136,131,198,161,134,142,0
END
Przykład 3.5.C
#include <ATMEL\REG8252.H>
#define WYSW P0
char code znaki[17] = {192,249,164,176,153,146,130,248,128,144,136,131,198,161,134,142,0};
sbit W1 = P2^0;
sbit W2 = P2^1;
sbit W3 = P2^2;
sbit W4 = P2^3;
void czekaj(char k)
{
char x,y,z;
for (z = k; z > 0; --z)
for (x = 10; x > 0; --x)
for (y = 47; y > 0; --y);
}
void main(void)
{
code char * pznaki;
pznaki = &znaki;
while(1)
{
W1 = 0;
WYSW = (*(znaki + 4));
czekaj(5);
W1 = 1;
W2 = 0;
WYSW = (*(znaki + 3));
czekaj(5);
W2 = 1;
W3 = 0;
WYSW = (*(znaki + 2));
czekaj(5);
W3 = 1;
W4 = 0;
WYSW = (*(znaki + 1));
czekaj(5);
W4 = 1;
}
}
Przykład 3.5.BAS
Wysw Alias P0
W1 Alias P2.0
W2 Alias P2.1
W3 Alias P2.2
W4 Alias P2.3
Do
Reset W1
Wysw = Lookup(0 , Znaki)
Waitms 5
Set W1
Reset W2
Wysw = Lookup(1 , Znaki)
Waitms 5
Set W2
Reset W3
Wysw = Lookup(2 , Znaki)
Waitms 5
Set W3
Reset W4
Wysw = Lookup(3 , Znaki)
Waitms 5
Set W4
Loop
Znaki:
Data 192 , 249 , 164 , 176 , 153 , 146 , 130 , 248 , 128 , 144 , 136 ,
131 , 198 , 161 , 134 , 142
End
Efektem działania tego programu jest już stabilny napis. Stało się tak
dzięki bezwładności ludzkiego oka. Jednak wadą sterowania multipleksowanego
jest, co zapewne widać, mniejsza jasność świecenia wyświetlaczy.
W bieżącym przykładzie zmodyfikowana została procedura opóˇniająca.
Liczbę powtórzeń pętli opóˇniającej możemy teraz wybrać z zakresu od 1
do 256, poprzez umieszczenie w akumulatorze przed wywołaniem procedury
liczby określającej ilość powtórzeń. Jedno powtórzenie procedury trwa
ok. 1ms przy zegarze 12MHz. Tak więc procedura zapewnia opóˇnienie od
1 do 256ms.
|
Ostatnio na forum:
|