czwartek, 4 maja 2017

Wyświetlacz LCD matrycowo punktowy 4.82 mm 4 x 20, DOGM204W-A, Electronic Assembly na 3.3 V.

Poszukując jakiejś alternatywy dla HD44780 natknąłem się przez przypadek na wyświetlacz firmy Electronic Assembly oparty na mało znanym kontrolerze SSD1803A. Wyświetlacz przykuł moją uwagę raz z uwagi na dedykowane zasilanie 3.3 V co w kontekście mikrokontrolerów PIC jest mile widziane a dwa z uwagi na piękne podświetlenie w kolorze bursztynowym. Wyświetlacz jest po za tym bardzo subtelny , grubość zaledwie 2 mm i jest prawie przezroczysty. Do dyspozycji mamy 4 linie po 20 znaków.

Podstawową zaletą jest możliwość zasterowania w kilku trybach : 8bit / 4bit / SPI / I2C, do wyboru do koloru. Poza tym fajne jest wyprowadzenie pinów w postaci szpilek, które bezpośrednio można wlutować w płytkę docelową lub wetknąć w płytkę stykową.


Ze wstępnej analizy materiałów wynika, że wyświetlacz jest bardzo szybki.
Czasy zapisu do sterownika są rzędu pojedyńczych nanosekund. Wygląda na to , że mamy do czynienia z rakietą.
Delikatnym minusem lub plusem w zależności od punktu widzenia jest konieczność dokupienia płytki podświetlającej . W podstawowej wersji kupujemy tylko sam wyświetlacz bez podświetlenia. Ponieważ kontrast jest imponujący dlatego za dnia podświetlenie jest zbędne.Płytka podświetlająca występuje w kilku opcjach kolorystycznych , mnie najbardziej spodobał się kolor bursztynowy.

Przejdźmy do konkretów. Poniżej schemat podłączeń.


Korzystamy z trybu 4-bitowego (IM1 i IM2 do +3.3 V). Ale pamiętajmy , że mamy jeszcze do dyspozycji SPI , I2C,  8-bitów.  Do sterowania w trybie 4-bitowym potrzebujemy łącznie osiem pinów mikrokontrolera. Przy czym pin RW, służący do wyboru zapis/odczyt do sterownika SSD1803A, pomijamy (w programie), no chyba , że chcemy bawić się w sprawdzanie flagi zajętości ale ja ten aspekt dla uproszczenia pomijam.
Opis podłączenia wyświetlacza do mikrokontrolera PIC24HJ128GP502 :

E              -->   RB2
RW          -->   RB3      (nie będziemy korzystać w programie ale podłączamy)
RS           -->   RA2
RESET   -->   RA0
DB7        -->   RB15
DB6        -->   RB14
DB5        -->   RB13
DB3        -->   RB12

E - przed wysłaniem danych/instrukcji ustawiamy na 1 po zakończeniu wysyłania danych/instrukcji ustawiamy na 0.
RS - rejestr instrukcji - 0 / rejestr danych - 1

W zasadzie sama obsługa programowa nie wiele się różni od obsługi HD44780.
Po włączeniu zasilania, inicjalizacja (łącznie z uwzględnieniem stabilizacji napięć) trwa ok 16 ms.

Inicjalizacja w trybie 4-bitowym wygląda tak :

1. Włączenie zasilania
2. Delay 5 ms
3. Hardware Reset 10 ms (RESET --> 0)
4. Delay 1 ms
5 Wysyłamy kolejno (wartości HEX) :
- 0x33 / 0x32 / 0x2A /  0x09 / 0x06 / 0x1E / 0x29 / 0x1B / 0x6E / 0x57 / 0x72 / 0x28 / 0x0F

Jeśli wszystko podłączyliśmy poprawnie po procedurze inicjalizacji zobaczymy migający kursor.

Wyświetlacz bez żadnych dąsów się inicjalizuje. Sterowanie zapisem do rejestru danych i rozkazów oraz definiowanie własnych znaków przebiega identycznie jak w HD44780 więc dużo roboty odpada w programie. Warto nadmienić , że wyświetlana czcionka jest ładna i prezentuje się bardzo profesjonalnie.

Podsumowując uważam , że prezentowany wyświetlacz jest idealną wręcz propozycją w świecie 3.3 V i wyświetlaczy znakowych. Praca z nim to czysta przyjemność.

Zalety to : dedykowane zasilanie 3.3 V, zajmuje mało miejsca w porównaniu do kobylastych HD44780, kilka interfejsów komunikacyjnych, bardzo duża szybkość pracy (wyświetlanie nie przytka głównej pętli programu),prosta inicjalizacja, duża czytelność znaków nawet bez podświetlenia, bardzo dobre i równe podświetlenie (6 diod LED), szpilki ułatwiające montaż. Inne jeszcze nie odkryte :)

Wady : cena ok 135 zł z płytką podświetlającą, płytkę podświetlającą trzeba dokupić osobno.

Program : inicjalizuje wyświetlacz, definiuje literkę "ę", wyświetla napis.


/************************* 
   File:   ustaw_zegar.h
 *************************/
#ifndef USTAW_ZEGAR_H
#define USTAW_ZEGAR_H
#define FCY 40000000 /* podajemy wartosc ustawionego zegara (40 MHz), wazne 
aby przed includowaniem <libpic30.h>, potrzebne to jest do wyliczania delay-i*/
/*deklaracja funkcji*/
void ustaw_zegar(void) ;
#endif  /* USTAW_ZEGAR_H */

/************************* 
   File:   dogm204.h         
 *************************/
#ifndef LCD_H
#define LCD_H

/*_TRISB3 --> TRISBbits.TRISB3*/
#define TRIS_RESET   _TRISA0
#define TRIS_RW      _TRISB3
#define TRIS_RS      _TRISA2
#define TRIS_E       _TRISB2
#define TRIS_DB4     _TRISB12
#define TRIS_DB5     _TRISB13
#define TRIS_DB6     _TRISB14
#define TRIS_DB7     _TRISB15
/*_RB3 --> PORTBbits.RB3*/
#define RESET   _RA0
#define RW      _RB3
#define RS      _RA2
#define E       _RB2
#define DB4     _RB12
#define DB5     _RB13
#define DB6     _RB14
#define DB7     _RB15

/* przyporzadkowanie adresow pamieci DD-RAM do pol wyswietlacza*/
#define LCD_Line1 0x00 /*adres 1 znaku 1 wiersza */
#define LCD_Line2 0x20 /*adres 1 znaku 2 wiersza */
#define LCD_Line3 0x40 /*adres 1 znaku 3 wiersza */
#define LCD_Line4 0x60 /*adres 1 znaku 4 wiersza */

 void Wyslij_do_LCD(unsigned char bajt);
 void WlaczLCD();
 void WyswietlLCD(char *napis);
 void UstawKursorLCD(uint8_t y, uint8_t x);
 void CzyscLCD();
 void WpiszSwojeZnaki(void);
#endif  /* LCD_H */

/************************ 
   File:  ustaw_zegar.c 
 ************************/

/*Ustawiamy zegar wewnetrzny na ok 40 MHz (dokladnie na 39.61375 MHz*/
#include "xc.h" /* wykrywa rodzaj procka i includuje odpowiedni plik 
naglówkowy "p24HJ128GP502.h"*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> /*dyrektywy do uint8_t itp*/
#include "ustaw_zegar.h" /*z uwagi na FCY musi byc przed #include <libpic30.h>*/

/*definicja funkcji*/
void ustaw_zegar(void) {
/*
* to co mozemy ustawic za pomoca '#pragma' jest dostepne w pliku 
* xc16/docs/config_index.html
*/
#pragma config JTAGEN = OFF
// Watchdog timer enable/disable by user software
#pragma config FWDTEN = OFF 

//********************Start Ustawien Zegara************************
/* 
* Fcy - zegar instrukcji , Fosc - zegar rdzenia (jest zawsze dwa razy wiekszy 
* od zegara instrukcji)) Ustawiamy zegar instrukcji na 40 Mhz z wewnetrznego 
* oscylatora Fin=7.37 MHz w/g wzoru Fcy=Fosc/2 gdzie Fosc=Fin x (M/(N1+N2))
* gdzie M=43, N2=2, N1=2 ustawiane w rejestrach PLLFBD/PLLPOST/PLLPRE
*/
//Select Internal FRC (Fast RC Oscillator)
#pragma config FNOSC = FRC // FOSCSEL-->FNOSC=0b000 (Fast RC Oscillator (FRC))
//Enable Clock Switching and Configure
#pragma config FCKSM = CSECMD //FOSC-->FCKSM=0b01 - wlacz zegar
#pragma config OSCIOFNC = OFF //FOSC-->OSCIOFNC=1 - Fcy b?dzie na pinie OSCO

/*Config PLL prescaler, PLL postscaler, PLL divisor*/
PLLFBD = 41 ; //M=43 (0 bit to 2 st?d 41 = 43 patrz w rejestrze), tutaj 3.685 x 43 = 158.455MHz
CLKDIVbits.PLLPRE=0 ;  //N1=2, tutaj 7.37 MHz / 2 = 3.685 MHz
CLKDIVbits.PLLPOST=0 ; //N2=2, tutaj 158.455 MHz / 2 = 79.2275 MHz (Fosc)
/*   
* UWAGA przerwania musza byc wylaczone podczas wywolywania ponizszych 
* dwóch funkcji __builtin_write_...brak definicji w pliku naglówkowym
* to wewnetrzne funkcje kompilatora patrz help M-LAB IDE
* i datasheet str 140(11.6.3.1 Control Register Lock)
*/
 /*Initiate Clock Switch to Internal FRC with PLL (OSCCON-->NOSC = 0b001)*/
    __builtin_write_OSCCONH(0x01); //tutaj argumentem jest wartosc z NOSC
    /*Start clock switching*/
    __builtin_write_OSCCONL(0x01);

/*Wait for Clock switch to occur*/
    while(OSCCONbits.COSC !=0b001);

/*Wait for PLL to lock*/
    while(OSCCONbits.LOCK !=1) {};

    }


/************************* 
    File:   dogm204.c         
 *************************/

#include "xc.h" /* wykrywa rodzaj procka i includuje odpowiedni plik*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h> /*dyrektywy uint8_t itp*/
#define FCY 40000000UL /* podajemy wartosc ustawionego zegara (40 MHz), wazne 
aby przed includowaniem <libpic30.h>, potrzebne to jest to wyliczania delay-i*/
#include <libpic30.h> /*biblioteka dajaca dostep do delay-i.*/
#include "dogm204.h"

/*definicje funkcji*/

void Wyslij_do_LCD(unsigned char bajt)
{
    /*ustaw linie EN, przed wysylka danych*/
    E = 1;
    /*wyslanie 4 najstarszych bitow danych*/
    if(bajt & 0x80) DB7 = 1else DB7 = 0;
    if(bajt & 0x40) DB6 = 1else DB6 = 0;
    if(bajt & 0x20) DB5 = 1else DB5 = 0;
    if(bajt & 0x10) DB4 = 1else DB4 = 0;
    __delay_us(1);
    /*potwierdzenie wyslania danych (opadajacym zboczem EN)*/
    E = 0;
    /*ustaw linie EN, przed wysylka danych*/
    __delay_us(1);
    E = 1;
    /*wyslanie 4 najmlodszych bitow danych*/    
    if(bajt & 0x08) DB7 = 1else DB7 = 0;
    if(bajt & 0x04) DB6 = 1else DB6 = 0;
    if(bajt & 0x02) DB5 = 1else DB5 = 0;
    if(bajt & 0x01) DB4 = 1else DB4 = 0;
    __delay_us(1);
    /*potwierdz wysylke danych opadajacym zboczem EN*/
    E = 0;

    __delay_us(16);
    
}   

void WlaczLCD()
{
    /*ustawienie kierunku wyjsciowego linii podlaczonych do LCD*/
    TRIS_RESET = 0 ;
    TRIS_RW = 0 ;
    TRIS_RS = 0;
    TRIS_E = 0;
    TRIS_DB7 = 0;
    TRIS_DB6 = 0;
    TRIS_DB5 = 0;
    TRIS_DB4 = 0;

    /*zerowanie linii*/
    RESET = 1 ; /* 0 - Stan aktywny*/
    RW = 0 ;
    RS = 0/* 0 - wskazuje na rejestr rozkazow / 1 - wskazuje na rejestr danych*/
    E = 0;
    DB7 = 0;
    DB6 = 0;
    DB5 = 0;
    DB4 = 0;

    /*Start Inicjalizacji DOGM204 tryb 4-bity*/
    /*zaczekaj co najmniej 5 ms na ustabilizowanie sie napiecia*/
    __delay_ms(5);
    /*Hardware Reset 10ms*/
    RESET = 0 ;
    __delay_ms(10);
    RESET = 1 ;
    __delay_ms(1);
    
  /*Sekwencja startowa dla trybu 4-bit, patrz mini-datasheet str 5*/
  Wyslij_do_LCD(0x33);//wysylamy instrukcje do rejestru rozkazow
  Wyslij_do_LCD(0x32);
  Wyslij_do_LCD(0x2A);
  Wyslij_do_LCD(0x09);
  Wyslij_do_LCD(0x06);
  Wyslij_do_LCD(0x1E);
  Wyslij_do_LCD(0x29);
  Wyslij_do_LCD(0x1B);
  Wyslij_do_LCD(0x6E);
  Wyslij_do_LCD(0x57);
  Wyslij_do_LCD(0x72);
  Wyslij_do_LCD(0x28);
  Wyslij_do_LCD(0x0F); /*Display on, cursor on, blink on*/
  CzyscLCD();
RS = 1 ; /*przelacz na rejestr danych*/  
        
 /*Koniec inicjalizacji i ustawien wyswietlacza DOGM204*/      
}

void WyswietlLCD(char *napis)
{
    while(*napis){
    Wyslij_do_LCD(*napis++);
    }
         
}

void UstawKursorLCD(uint8_t y, uint8_t x)
{
    uint8_t n ;
    /*y (wiersze) = 1 do 4*/
    /*x (kolumna) = 1 do 20*/
    /*ustal adres poczatku znaku w wierszu*/
    switch(y)
    {
        case 1: y = LCD_Line1 ;break;
        case 2: y = LCD_Line2 ;break;
        case 3: y = LCD_Line3 ;break;
        case 4: y = LCD_Line4 ;break;
    
    }
    /*ustal nowy adres pamieci DD RAM*/
    /*ustaw bajt do Set DDRAM adres*/
    /* x odejmujemy jeden aby przekonwertowac z 0-19 na 1-20 */
    n = 0b10000000 + y + (x-1) ;
    
    /*wyslij rozkaz ustawienia nowego adresu DD RAM*/
    RS = 0/*stan niski na linii RS, wybieramy rejestr instrukcji*/
    Wyslij_do_LCD(n);
    RS = 1;  /*przelacz na rejestr danych */ 
}

void CzyscLCD()
{
    RS = 0/*przelacz na rejestr rozkazow*/
    Wyslij_do_LCD(1);
    RS = 1/*przelacz na rejestr danych*/
    __delay_us(1);

void WpiszSwojeZnaki(void) {
    /*definicja wlasnych znaków maks 8 szt*/
    char znak1[]= {0,0,14,17,31,16,14,2}; /* definicja literki e z ogonkiem */
    int i; 
    /* adresy poczatku definicji znaku to wielokrotnosc osmiu DEC(0,8,16,24,32,40,48,56)
     * ale uwaga wazne ! adresy kodowane sa na 6 mlodszych bitach dwa najstarsze bity
     * to zawsze  01 (01AAAAAA-gdzie A adres).Uwzgledniajac wartosc calego bajtu
     * adresy poczatku beda wygladal tak HEX(0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78)
     * Aby wpisac do pamieci wyswietlacza zdefiniowany znak nalezy najpierw wyslac 
     * do rejestru rozkazów (RS na 0) adres poczatku definicji znaku 
     * a w drugim kroku przesylamy dane (RS=1) 8 x bajt (tablica) definjujace obraz znaku*/
    
    RS = 0 ;/*stan niski na linii RS, wybieramy rejestr instrukcji*/
     /*wysylamy instrukcje do rejestru rozkazow (ustaw adres poczatkowy w CGRAM 
      na nasz znak w tym przypadku znak na pozycji drugiej) */
    Wyslij_do_LCD(0x48);/*wysylamy instrukcje do rejestru rozkazow 
     (ustaw adres poczatkowy w CGRAM na nasz znak w tym przypadku znak na pozycji drugiej) */
    
    RS = 1 ;/*stan wysoki na linii RS, wybieramy rejestr danych*/
    /*wysylamy 8 x bajt zdefiniowanego w tablicy znak1[] znaku*/
    for(i=0;i<=7;i++)
    {
       Wyslij_do_LCD(znak1[i]);
    }
   
    RS = 0 ;/*stan niski na lini RS, wybieramy rejestr instrukcji*/
    /*ustawiamy adres DDRAM na pierwszy znak w pierwszej linii, nie zapomnijmy
     o tym poniewaz inaczej zostaniemy w pamieci CGRAM*/
    Wyslij_do_LCD(0x80);
    RS = 1 ; /*stan wysoki na linii RS, wybieramy rejestr danych*/
}


/************************* 
   File:   main.c         
 *************************/

/*wyswietlacz DOGM204-A (4x20) firmy Electronic Assembly*/
#include "xc.h" /* wykrywa rodzaj procka i includuje odpowiedni plik naglowkowy "p24HJ128GP502.h"*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> /*dyrektywy uint8_t itp*/
#include "ustaw_zegar.h" /*tutaj m.in ustawione FCY*/
#include <libpic30.h> // biblioteka dajaca dostep do delay-i.
#include "dogm204.h"

char napis[] = "Kocham Monik""\x01"/* "\x01" to zapis kodu ASCII dla zdefiniowanej
literki e z ogonkiem. Dla wlasnych znaków mamy zarezerwowane kody ASCII od 0 do 7,
przyczym aby uzywac podanego sposobu wstawiania wlasnych znaków w stringa, nie mozemy 
uzywac kodu ASCI 0, czyli zamiast 8 znaków korzystamy z 7 (od 1 do 7)*/
int main(void) {
    ustaw_zegar();/*odpalamy zegar na ok 40MHz*/
        
    PMD1bits.AD1MD=1;       //wylaczamy ADC
    AD1PCFGL = 0x1E3F;      //wylaczenie linii analogowych(wszystkie linie cyfrowe)
                                
    WlaczLCD();             //inicjalizacja wyswietlacza LCD
    WpiszSwojeZnaki();      //wpisz do CGRAM-u definicje znaku e z ogonkiem
    UstawKursorLCD(1,4);
    WyswietlLCD(napis);    //wyswietl napis z tablicy napis[]
    
    while(1)
      {
          /*Glowna Petla Programu*/   
      }
    
    return 0;
}



Link :
DOGM204-A - mini datasheet

SSD1803A - datasheet

Wyświetlacze EA DOGM

Brak komentarzy:

Prześlij komentarz