mikrokontrolery.net

 

   

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.

 

 

 

 

 

 

 

 

 

 

 
 
 
 

(c) 2004-2008 Radosław Kwiecień
Polityka prywatności