11.12.2018 05:07
Tutoriale
AVR
Projektowanie płytek
Artykuły
Bezpieczne sterowanie przekaźnikami przez LPT
Multipleksowanie wyświetlaczy LED
Oświetlenie LED
Silniki krokowe
Wyświetlacze LCD
Fotorelacje
Wytrawiarka do płytek
Tester kabli LAN
Linijka świetlna LED
Zrób sobie biurko
Soft-start do 12V DC
Gościnne Pęseta pomiarowa
Pokrywa do akwarium PCV

W przygotowaniu
7. Zegar cyfrowy
Ukończone: 80%

Aktualizacja: 29.06.2008
9. Regulator prędkości ...
Ukończone: 50%

Aktualizacja: 02.11.2008
Użytkowników Online
Gości Online: 1
Brak Użytkowników Online

Zarejestrowanch Uzytkowników: 132
Najnowszy Użytkownik: donprezes

Obsługa wyświetlaczy LED w C
Przedstawiam długo oczekiwany Tutorial na temat obsługi wyświetlaczy LED. Artykuł oparty będzie na jednym podwójnym wyświetlaczu 7-segmentowym o wspólnej katodzie i procesorze Attiny2313. Z powodzeniem może być wykorzystany na prawie każdym innym procesorze AVR (ograniczeniem jest tylko ilość wyprowadzeń). Oczywiście oba wyświetlacze będą multipleksowane.

Zanim zaczniemy!

Poniższy tutorial będzie zasadniczo zlepkiem wiedzy z dwóch poprzednich moich artykułów. Zanim przystąpimy do pracy, radzę się z nimi zapoznać:
Podłączenie wyświetlacza LED

Zastosowany przeze mnie podwójny wyświetlacz posiada wspólną katodę. Oznacza to, że jego poszczególne segmenty zapalamy podając na nie stan wysoki. Wyświetlacz posiada 18 wyprowadzeń, czyli tak na prawdę są to dwa osobne wyświetlacze w jednej obudowie. Dlatego też będę musiał dokonać zewnętrznych połączeń poszczególnych linii (zielone przewody na następnym zdjęciu). Można też spotkać wyświetlacze podwójne, potrójne czy poczwórne z mniejszą ilością wyprowadzeń. W takim przypadku połączenia poszczególnych segmentów są już zrobione fabrycznie przez producenta. Bez znaczenia co tak na prawdę kupicie, zasada pracy z wyświetlaczami jest identyczna.

Poniżej przedstawiam schemat połączeń mojego wyświetlacza i odpowiadający mu model rzeczywisty na uniwersalnej płytce testowej:



Multipleksowanie

Jak widać, poszczególne segmenty (A, B itd.) połączone są ze sobą, tak więc sygnał będzie podawany na oba wyświetlacze jednocześnie.

Programujemy


Aby ułatwić sprawę, udostępniam plik wyswietlacze.h . Zdefiniowałem w nim kształty wszystkich cyfr, które zapisywane są w pamięci danych procesora. Aby dostać się do danej cyfry, wystarczy użyć funkcji cyfra(arg), która za argument przyjmuje liczby od 0 do 10. Pod pozycją 10 umieściłem całkowite wygaszenie wyświetlacza.

Szkielet programu posiada następującą postać:

/////////////////////////////////////////////////////////////////
// LedTutorial.c - plik główny tutoriala LED
//
// Autor: Ravender Kompilator: WinAVR
// Strona: www.wkretak.pl
/////////////////////////////////////////////////////////////////

#include <avr/interrupt.h>
#include <inttypes.h>
#include <wyswietlacze.h> //mój plik nagłówkowy

int main(void)
{

while(1)
{
}

return 0;
}

Na początku wyświetlimy kilka cyfr na jednym wyświetlaczu, aby mieć pewność, że wszystko jest dobrze podłączone.

W celu wysłania na port B kształtu cyfry np. 4, należy użyć następującej składni (pod warunkiem, że wykorzystuje się mój plik nagłówkowy wyswietlacze.h):

PORTB = cyfra(4);
W tym momencie nic się nie stanie, bo nie aktywowaliśmy żadnego wyświetlacza (a raczej tranzystora nim sterującego). Aby wyświetlić cyfrę na pierwszym wyświetlaczu, ustawiam jego port w stan wysoki:

PORTD |= (1<<0); // port PD0 w stan wysoki
Multipleksowanie


Aby nieco uatrakcyjnić projekt, możemy pokusić się o umieszczenie prostej funkcji FOR, która wyświetli wszystkie dostępne cyfry:

uint8_t i;
(...)

for (i=0; i<10; i++)
{
PORTB = cyfra(i);
_delay_ms(1000); // opóźnienie 1s między kolejnymi cyframi
}

Cały program wygląda tak:

#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/delay.h>
#include <wyswietlacze.h> //mój plik nagłówkowy

uint8_t i;

int main(void)
{

DDRB = 255; //cały port jako wyjściowy
DDRD |= (1<<0)|(1<<1); //porty PD0 i PD1 również jako wyjścia

PORTD |= (1<<0); //aktywowanie pierwszego wyświetlacza

while(1)
{
for (i=0; i<10; i++)
{
PORTB = cyfra(i);
_delay_ms(1000); // opóźnienie 1s między kolejnymi cyframi
}

}

return 0;
}

Jeśli podamy stan wysoki również na drugi tranzystor, włączone zostaną oba wyświetlacze. Dodajmy wiec dla przykładu linijkę:

PORTD |= (1<<0); //aktywowanie pierwszego wyświetlacza
PORTD |= (1<<1); //aktywowanie drugiego wyświetlacza

Film na YouTube

W tym momencie potrafimy już aktywować wyświetlacz i wyświetlić na nim cyfrę. Niestety sposób w jak połączone są wyświetlacze sprawia, że na obu można wyświetlać tylko tą samą cyfrę. Dlatego pokażę, jak praktycznie zrealizować multipleksowanie wyświetlaczy, aby wyświetlać różne cyfry.

Multipleksowanie wyświetlaczy

Naszym celem będzie wyświetlenie liczby dwucyfrowej na dwóch połączonych ze sobą wyświetlaczach LED. Aby to osiągnąć, należy zrealizować następujące podpunkty:
  1. rozdzielić liczbę dwucyfrową, na poszczególne cyfry. Cyfra dziesiątek zostanie wyświetlona na wyświetlaczu lewym, a cyfra jedności na prawym,
  2. wykorzystując przerwania, należy przełączać na przemian tranzystory z dużą częstotliwością aby oszukać oko i wywołać wrażenie, że oba wyświetlacze pracują jednocześnie,
  3. trzeba wykryć, który wyświetlacz jest aktywny i wysłać na niego odpowiednio cyfrę dziesiątek lub jedności.
Aby nieco ułatwić pracę, rozpocznę pisanie programu od skonfigurowania timera i przerwań. Nie będę tutaj skupiał się na wyjaśnieniach aby nie powtarzać tego, co znajduje się w artykule o przerwaniach.

By oszukać oko, należy odświeżać wyświetlacz z częstotliwością około 50Hz, czyli dla dwóch wyświetlaczy daje to częstotliwość 100Hz. Wykorzystując program TimerCycles (do pobrania z działu Download) obliczyłem, że dla kwarcu 4MHz który wykorzystuję, muszę policzyć do 40000, 5000 lub 625 dla różnych preskalerów.

Multipleksowanie


Tak czy siak muszę zastosować licznik 16 bitowy. Poniżej kod, który konfiguruje timer 16bitowy.

/////////////////////////////////////////////////////////////////
// LedTutorial.c - plik główny tutoriala LED
//
// Autor: Ravender Kompilator: WinAVR
// Strona: www.wkretak.pl
/////////////////////////////////////////////////////////////////

#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/delay.h>
#include <wyswietlacze.h> //mój plik nagłówkowy

int main(void)
{

DDRB = 255; //cały port jako wyjściowy
DDRD |= (1<<0)|(1<<1); //porty PD0 i PD1 również jako wyjścia

TCCR1B |= (1 << WGM12); // Ustawia timer1 w tryb CTC
OCR1A = 40000; // Ustawia wartość pożądaną na 100Hz dla preskalera 1
TCCR1B |= (1 << CS10); // Ustawia timer z preskalerem Fcpu/1
TIMSK |= (1 << OCIE1A); // Zezwolenie na przerwania dla CTC
sei(); // Zezwolenie globalne na przerwania

while(1)
{

}

return 0;
}

ISR(TIMER1_COMPA_vect)
{
//Obsługa przerwania
}

Jak widać, jest on praktycznie żywcem skopiowany (z drobnymi zmianami) z tutoriala o przerwaniach. Licznik będzie się zwiększał do 40000 a gdy doliczy, wywołane zostanie przerwanie. W przerwaniu umieszczę instrukcje przełączające tranzystory. Aby łatwo rozróżniać, który wyświetlacz jest aktywny, wprowadziłem zmienną WYSW, przyjmującą wartość 0 lub 1. Poniżej kod obsługi przerwania:

(...)
volatile uint8_t wysw; // zmienna oznaczająca numer aktywnego wyświetlacza
(...)


switch (wysw)
{
case 0:
PORTD &= ~(1 << 0); //zeruje bit 0 portu D - wyłącza wyświetlacz nr 1
PORTD |= (1 << 1); //ustawia bit 1 portu D - włącza wyświetlacz nr 2
wysw++;
break;

case 1:
PORTD &= ~(1 << 1); //ustawia bit 0 portu D - włącza wyświetlacz nr 1
PORTD |= (1 << 0); //zeruje bit 1 portu D - wyłącza wyświetlacz nr 2
wysw=0;
break;
}

Jeśli zmienna WYSW = 0, wtedy uruchamiany jest wyświetlacz dziesiątek a gaszony jednostek, a dla WYSW=1 sytuacja jest odwrotna. Pomijam już fakt tego, że ten sam efekt można uzyskać na milion lepszych sposobów (rotacje bitów w porcie itp.) ale żeby nie zaciemniać ogólnej koncepcji, zarzucę na to zasłonę milczenia :).

Pozostało nam wyświetlić na wyświetlaczach jakąś liczbę. Niech będzie to liczba 24. Zadeklaruję sobie trzy zmienne;

uint8_t liczba = 24;
uint8_t dziesiatki;
uint8_t jednosci;

Aby rozdzielić liczbę 24 na cyfry, należy przeprowadzić następujące obliczenia:

dziesiatki = liczba / 10; //ponieważ 'dziesiatki' to typ całkowity, zostanie wpisana tylko cyfra 2, czyli część całkowita z dzielenia
jednosci = liczba % 10; //a do jednostek zostanie wpisana reszta z dzielenia modulo 10, czyli 4;

Cały kod przedstawiam poniżej:

/////////////////////////////////////////////////////////////////
// LedTutorial.c - plik główny tutoriala LED
//
// Autor: Ravender Kompilator: WinAVR
// Strona: www.wkretak.pl
/////////////////////////////////////////////////////////////////

#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/delay.h>
#include <wyswietlacze.h> //mój plik nagłówkowy

volatile uint8_t wysw; // zmienna oznaczająca numer aktywnego wyświetlacza
uint8_t liczba = 24;
uint8_t dziesiatki;
uint8_t jednosci;

int main(void)
{

DDRB = 255; //cały port jako wyjściowy
DDRD |= (1<<0)|(1<<1); //porty PD0 i PD1 również jako wyjścia

TCCR1B |= (1 << WGM12); // Ustawia timer1 w tryb CTC
OCR1A = 40000; // Ustawia wartość pożądaną na 100Hz dla preskalera 1
TCCR1B |= (1 << CS10); // Ustawia timer z preskalerem Fcpu/1
TIMSK |= (1 << OCIE1A); // Zezwolenie na przerwania dla CTC
sei(); // Zezwolenie globalne na przerwania

PORTB = cyfra (2);

dziesiatki = liczba / 10; //ponieważ 'dziesiatki' to typ całkowity, zostanie wpisana tylko cyfra 2, czyli część całkowita z dzielenia
jednosci = liczba % 10; //a do jednostek zostanie wpisana reszta z dzielenia modulo 10, czyli 4;

while(1)
{

}

return 0;
}

ISR(TIMER1_COMPA_vect)
{
switch (wysw)
{
case 0:
PORTD &= ~(1 << 0); //zeruje bit 0 portu D - wyłącza wyświetlacz nr 1
PORTD |= (1 << 1); //ustawia bit 1 portu D - włącza wyświetlacz nr 2
PORTB = cyfra(dziesiatki);
wysw++;
break;

case 1:
PORTD &= ~(1 << 1); //ustawia bit 0 portu D - włącza wyświetlacz nr 1
PORTD |= (1 << 0); //zeruje bit 1 portu D - wyłącza wyświetlacz nr 2
PORTB = cyfra(jednosci);
wysw=0;
break;
}
}

Efekt działania programu jest następujący:

Multipleksowanie LED


Powyższy kod można łatwo zmodyfikować by wyświetlać cyfry na większej ilości wyświetlaczy. Należy wtedy dodać więcej warunków CASE. Zwiększa się też liczba obliczeń rozbicia cyfr. Poniżej przedstawiam sposób obliczenia cyfr dla liczby trzycyfrowej (z innego programu). Operuje się tutaj tylko operatorem dzielenia i dzielenia modulo.

cyfra1 = (ustawiony/100); //setki
cyfra2 = (ustawiony/10)%10; //dziesiatki
cyfra3 = ustawiony%10; //jednosci

Poniżej przedstawiam jeszcze kod, który sobie zlicza od 0 do 99 i obliczenia wyświetla na wyświetlaczach.

/////////////////////////////////////////////////////////////////
// LedTutorial.c - plik główny tutoriala LED
//
// Autor: Ravender Kompilator: WinAVR
// Strona: www.wkretak.pl
/////////////////////////////////////////////////////////////////

#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/delay.h>
#include <wyswietlacze.h> //mój plik nagłówkowy

volatile uint8_t wysw; // zmienna oznaczająca numer aktywnego wyświetlacza
uint8_t liczba = 0;
volatile uint8_t dziesiatki;
volatile uint8_t jednosci;

int main(void)
{

DDRB = 255; //cały port jako wyjściowy
DDRD |= (1<<0)|(1<<1); //porty PD0 i PD1 również jako wyjścia

TCCR1B |= (1 << WGM12); // Ustawia timer1 w tryb CTC
OCR1A = 40000; // Ustawia wartość pożądaną na 100Hz dla preskalera 1
TCCR1B |= (1 << CS10); // Ustawia timer z preskalerem Fcpu/1
TIMSK |= (1 << OCIE1A); // Zezwolenie na przerwania dla CTC
sei(); // Zezwolenie globalne na przerwania

while(1)
{
dziesiatki = liczba / 10;
jednosci = liczba % 10;
_delay_ms(100); // przerwa między liczeniem
if (liczba == 99) {liczba = 0;} else {liczba++;} //jeśli doliczy do 99 to licznik się zeruje
}

return 0;
}

ISR(TIMER1_COMPA_vect)
{
switch (wysw)
{
case 0:
PORTD &= ~(1 << 0); //zeruje bit 0 portu D - wyłącza wyświetlacz nr 1
PORTD |= (1 << 1); //ustawia bit 1 portu D - włącza wyświetlacz nr 2
PORTB = cyfra(dziesiatki);
wysw++;
break;

case 1:
PORTD &= ~(1 << 1); //ustawia bit 0 portu D - włącza wyświetlacz nr 1
PORTD |= (1 << 0); //zeruje bit 1 portu D - wyłącza wyświetlacz nr 2
PORTB = cyfra(jednosci);
wysw=0;
break;
}
}

Film na YouTube


Zakończenie

To tyle jeśli chodzi o multipleksowanie wyświetlaczy. W celu utrwalenia sobie materiału proponuję zbudowanie układu wyświetlającego liczby czterocyfrowe. Kolejną czynnością może być zbudowanie zegara lub woltomierza.







Dodane przez Ravender dnia 01.03.2009 18:36 · 2 Komentarzy · 36424 Czytań · Drukuj
Komentarze
nelik1987 dnia 03.06.2009 21:36
Doskonały opis, przygotowany dla prawdziwego laika, naprawdę gratuluję. Sam również piszę (a raczej pisałem teraz nie mam czasu) tutoriale dla początkujących tak by pomóc innym. Jeszcze raz gratuluję opisu oby tak dalej czekam na więcej takich opisów !!smiley
dawid1215 dnia 14.11.2009 01:21
Właśnie taki toturial jest w sam raz dla kogoś kto się nie zna a chciałby zacząć przygodę z elektroniką.
Oby więcej takich toturiali, czekam na kolejne.
Pozdrawiam.
Dodaj komentarz
Zaloguj się, żeby móc dodawać komentarze.
Oceny
Dodawanie ocen dostępne tylko dla zalogowanych Użytkowników.

Proszę się zalogować lub zarejestrować, żeby móc dodawać oceny.

Brak ocen.
Logowanie
Nazwa Użytkownika

Hasło



Zapomniane hasło?
Wyślemy nowe, kliknij TUTAJ.

Newsletter
Bądź nowoczesny! Info o nowościach na e-mail. Zapisz się i nie przegap niczego!



Ilość subskrypcji: 2455
Stats
1222640 Unikalnych wizyt