Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.
Pokazywanie postów oznaczonych etykietą Tips-Tricks. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą Tips-Tricks. Pokaż wszystkie posty

niedziela, 13 marca 2011

Zmieniaj funkcje pinów w trakcie pracy programu!


Autor: Dondu

Początkujący projektanci z braku doświadczenia (co jest naturalne) bardzo często wychodzą z założenia, że funkcjonalność danego pinu mikrokontrolera jest ustawiana gdzieś na początku programu i nie podlega zmianom w trakcie jego działania.

Inspiracją do napisania tego artykułu było pytanie zadane przez kol. Bonczi:


Bonczi
Czy przypadkiem zbieranie szumów na jednym z wyprowadzeń ADC nie będzie wpływać na dokładność pomiaru reszty multipleksowanych kanałów ADC?

Pytam bo w artykule o ADC jest powiedziane, że nawet nieużywane kanały ADC powiiny zostać jakoś spolaryzowane.


To bardzo dobre pytanie!

Pytanie zostało zadane w artykule dot. generatora liczb losowych wykonanego za pomocą pomiarów jednego z pinów ADC niepodłączonego do niczego i z wyłączonym rezystorem pull-up. Taki pin staje się antenką zbierającą wszelkie zakłócenia. Pisałem o tym w wielu miejscach, a w szczególności:

Zakłócenia zbierane przez jeden z tak wykorzystanych pinów ADC mogą (lecz nie muszą) być przyczyną interferencji zakłóceń na sąsiednich pinach ADC. Nie da się tutaj generalizować skutków, ponieważ zależą one od sposobu wykonania projektu i środowiska, w którym pracuje.

W przypadku generatora liczb losowych wykorzystujemy zakłócenia do generowania losowych liczb. Kol. Bonczi zauważył, że istnieje tutaj wewnętrzna sprzeczność interesów, gdy chcemy jednocześnie używać jeden kanał (pin) przetwornika ADC do generowania liczb losowych, a inne do pomiarów innych sygnałów analogowych.

Co w takiej sytuacji zrobić? Odpowiedź jest bardzo prosta:

Zmieniaj funkcje pinów w trakcie pracy programu!

To powszechna praktyka, a bardzo często wręcz konieczność, bez której wiele projektów byłoby znacznie bardziej skomplikowanych, gdyby nie wykorzystywały zmian funkcjonalności pinów w trakcie realizacji programu.

Jak więc powinniśmy rozwiązać problem poruszony przez kol. Bonczi?




W ten sposób, "antenka" włączona jest tylko w określonym przedziale czasu, gdy nie dokonujemy innych pomiarów za pomocą ADC niż pomiar na potrzeby generatora liczba losowych. Jeżeli więc wykonywać będziesz jakieś pomiary na pozostałych kanałach ADC, antenka będzie spolaryzowana np. wewnętrznym rezystorem pull-up i nie będzie zbierała zakłóceń.

Taki algorytm może jednak spowodować, że potencjał napięcia na pinie odpowiedzialnym za generowanie liczb losowych nie będzie już tak bardzo losowy jak w przypadku ciągłego jego pozostawienia w formie "antenki" zbierającej zakłócenia. Wynika to z faktu, iż tuż przed dokonaniem pomiaru włączamy rezystor pull-up, który ładuje nam wszelkie wewnętrzne ukryte pojemności związane z częścią wejściową pinu.

Co więc możemy zrobić? Na przykład dodać opóźnienie:




A jeżeli nie możemy dodać opóźnienia lub nie daje to odpowiednio losowych zakłóceń na pinie wejściowym generatora liczb losowych?

Niektóre mikrokontrolery mają różne struktury wewnętrzne wybranych pinów wejściowych ADC (kanałów). Przykładem takiego mikrokontrolera jest mikrokontroler ATmega8, który zawiera 6 (w wersji obudowy DIP) lub 8 (w wersjach pozostałych) kanałów przetwornika ADC.

Część analogowa tego mikrokontrolera (w tym przetwornik ADC) jest zasilana z osobnego pinu, którym jest AVcc. Ale są wyjątki:




Piny ADC4 i ADC5 są inaczej zasilane niż pozostałe piny wejściowe przetwornika ADC. Jest to związane z ich szczególną funkcjonalnością alternatywną, jaką jest przypisanie im funkcji interfejsu komunikacyjnego TWI (I²C):



Ponieważ zasilanie wewnętrznej struktury tych pinów jest realizowane z pinu zasilającego pozostałą (cyfrową) część mikrokontrolera możemy się spodziewać, że pomiary będą obarczone większym błędem niż na pozostałych pinach ADC. W związku z tym piny te należy używać do pomiarów 10-bitowych tylko wtedy, gdy już nie mamy innego wyjścia.

Jednak w przypadku generatora liczb losowych zakłócenia na pinie pomiarowym przeznaczonym do tworzenia liczb losowych, są nam "na rękę" stąd w przypadku, o którym pisze kol. Bonczi warto jest podzielić funkcjonalności w następujący sposób:
  • ADC0-ADC3: piny pomiarowe o dużej dokładności,
  • ADC4: pin pomiarowy o możliwych większych błędach niż ADC0-ADC3,
  • ADC5: pin pomiarowy generatora liczb losowych,
  • ADC6-ADC7:  piny pomiarowe o dużej dokładności (w obudowach innych niż DIP).


Odległość "antenki" od pozostałych pinów

Odległość pinu z antenką od innych pinów pomiarowych także może mieć wpływ na interferencję zakłóceń. Dlatego jeżeli masz możliwość wyboru, powinieneś tak rozplanować podłączenie kanałów ADC, by leżały możliwie daleko od siebie, a na PCB były oddzielone polygonem masy:




Usypianie

Należy także pamiętać o możliwościach związanych z odpowiednim trybie usypiania na czas pomiaru ADC dla pinów innych niż pomiar dla potrzeb generatora liczb losowych. W mikrokontrolerach AVR tym trybem jest ADC Noise Reduction mode.


Podsumowanie

W ten sposób dzięki:
  • odpowiedniemu algorytmowi zmieniającemu funkcje pinu w trakcie pracy mikrokontrolera,
  • odpowiedniemu przydzieleniu pinów pomiarowych,
  • usypianiu mikrokontrolera na czas pomiaru,
minimalizujemy wpływ antenki zbierającej zakłócenia na wyniki pomiarów na innych pinach ADC.



Jakie inne przypadki zmiany funkcji pinu w trakcie działania programu chcecie, aby zostały omówione?


Czekam na propozycje w komentarzach.

Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

piątek, 11 marca 2011

LCD HD44780 na 3 pinach z 74HC595


Autor: Sheep94
Redakcja + dodatki: dondu

Na pewno każdy z nas tworząc swój projekt spotkał się z problemem brakujących pinów procesora. Przykładowo - podłączyliśmy już termometry, klawiaturę matrycową (dzięki której już zaoszczędziliśmy kilka pinów), kilka diod LED informujących nas o stanie pracy mikrokontrolera ...

... ale musimy jeszcze podpiąć ten nieszczęsny wyświetlacz do procesora, który potrzebuje, aż 6 pinów lub nawet 7 (gdy podłączymy linię RW do wyświetlacza w celu odczytania jego zawartości).

Postawiłem zatem pytanie:

Jak obsłużyć wyświetlacz używając mniejszej ilości pinów procesora?

Przyszło mi na myśl rozwiązanie, by wykorzystać do obsługi wyświetlacza rejestr przesuwny 74HC595, do którego wysyłać będziemy szeregowo informację (8 bitów), a po wysłaniu wszystkich bitów każemy mu ustawić odebraną wartość na swoich wyjściach.

Zalety:
  • zyskujemy co najmniej 3 piny procesora, które możemy przeznaczyć na inne działanie.

Wady:
  • wzrost objętości programu (~200 bajtów, w porównaniu do obsługi wyświetlacza za pomocą 6 pinów),
  • konieczność umieszczenia dodatkowego układu scalonego na płytce (między mikrokontrolerem a wyświetlaczem musimy umieścić rejestr 74HC595) + jego koszt (0,60zł w 2012r.).

Krótkie objaśnienie zasady działania rejestru 74HC595.


Datasheet: 74HC595, 74HCT595

Rejestr sterowany jest za pomocą 3 pinów:
  • DS - (data serial input) za pomocą którego odbiera wysłane szeregowo bity do ukrytego rejestru SHIFT REGISTER.
  • SHCP - pin, który podczas zbocza narastającego (przejście ze stanu niskiego w stan wysoki) zapamiętuje w buforze pamięci stan pinu DS i przesuwa informację w SHIFT REGISTER, o jeden bit w celu ustąpienia miejsca następnej porcji informacji. Stan niski (0) musi nastąpić przed wprowadzeniem kolejnych bitów.
  • STCP - pin jest w stanie niskim podczas wprowadzania danych do SHIFT REGISTER  Natomiast zbocze narastające powoduje pojawienie się zawartości rejestru SHIFT REGISTER do rejestru STATE OUTPUTS. Jeżeli sygnał OE jest w stanie niskim, to informacja ta od razu pojawi się  na pinach Q0 - Q7.

Układ posiada 8 wyjść, do których możemy podłączyć dowolne urządzenie w standardzie TTL.

Musimy znać jeszcze przeznaczenie pozostałych pinów:
  • OE - (Ouput Enable) - musi występować stan niski (0), by móc sterować rejestrem. Możemy spokojnie podłączyć w naszym projekcie na stałe do masy.
  • MR  (Master Reset) - musi występować stan wysoki (1), by rejestr nie był w stanie ciągłego resetu. Możemy spokojnie podłączyć w naszym projekcie na stałe do VCC.
  • Q7S - serial data output - w momencie wprowadzania 9 bitu informacji na wyjściu Q7S pojawia się bit informacji wprowadzony jako pierwszy. Dzięki temu sygnałowi możemy podłączyć go do pinu DS kolejnego rejestru przesuwnego, by ułożyć kaskadowo kolejne rejestry. Tym sposobem możemy za pomocą 3 pinów obsłużyć znacznie więcej pinów urządzeń (wielokrotność 8 bitów), które nie wymagają odczytu stanu logicznego (linijka LED, wyświetlacz 7-segmentowy, itp.).

Jaki problem napotkałem podczas pisania tego rozwiązania?

Wszyscy wiemy, że wyświetlaczem możemy sterować w trybie wykorzystującym tylko 4 bitów danych (DB4-DB7). Natomiast podczas obsługi wyświetlacza musimy mu „pokazać”, czy wprowadzamy komendy (stan niski na linii RS), czy wprowadzamy dane do wyświetlenia (stan wysoki linii RS). Do tego, by przesłać młodszą część bajtu, musimy wysterować odpowiednio linię E.


Przykład: HY-1602

Tu powstaje pytanie:

Jak sterować poszczególnymi wyjściami Qn rejestru 74HC595, nie zmieniając jednocześnie stanów na pozostałych liniach wyjściowych rejestru?

Problemu nie ma, gdy chcemy sterować w ten sposób wyjściami mikrokontrolera, ponieważ używamy wtedy operacji bitowych sumy OR, mnożenia AND oraz sumy wyłączającej XOR.

Więcej informacji o operacjach bitowych oraz możliwość ich ćwiczenia online, znajdziesz tutaj: Kurs języka C z kompilatorem CManiak online

Wpadłem na rozwiązanie, aby rejestr posiadał własną zmienną statyczną, którą odczytywałby i prezentował jej zawartość na liniach Q0-Q7. Dalej nie ma już problemu z operacją bitową na zmiennej (dodawanie wartości, wyłączanie poszczególnych bitów).

W moim rozwiązaniu jest to zmienna o nazwie tempdata (nazwa wymyślona na szybko, potem okazało się, że jest w tym trochę prawdy, iż jest to zmienna temporary (tymczasowa) ponieważ przez cały czas sterowania wyświetlaczem następuje zmiana jej zawartości).

Do funkcji sterującej rejestrem wstawiłem 2 argumenty:
  • unsigned char WriteOrErase - która w zależności od stanu 0 lub 1 decyduje o tym, czy wykonujemy dodawanie bitów do zmiennej za pomocą operacji bitowej OR | (1), lub wyłączamy poszczególne bity za pomocą mnożenia AND oraz koniunkcji bitowej ~(0).
  • unsigned char data - zmienna, która w zależności od wartości zmiennej lokalnej WriteOrErase dodaje lub usuwa bity ze zmiennej statycznej tempdata.

Reszta funkcji polega na odczycie poszczególnych bitów ze zmiennej tempdata i wystawienie jej zawartości na pinach Q0-Q7, oraz wysterowaniu odpowiednio sygnałami pinów rejestru.

Całość prezentuje się mniej więcej tak:

// DS_x, STCP_x, SHCP_x to nazwy sygnałów sterujących rejestrem 74HC595,
// gdzie x to stan logiczny wystawiany do rejestru

void rejestr(unsigned char data, unsigned char WriteOrErase)
{
 if(WriteOrErase==1)
  tempdata=(tempdata|data);
 else
  tempdata&=~(data);
 STCP_0;
 SHCP_0;
 if(tempdata & 0x80)DS_1;else DS_0;
 SHCP_1;
 SHCP_0;
 if(tempdata & 0x40)DS_1;else DS_0;
 SHCP_1;
 SHCP_0;
 if(tempdata & 0x20)DS_1;else DS_0;
 SHCP_1;
 SHCP_0;
 if(tempdata & 0x10)DS_1;else DS_0;
 SHCP_1;
 SHCP_0;
 if(tempdata & 0x08)DS_1;else DS_0;
 SHCP_1;
 SHCP_0;
 if(tempdata & 0x04)DS_1;else DS_0;
 SHCP_1;
 SHCP_0;
 if(tempdata & 0x02)DS_1;else DS_0;
 SHCP_1;
 SHCP_0;
 if(tempdata & 0x01)DS_1;else DS_0;
 SHCP_1;
 STCP_1;
}

Jeżeli na przykład na pinie Q7 chcesz ustawić jedynkę lub zero, wystarczy wywołać funkcję:
rejestr(0x80,1);  //ustaw 1 na Q7  
rejestr(0x80,0);  //ustaw 0 na Q7

ale możesz także użyć zdefiniowanych:
Q71;  //ustaw 1 na Q7  
Q70;  //ustaw 0 na Q7

Gotowe.

Możemy już niezależnie sterować  8 pinami z rejestru. Reszta kodu oparta jest na przykładzie z tego kursu. Autor wyraził zgodę na publikację zmodyfikowanego kodu na potrzeby rozwiązania obsługi wyświetlacza LCD z wykorzystaniem mniejszej ilości pinów procesora.

Dopisek Dondu (2012r.):
Wspomniany wyżej kurs oparty jest o przestarzałe środowisko WINAvr, które wymaga tworzenia we własnym zakresie pliku makfile, a który często jest powodem problemów początkujących. Jeżeli będziesz korzystał z tego kursu, to używaj co najmniej AVR Studio 4 , które automatycznie tworzy plik makefile i co najważniejsze zawsze poprawnie. Kurs AVR znajdziesz także na naszym blogu:  Drzaśkowy pamiętnik, czyli kurs mikrokontrolerów AVR.





Którą wersję rejestru 74xx595 wybrać?

W zależności od parametrów Twojego urządzenia możesz wybrać różne wersje tego układu. W niniejszym artykule wybrałem wersję HC (74HC595) jako tanią i najbardziej wszechstronną. Ale można wykorzystać inne wersje: Logic family




Biblioteka

W załączniku zamieszczone zostały 3 wersje biblioteki.

Biblioteka jest uniwersalna i może być stosowana na dowolnym 
mikrokontrolerze np. AVR, PIC, STM, itd.

Na potrzeby niniejszego artykułu posłużę się mikrokontrolerem ATmega8.

Biblioteka składa się z dwóch plików:
  • hd44780.h (plik nagłówkowy),
  • hd44780.c (plik z funkcjami obsługi wyświetlacza).

Rejestr przesuwny 74HC595 może być podłączony pod praktycznie każdy pin, który może być wyjściem cyfrowym mikrokontrolera. Podłączane sygnały to SHCP, STCP oraz DS (patrz schematy poniżej).

Aby wykorzystać bibliotekę, musisz ją poinformować, do których pinów mikrokontrolera podłączyłeś te trzy sygnały. Wykonuje się to poprzez zmianę definicji w pliku nagłówkowym hd44780.h:

//DS
#define pin_DS     PD0
#define DDR_DS     DDRD
#define PORT_DS    PORTD

//STCP
#define pin_STCP   PD1
#define DDR_STCP   DDRD
#define PORT_STCP  PORTD

//SHCP
#define pin_SHCP   PD2
#define DDR_SHCP   DDRD
#define PORT_SHCP  PORTD


Niektóre wyświetlacze LCD ze sterownikiem HD44780 wymagają opóźnienia pomiędzy włączeniem zasilania, a jego inicjalizacją. W pliku nagłówkowym hd44780.h znajdziesz do tego komentarz oraz odpowiednią definicję:

//Niektóre wyświetlacze wymagają opóźnienia pomiędzy włączeniem
//zasilania, a inicjalizacją. Jeżeli chcesz włączyć opóźnienie usuń znak
//komentarza i podaj liczbę milisekund, sugeruję około 20.
//
//#define LCD_START_DELAY_MS 20

Następnie tak przygotowaną bibliotekę linkujesz na początku programu w ten sposób:

#include "hd44780.h"

Wybrane funkcje dostępne w bibliotece:


Funkcja/definicjaOpis
lcd_init();Inicjuje wyświetlacz po włączeniu zasilania. Jeżeli zdefiniujesz opóźnienie to wykona się ono na początku tej funkcji.
LCD_CLEAR;Definicja wywołująca funkcję kasowania zawartości wyświetlacza.
LCD_LOCATE(x,y);Definicja wywołująca funkcję ustawienia kursora w kolumnie x i wierszu y. Współrzędne liczone są począwszy od zera.
lcd_puts(nazwa_bufora);Funkcja wyświetlająca zawartość tablicy nazwa_bufora[] począwszy od miejsca w którym jest ustawiony kursor. Może to być dowolna inna tablica.
LCD_HOME;Ustawia kursor w pozycji (0,0).
LCD_SHIFT_DISPLAY(kierunek);Przesuwa zawartość wyświetlacza w lewo, gdy kierunek = LCDLEFT lub w prawo, gdy LCDRIGHT.
rejestr(piny, stan);Ustawia jedynkę (gdy stan=1) lub zero (gdy stan=0) na wybranych pinach rejestru 74HC595 (czytaj w artykule powyżej tabelki).

W pliku nagłówkowym znajdziesz także inne funkcjonalności starownika HD44780, a przykład wykorzystania biblioteki znajdziesz w dalszej części artykułu.


Wersja A

Pin RW wyświetlacza podłączony na stałe do masy. Wyjścia rejestru Q6 oraz Q7 są zaprogramowane do obsługi innych urządzeń niezależnie od stanu pracy wyświetlacza.




Pliki biblioteki: LCD-3piny-74hc595-v1-wersja-A.zip



Wersja B

Pin RW wyświetlacza podłączony na stałe do masy. Wyjścia rejestru Q6 oraz Q7 nie są obsługiwane - wersja dla czytelników, którzy walczą o każdy bajt pamięci FLASH.

Schemat ten sam co w wersji A.



Wersja C

Pin RW wyświetlacza podłączony do rejestru. Wyjście rejestru Q7 jest zaprogramowane do obsługi innego urządzenia. Wyjście Q6 jest wykorzystane do LCD. Rozwiązanie to wymaga podłączenia pinu RW do wyjścia rejestru (np.  sytuacja,  w której nie możemy na schemacie poprowadzić masy do RW, a rejestr przesuwny umieściliśmy blisko wyświetlacza).





Pliki biblioteki: LCD-3piny-74hc595-v1-wersja-C.zip




Przykład 

Czas zrealizować jeden z przykładów. Wykorzystamy wersję A biblioteki. W tym celu zmontujemy taki układ:



Zmontowany układ:



Jako przykład wykorzystamy program, który będzie:
  • generował jakieś napisy na LCD, 
  • chował zawartość LCD w prawo lub lewo (z wykorzystaniem funkcji SHIFT wyświetlacza)
  • mrugał LED'ami podpiętymi pod piny Q6 i Q7 rejestru 74HC595.

#include <avr/io.h>
#include <util/delay.h>
#include "hd44780.h"

int main(void)
{

 unsigned char i;
 unsigned char kierunek = 0;
    
 char napis[] = "LCD 3 piny " ;
 char text[]  = "74HC595 ";

 lcd_init();
 LCD_CLEAR;

 while(1)
 {

  _delay_ms(500);
  LCD_LOCATE(5,1);
  lcd_puts(napis);
    
  _delay_ms(500);
  LCD_LOCATE(8,0);
  lcd_puts(text);

  _delay_ms(500);
  LCD_LOCATE(1,1);
  lcd_puts(text);

  _delay_ms(500);
  LCD_LOCATE(1,0);
  lcd_puts(napis);

  _delay_ms(1000);

  //chowamy zawartość wyświetlacza w jedną ze stron
  for(i=0; i<16; i++){
    
    if(kierunek)
     LCD_SHIFT_DISPLAY(LCDLEFT);
    else 
     LCD_SHIFT_DISPLAY(LCDRIGHT);
    
    _delay_ms(50);
  }

  LCD_CLEAR;

  kierunek ^= 1; //zmień kierunek na przeciwny

  //migamy diodami kilka razy
  for(i=0; i<16; i++){

   //LED na pinie Q7  
   if(i & 1) rejestr(0x80,0); //zgaś  gdy i jest nieparzyste
   else      rejestr(0x80,1); //zapal gdy i jest parzyste

   //LED na pinie Q6
   if(i & 1) Q61;             //zgaś  gdy i jest nieparzyste
   else      Q60;             //zapal gdy i jest parzyste

    _delay_ms(100);
  }
 }
}

Projekt do pobrania: Projekt AVR Studio 4 + pliki biblioteki + main.c + plik HEX dla 1MHz


Efekt działania programu:



Jeżeli macie jakiś pomysł na zoptymalizowanie kodu, zaproponowanie zmian - piszcie śmiało w komentarzach.

Pozdrawiam
Sheep94

Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.