poniedziałek, 30 grudnia 2013

Wyświetlacz przede wszystkim.


Ku pamięci: ctrl + shift + l najprzydatniejszy skrót do wszystkich skrótów ;]

         Odpowiedź na dawno zadane pytanie jest banalna – nigdy nie wiadomo kiedy na gwałtu rety trzeba będzie odkopać dawno zapomniany, czasem nawet trywialny, kawałek działającego kodu. Trzeba będzie dać tylko parę, może nawet jedną, malutką zmianę.
Przy dobrze napisanym kodzie – nie ma problemu, są komentarze, napisane czytelnie, a może nawet w celu utrzymania czytelnego kodu odrobinę nadmiarowo. Przy kiepsko napisanym kodzie jest po prostu na odwrót :)
Najprostszym chyba przykładem jest nie stosowanie makr z avr/io.h skoro wiemy że REFS1 ma numer 7 w rejestrze to zamiast pisać _bv(REFS1) można napisać _bv(7) efekt ten sam. Osobiście nie lubię makra _bv – stąd moim zboczeniem jest albo pisanie własnego makra do bit-write'u albo pisanie po prostu (1<<REFS1) wiem że jest tam ładne przesunięcie bitowe o wartość makra REFS1. ( Przed nim zawsze widnieje jedno z trzech &=~ lub |= lub =^ które jak tłumaczyłem młodszemu bratu ( podstawówka ) zerują wskazane miejsce, ustawiają to miejsce, lub zmieniają to miejsce na odwrotne. )
 
Żeby nie było że jestem gołosłowny: pewnego pięknego dnia zdarzyło mi się pisać parę linijek „na zaraz” które od razu miały wywędrować w świat. Miałem przy sobie kawałek działającego kodu i jedną z popularnych książek – w której w moim egzemplarzu w przykładowym kodzie akurat był błąd w krytycznym dla działania miejscu. Z tej samej książki na szczęście nauczyłem się że warto pisać ładny kod – tak więc mimo że przedsięwzięcie nie było specjalnie udane, to nie było to z winy mojej marnej pisaniny.


A teraz do rzeczy, bo w końcu miał tu pojawić się kawałek kodu!
U siebie na płytce testowej używam wyświetlacza od noki 5110 – jest tani, pancerny i prosty w obsłudze. Tani (~10zł) , czyli tańszy od popularnych alfanumerycznych na x znaków i y linijek, pancerny bo w końcu był w starej nokii i wreszcie prosty w obsłudze bo wykorzystuje SPI w najprostszej postaci ( Serial Perypherial Interface ).

Żeby za dużo nie pisać opiszę co zrobić by napisać „I love Ken!” na wyświetlaczu krok po kroku.
Na koniec okaże się że jeśli nic się na razie nie rozumie, to i tak wystarczy wiedzieć jak działają podstawowe funkcje: lcd_init, lcd_place, lcd_clear, lcd_string, lcd_int – nie trudno się domyślić że init to inicjalizacja wyświetlacza, potem place to ustawienie w którym miejscu chcemy wyświetlać, następnie clear to wyczyszczenie zawartości wyświetlacza, string wypisze nam tekst a int wypisze nam liczbę na ekran. Ważne tylko by nie pomylić int z init :P
Zakładam że stworzyliśmy nowy projekt. Zawsze jest w nim już plik main.c który będzie zawsze naszym plikiem głównym – jak sama nazwa wskazuje.
Mamy zaznaczony projekt w drzewie wyboru po prawej stronie i jest otwarty. Klikamy: ctrl + n by otworzyło nam się okno dodania nowego pliku. Wybieramy typ C/C++ file → header file i klikamy next, dalej dajemy mu nazwę: ansii.h . Następnie identycznie tworzymy n5510.h . Oraz prawie identycznie n5510.c , z tą tylko zmianą że zamiast wybrać header file wybieramy source file .
Mamy więc 3 nowe pliki bez wnętrza.
Najprościej jest ściągnąć teraz moje pliki i przekopiować zawartości. Program wyświetlający „I love Ken!” wygląda tak:

/* Dołączamy biblioteki */
#include <avr/io.h> // Generalna biblioteka do avr
#include <util/delay.h> // Biblioteka do opóźnień
#include "ascii.h" // Biblioteka z znakami ASCII
#include "spi.h" // Biblioteka z komunikacją SPI
#include "n5110.h" // Biblioteka od działania wyświetlacza


int main()
{
spi_init(); // inicjalizacja SPI
lcd_init(); // inicjalizacja LCD

while(1) // Główna pętla
{
lcd_clear(); // wyczyszczenie wyświetlacza
lcd_place(0,0); // wybranie miejsca na wyświetlaczu
lcd_string("I <3 Ken!"); // wyświetlenie tekstu
_delay_ms(300); // pauza 300 ms
}
}

Samo wyświetlanie jest w głównej pętli programu, by pokazać jak może wyglądać ciągłe generowanie tekstu ( w końcu co 300ms odświeża się on :) )

Użytkowanie jak widać bardzo proste. W n5510.h można zmienić podłączone piny do wyświetlacza, nie jest to w spi.h, gdzie jest właściwie tylko dlatego że używam więcej niż jednego urządzenia na spi i wolę mieć każdy pin urządzenia opisany headerze właśnie tego urządzenia.

Trzeba jeszcze pamiętać żeby wyświetlacz podłączyć :P SCE i DC można zmieniać dowolnie.

#define SCE PD7 // ta nóżka „wybiera” użądzenie na magistrali SPI
#define RES PD4 // Reset na SPI
#define DC PD5 // linia wyboru „rodzaju danych” wyświetlacza
#define SDIN PB3 // MOSI
#define SCKL PB5 // CLCK

To tyle. Dalej w przyszłości przybliżę może pobieżnie działanie wyświetlacza oraz działanie funkcji tej prostej biblioteki. Na największą uwagę zasługuje chyba lcd_string(), choćby dlatego że był to pierwszy raz gdy łatwiej było napisać program w taki właśnie sposób :P

W ramach ćwiczenia polecam samemu przepisać kod ;] Pomaga zwłaszcza gdy samemu chce się coś dodać.

Czemu akurat ten kod chciałbym mieć  zanim na dobre zacząłem coś robić? Ponieważ podczas pisania programu który ma wykonywać coś sensownego najprościej jest pisać go kawałkami i sprawdzać na bieżąco. Możemy sprawdzić czy rejestry dobrze się ustawiają, czy komunikacja działa tak jak nam się wydaje że powinna, w którym miejscu działania programu on nagle się zawiesza.
Jeśli miałbym się uczyć jeszcze raz programowania, to ten kod chciałbym mieć od razu dostępny przed pierwszym rozdziałem z instrukcją: skompletuj zestaw, skompiluj całość, wrzuć → działa? To super! Będzie przydawać Ci się non stop. Nie działa? To musiałeś coś zrobić naprawdę bardzo, bardzo źle...

Brak komentarzy:

Prześlij komentarz