top of page

Budwa transceivera CW, SSB na pasma 50MHz i 70MHz w oparciu o układy Atmega i Cypress oraz programowanie w języku C

Kilka lat temu z nudów zbudowałem sobie mały prosty transceiver pracujący wyłącznie na paśmie 50MHz. Pomysł zbudowania takiego urządzenia narodził się kiedy stałem się posiadaczem kultowego transceivera FT-1000 MK-V.

Ponieważ FT-1000 nie posiadał właśnie tego pasma, a ja już zasmakowałem w pracy na tej magicznej częstotliwości.

Transceiver który sobie zbudowałem to była klasyczna superheterodyna  z podwójną przemianą częstotliwości, która pracowała wyłącznie emisjami SSB i CW z mocą około 5W doprowadzoną do anteny. Do budowy urządzenia użyłem filtrów drabinkowych które też sam poskładałem. Pierwsza przemiana 40MHz na jednym filtre czterokwarcowym i druga przemiana 8MHz na dwóch filtrach ośmiokwarcowych. Radio pracowało tylko na górnej wstędze, a jako VFO użyłem układu PLL z mieszaniem częstotliwości.

Transceiver pracował bardzo fajnie jednak przepadł mi po tym jak pożyczyłem go jednemu z kolegów który chciał sobie odwzorować to radio. 

Teraz kiedy podniosłem trochę swoją wiedzę na temat programowania mikrokontrolerów, przyszedł mi pomysł zbudowania sobie nowego urządzenia o nieco poszerzonym zakresie pracy. Chcę mieć transceiver który pozwoli mi na swobodną pracę na pasmach 50MHz oraz 70MHz emisjami SSB i CW (nie mam w zamiarze używać modulacji FM).

Być może jeżeli nowa konstrukcja okaże się udana, posłużę się nim jako bazą do dobudowania innych pasm.

Na początku jednak skupiam się  na na podstawowych założeniach, czyli pasma 6m i 4m w wykonaniu modułowym, co pozwoli mi na ewentualne rozbudowy. 

Podstawowe założenia to:

-Podwójna przemiana częstotliwości 1 P.CZ 38MHz  i 2 P.CZ 8MHz.

Syngał SSB formowany na 8MHz. / filtry kwarcowe w układzie drabinkowym z ogólnie dostępnych rezonatorów kwarcowych które można kupować tanio w dowolnych ilościach.

 

-Urządzenie sterowane mikrokontrolerem z rodziny Cypress Psoc CY8C5888LTI-LP

-Jako wspomagający mikroprocesor Atmega 32 lub 128 , jeszcze nie zdecydowałem i w chwili obecnej pracuję nad oprogramowaniem na wszystkie te układy. Możliwe że w wersji końcowej zastosuję wyłącznie układy Cypress jeżeli uda mi się opracować software optymalny na ten mikroprocesor. 

-Jako wyświetlacz użyję HX8357B sterowany magistralą równoległą 16bit. 

-jako VFO oraz generatory fali nośnej użyję popularnych układów DDS AD8951 które w prosty sposób można obsłużyć sterując za pomocą interfejsu SPI zarówno przez układy Atmega jak i Psoc z rdzeniem ARM.

Ponieważ cały czas pracuję nad prototypem transceivera oraz jego oprogramowaniem, sukcesywnie będę dzielił się postępami w pracy i przedstawiał poszczególne moduły urządzenia wraz z opisem oprogramowania.

Chcę zaznaczyć że piszę oprogramowanie wyłącznie w języku C. Biblioteki użyte do konstruowania modułów, są albo napisane w całości przeze mnie, albo są przeze mnie modyfikowane z dostępnych w sieci bibliotek udostępnianych przez użytkowników głównie w języku C++ dla Arduino.

Ponieważ nie znam języka C++ ani Arduino, biblioteki te służą mi wyłącznie jako wspomaganie dla kodów które staram się sam opracować w języku C. Nie jestem programistą dla tego też materiały zaczerpnięte z innych rozwiązań są dla mnie dużą pomocą. Każde zapożyczenie będzie opatrzone stosownym komentarzem w programie źródłowym z zawartą tam informacją o jego pochodzeniu.

  

AD9850 oraz AD9851  DDS -  Syntezery częstotliwości do układów VFO, BFO 

Jako pierwsze opiszę układy bardzo popularnych, prostych w obsłudze i niezwykle użytecznych syntezerów DDS AD9850 i AD9851. Oba układy różnią się miedzy sobą zakresem generowanych częstotliwości oraz częstotliwością generatora wzorca. Wyprowadzenia i sposób sterowania obu układów są dokładnie takie same z jedną małą różnicą w słowie konfiguracyjnym. Oprogramowanie jakie później przedstawię, będzie uniwersalne dla obu układów z zaznaczoną różnicą którą należy zmienić w przypadku użycia jednego bądź drugiego układu.  

AD9850 - graniczna częstotliwość jaką według noty katalogowej może wygenerować ten układ to 50MHz, natomiast częstotliwość taktowania tego układu to 125MHz. i taki też generator 125MHz jest używany przy tym module.

AD9851 - graniczna częstotliwość jaką według noty katalogowej może wygenerować ten układ to 70MHz, natomiast częstotliwość taktowania tego układu to 180MHz. Generator częstotliwości wzorca użyty do tego układy to 30MHz i ta częstotliwość jest mnożona wewnątrz układu AD9851 razy 6 co daje częstotliwość taktowania 180MHz.

Mnożnik częstotliwości razy 6 włączany jest programowo za pomocą bitu konfiguracyjnego w ramce sterującej. Wszystko opiszę dokładniej przy okazji omawiania oprogramowania dla tego modułu. Zaznaczam że domyślnie w modułach AD9851, mnożnik zegara jest wyłączony, jeżeli o tym zapomnimy, nasz układ będzie generował znacznie niższe częstotliwości od oczekiwanych.

Dla uproszczenia i oszczędności pinów mikroprocesora sterującego układami AD985X, będziemy je sterować za pomocą magistrali SPI. 

Ja dla oszczędności i ułatwienia pracy, zaopatrzyłem się w gotowe moduły z układami AD9851 które są dostępne w sprzedaży internetowej już zmontowane i gotowe do użycia. W dodatku często jest tak że zmontowany moduł z AD9851 na pokładzie , jest tańszy od samego układu scalonego. Używałem kilku modułów z różnych źródeł i nigdy nie miałem z nimi problemu. Co prawda nie kupowałem ich z najtańszych źródeł, tylko od sprawdzonych dostawców.

Moduły jakich ja użyłem wyglądają tak

Moduły przygotowane są do pracy z napięciem 5V i zaopatrzone są we wszystkie niezbędne wyprowadzenia.

podczas zabaw z tymi modułami, zauważyłem że pracują one wyżej niż graniczna częstotliwość podana w nocie katalogowej, lecz im bliżej częstotliwości granicznej, tym na sygnale pojawia się więcej pasożytów. Na pewno spowodowane jest to między innymi raczej przeciętnej jakości filtrem dolnoprzepustowym  który jest umieszczony na module. W naszym przypadku jednak, moduł który zastosujemy do VFO, nie będzie pracował wyżej niż 35MHz.

Przy częstotliwości pierwszej P.CZ 38MHz, dla pracy na zakresie częstotliwości 70 do 73MHz, do mieszacza musimy dostarczyć częstotliwość 32 do 35MHz (70-38 = 32,   73-38 = 35MHz ). Zatem z powodzeniem możemy zastosować moduł DDS z układem AD9850 którego graniczna częstotliwość pracy wynosi 50MHz, jednak właśnie do VFO ja preferuję użyć AD9851 aby w razie potrzeby poszerzyć docelowy zakres pracy....  a także ze względu na mniejszą ilość "śmieci" jakie generuje układ AD9851 pracujący znacznie poniżej swojej częstotliwości granicznej.

Tańsze moduły AD9850 możemy użyć sobie w generatorach fali nośnej albo w generatorze przemiany dla 2 P.CZ

Aby nasz moduł wydał z siebie ładną sinusoidę o żądanej przez nas częstotliwości, musimy wysłać do niego poprzez interfejs SPI słowo w którym zawarte będą informacje o częstotliwości jaką chcemy uzyskać, oraz dane konfiguracyjne. Dokładne informacje można znaleźć w notach katalogowych naszych układów. Ja ograniczę się do przedstawienia skondensowanych informacji dotyczących metody obliczania częstotliwości oraz konfiguracji SPI.

Słowo które będziemy wysyłać do AD985X ma długość 40 bitów czyli 5 bajtów. Pierwsze 4 bajty zawierają informację o częstotliwości i ostatni bajt to bajt konfiguracyjny naszego DDSa. Dla poprawnej transmisji słowa po SPI, musimy ustawić interfejs w konfiguracji "LSB first".

A oto wzór jaki należy zastosować do wyliczenia wartości jaką będziemy wysyłać do DDSa by poinformować go o żądanej częstotliwości:

QRG = F * 4294967296 / zegar

gdzie QRG to żądana częstotliwość w Hz (10MHz = 10000000, 21MHz = 21000000 itd), a zegar przyjmuje wartość częstotliwości zegara taktującego nasz DDS wyrażonej też w Hz czyli 125MHz = 125000000 dla układu AD9850 albo 180MHZ = 180000000 dla układu AD9851. 

zatem aby uzyskać częstotliwość w zakresie pasma dwudziestu metrów 14,250.230 MHz nasz wzór będzie wyglądał tak: QRG = 14250230 * 4294967296 / 180000000 

jak widać mamy możliwość ustawiania każdej częstotliwości z dokładnością do jednego HZ. 

Poniżej przedstawię kod dla mikroprocesora Atmega 32 z wykorzystaniem sprzętowego SPI

Przedstawiam zatem treść biblioteki składającej się z dwóch plików.

Plik nagłówkowy SP_AD9851.h

Plik główny SP_AD8951.c

/////////////////////////////////////////////////////////////////////SP_AD9851.h/////////////////////////////////////////////////////////////////////////

#ifndef SP_AD9851_SP_AD9851_H_
#define SP_AD9851_SP_AD9851_H_

/* konfiguracja hardware SPI do AD9851*/


#define MOSI (1<<PB3)        //   <---- A (SER IN) = D7
#define SCK (1<<PB5)        //   <---- SHIFT CLOCK (SC) = WCLK
#define LT (1<<PB2)            //     <---- LATCH CLOCK (LT) = FQ_UP

#define RESET (1<<PD1)        //     <---- Reset AD9851 (RESET)
#define RESETDIR DDRD
#define RESETPORT PORTD


// definicje makr LT, SCK, RST //
#define LT_ON PORTB |= LT
#define LT_OFF PORTB &= ~LT

#define SCK_ON PORTB |=SCK
#define SCK_OFF PORTB &= ~SCK

#define RESET_ON PORTD |= RESET
#define RESET_OFF PORTD &= ~RESET


uint32_t qrg;

 

//Funkcje obsługi AD9851
void InitSpi(void);
void SendSpi(uint32_t qrg);
void AD985Xinit (void);


#endif /* SP_AD9851_SP_AD9851_H_ */

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Drugi plik biblioteczny SP_AD9851.c

////////////////////////////////////////////////////////////////Teraz plik SP_AD8951.c////////////////////////////////////////////////////////////////////////

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "SP_AD9851.h"

 

 


//----------------------------DEFINICJE FUNKCJI-------------------------------------------------//


// funkcja inicjalizacji sprzętowego SPI  dla AD985/9851 =LSB First //
void InitSpi(void) {

    DDRB |= MOSI|SCK|LT;                                    // piny SPI jako wyjścia
    SPCR |= (1<<SPE)|(1<<MSTR)|(1<<DORD);   // włącz SPI i ustaw Master oraz DORD na LSB first
    SPSR |= (1<<SPI2X);                                           // fosc/2
}


//.....................................................................//

// funkcja Wysyłania słowa 40 bit do AD9851 bajt po bajcie//
void SendSpi( uint32_t qrg) {

    LT_ON;
    LT_OFF;
    SPDR = qrg;
    while( !(SPSR & (1<<SPIF)) );
    SPDR = qrg>>8;
    while( !(SPSR & (1<<SPIF)) );
    SPDR = qrg>>16;
    while( !(SPSR & (1<<SPIF)) );
    SPDR = qrg>>24;
    while( !(SPSR & (1<<SPIF)) );
    SPDR = 0x01;
//bajt konfiguracyjny - 0x01 dla AD9851 ustawia mnożnik zegara x6 w przypadku AD9850 należy wysłac 0x00 //   

while ( ! (SPSR & (1<<SPIF)) );
    LT_ON;
    LT_OFF;
}

//.........................................................................................

//Funkcja inicjująca uklad DDS AD9850_9851 Bezpośrednio po wywolaniu inicjalizacji należy
// kolejno wywolac funkcje sendspi nawet z ustawieniem zero.

 

void AD985Xinit (void) {

    RESET_ON;                      // Reset AD9851 stanem wysokim
        _delay_ms (5);
        RESET_OFF;
        SCK_ON;
        _delay_ms (5);
        SCK_OFF;
        LT_ON;
        _delay_ms (5);
        LT_OFF;

        SendSpi ( qrg );            // wyslanie zerowej qrg z bajtem konfiguracyjnym (inicjacja AD985X)
                    

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

W dwóch powyższych plikach mamy ustawioną konfigurację dla układu Atmega32. Wykorzystuję tam sprzętowy interfejs SPI. 

Jak widać z opisów w pliku nagłówkowym, moduł DDS podłączamy do mikroprocesora w następujący sposób:

#define MOSI (1<<PB3)        //   <---- A (SER IN) = D7
#define SCK (1<<PB5)        //   <---- SHIFT CLOCK (SC) = WCLK
#define LT (1<<PB2)            //     <---- LATCH CLOCK (LT) = FQ_UP

#define RESET (1<<PD1)        //     <---- Reset AD9851 (RESET)

PB3 = D7

PB5 = WCLK

PB2 = FP_UP

PD1 = RESET

Korzystając z powyższej biblioteki, możemy teraz umieścić w programie taką funkcję:

 

qrg = data * 4294967296 / zegar;
        SendSpi ( qrg );

Teraz wpisując w miejsce "data" rządną częstotliwość w Hz, wysyłam wynik do moduły i uzyskuję na jego wyjściu zadaną częstotliwość. 

Dalej już możemy sobie wykorzystać ten kod w dowolny sposób do sterowania naszymi DDSami w Transceiverze.

Kolejny moduł który użyjemy to wyświetlacz graficzny. Moduł dostępny w internecie w wielu różnych odmianach.

 

HX8357B 3,2'' 420x380 16bit bus

Ponieważ wyświetlacze z tym interfejsem HX8357 dostępne są w wielu różnych wykonaniach, przedstawię zdjęcia tych egzemplarzy które trafiły w moje ręce zakupione u jednego ze sprzedawców internetowych. 

Ten rodzaj wyświetlacza gotowy jest do pracy z napięciem 5V, jego rozdzielczość to 420x380 a przekątna ekranu to 3,2'' , ale uwaga!! wykorzystuje on równoległy interfejs 16 bitowy czyli będziemy musieli użyć dwóch ośmiobitowych portów do sterowania tym wyświetlacze ( są dostępne te wyświetlacze także z interfejsem SPI, jednak ja mam właśnie takie z interfejsem równoległym i takiego użyję). Na jego pokładzie znajdziemy też interfejs karty SD który obsługuje się przez SPI, jednak ja  nie będę się nim zajmował (przynajmniej nie na tym etapie konstruowania transceivera).

Ten wyświetlacz posłuży mi do obrazowania aktywnych ustawień urządzenia oraz częstotliwości na której Transceiver pracuje. Moja wiedza nie pozwala mi jeszcze na zbudowanie popularnej obecnie ramki monitora pasma, jednak nie wykluczam takiej możliwości w przyszłości. 

Opanowanie programowe takiego wyświetlacza jest bardzo cenną nauką, ponieważ większość innych wyświetlaczy graficznych działa bardzo podobnie i nie ma już większego kłopotu żeby opanować ich obsługę. 

 

Zaczynamy

Do wysterowania tego właśnie wyświetlacza potrzebujemy aż dwudziestu pinów z naszego mikroprocesora. 

16 dla magistrali danych, oraz 4 dla sterowania kontrolera wyświetlacza.

Na zdjęciu poniżej widać mapę wyprowadzeń:

Nas interesują piny DB0 do DB15 to właśnie 16 bitów magistrali danych, oraz LCD_RS, LCD_WR, LCD_CS, LCD_RST.

Oczywiście piny 5V oraz GND aby zasilić nasz wyświetlacz. Pozostałe piny SPI które są tam widoczne,  to właśnie interface do obsługi slotu kart SD. 

Przykład który teraz opisuję, dotyczy sterowania tego wyświetlacza za pomocą mikroprocesora Atmega 32.

W internecie znalazłem całą masę przykładów bibliotek dla sterownika HX8357, jednak albo były przygotowane w języku C++ dla Arduino którego nie znam, albo dla interfejsu SPI którego nie ma w moim wyświetlaczu.

 

Najważniejsze jest przygotowanie podstawowych funkcji za pomocą których będziemy sterować tym wyświetlaczem, czyli takich funkcji sprzętowych. Resztę funkcji już tych z wyższego poziomu, do sterowania samym interfejsem graficznym, będę mógł po modyfikacji wykorzystać z istniejących w internecie bibliotek. Oczywiście niezbędne będzie ich przerobienie z C++ czy Arduino do czystego języka C którym się posługuję. 

Żeby jeszcze bardziej uprościć sobie obsługę interfejsu równoległego, postanowiłem użyć dwóch pełnych portów mikrokontrolera, a dokładnie wybór padł na porty PA oraz PC. Dla sygnałów sterujących użyłem pinów z portów PD oraz PB. Oto lista połączeń jakie użyłem w moim projekcie:

 

      TFT    AVR
    -------------------
    D15    PA7
    D14    PA6
    D13    PA5
    D12    PA4
    D11    PA3
    D10    PA2
    D9      PA1
    D8      PA0
    -------------------
    D7    PC7
    D6    PC6
    D5    PC5
    D4    PC4
    D3    PC3
    D2    PC2
    D1    PC1
    D0    PC0

  

    RS      PD7
    WR    PB2
    CS     PB1
    RST   PB0

Ze względu na objętość kodu potrzebnego do obsługi HX8357B, przedstawię tutaj tylko podstawowe informacje i niezbędne funkcje aby posłużyć się naszym wyświetlaczem.

Na początek potrzebujemy skonfigurować połączenia TFT z Atmega32 oraz stworzyć niezbędne makra do obsługi sygnałów sterujących i to wszystko w pliku nagłówkowym SP_HX8357B.h:

///////////////////////////////////////////////////////////////////////SP_HX8357.h///////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------
//
//        Ustawienia sprzętowe połączeń sterownika z mikrokontrolerem
//
//----------------------------------------------------------------------------------------


// tu definiuje piny procesora do których podłączam sygnały RS,WR,CS, RST
//! konfiguracja pinów sterujących LCD TFT HX8357B


#define RST (1<<PB0)        //ustawiam pin RST
#define RST_PORT      PORTB
#define RST_DDR        DDRB

#define CS     (1<<PB1)        //ustawiam pin CS
#define CS_PORT      PORTB
#define CS_DDR        DDRB

#define WR     (1<<PB2)        //ustawiam pin WR
#define WR_PORT      PORTB
#define WR_DDR        DDRB

#define RS     (1<<PD7)        //ustawiam pin RS
#define RS_PORT      PORTD
#define RS_DDR        DDRD

// tu konfiguruje porty dla linii D0..D15 LCD muszą byc dwa pelne porty od 0 do 7
#define DATA_PORT1         PORTC        // ustawiam port pierwszy D0-D7
#define DATA_PORT1_DDR    DDRC

#define DATA_PORT2         PORTA        // ustawiam port drugi    D8-D15
#define DATA_PORT2_DDR    DDRA

 

//------------------------------------------------  koniec ustawień sprzętowych ---------------


//definicje makr pinów sterujących wyświetlacz//
#define DEB_H     PORTD |= DEB
#define DEB_L     PORTD &= ~DEB
#define DEB_B    PORTD ^= DEB

#define RST_H     PORTB |= RST
#define RST_L     PORTB &= ~RST

#define CS_H    PORTB |= CS
#define CS_L     PORTB &= ~CS

#define WR_H     PORTB |= WR
#define WR_L     PORTB &= ~WR
#define WR_STB     PORTB &= ~WR; PORTB |= WR;

#define RS_H     PORTD |= RS
#define RS_L     PORTD &= ~RS

/////////////////////////////////////////////////////cdn. //////////////////////////////////////////////////////////////////

Do naszego wyświetlacza będziemy wysyłać dwa rodzaje informacji, komendy - Command i dane - Data.

Komendy żeby było łatwiej i jaśniej, zdefiniujemy sobie również w pliku nagłówkowy. Także dane o kolorach oraz inne dane potrzebne do konfiguracji wyświetlacza . Zaznaczam że poniższe dotyczy dokładnie tego wyświetlacza jakim się teraz zajmujemy. Dla innego modelu z tym sterownikiem HX8357 poniżesz komendy mogą się nieco różnić. To też dotyczy danych konfiguracyjnych. Jednak to co tutaj przedstawiam jest sprawdzone i działa poprawnie z wyświetlaczem który tutaj omawiam.

///////////////////////////////////////////////////////////dalszy ciąg SP_HX8357B.h////////////////////////////////

// komendy dla sterownika HX8357D
#define HX8357B 0xB

#define HX8357_TFTWIDTH  480 //320 
#define HX8357_TFTHEIGHT 320 //480

#define HX8357_NOP     0x00
#define HX8357_SWRESET 0x01
#define HX8357_RDDID   0x04
#define HX8357_RDDST   0x09

#define HX8357_RDPOWMODE  0x0A
#define HX8357_RDMADCTL  0x0B
#define HX8357_RDCOLMOD  0x0C
#define HX8357_RDDIM  0x0D
#define HX8357_RDDSDR  0x0F

#define HX8357_SLPIN   0x10
#define HX8357_SLPOUT  0x11
#define HX8357B_PTLON   0x12
#define HX8357B_NORON   0x13

#define HX8357_INVOFF  0x20
#define HX8357_INVON   0x21
#define HX8357_DISPOFF 0x28
#define HX8357_DISPON  0x29

#define HX8357_CASET   0x2A
#define HX8357_PASET   0x2B
#define HX8357_RAMWR   0x2C
#define HX8357_RAMRD   0x2E

#define HX8357B_PTLAR   0x30
#define HX8357_TEON  0x35
#define HX8357_TEARLINE  0x44
#define HX8357_MADCTL  0x36
#define HX8357_COLMOD  0x3A

#define HX8357_SETOSC 0xB0
#define HX8357_SETPWR1 0xB1
#define HX8357B_SETDISPLAY 0xB2
#define HX8357_SETRGB 0xB3
#define HX8357D_SETCOM  0xB6

#define HX8357B_SETDISPMODE  0xB4
#define HX8357D_SETCYC  0xB4
#define HX8357B_SETOTP 0xB7
#define HX8357D_SETC 0xB9

#define HX8357B_SET_PANEL_DRIVING 0xC0
#define HX8357D_SETSTBA 0xC0
#define HX8357B_SETDGC  0xC1
#define HX8357B_SETID  0xC3
#define HX8357B_SETDDB  0xC4
#define HX8357B_SETDISPLAYFRAME 0xC5
#define HX8357B_GAMMASET 0xC8
#define HX8357B_SETCABC  0xC9
#define HX8357_SETPANEL  0xCC

#define HX8357B_SETPOWER 0xD0
#define HX8357B_SETVCOM 0xD1
#define HX8357B_SETPWRNORMAL 0xD2

#define HX8357B_RDID1   0xDA
#define HX8357B_RDID2   0xDB
#define HX8357B_RDID3   0xDC
#define HX8357B_RDID4   0xDD

#define HX8357D_SETGAMMA 0xE0

#define HX8357B_SETGAMMA 0xC8
#define HX8357B_SETPANELRELATED  0xE9

//definicje kolorów
#define black           0x0000
#define navy            0x000F
#define dark_green      0x03E0
#define dark_cyan       0x03EF
#define maroon          0x7800
#define purple          0x780F
#define olive           0x7BE0
#define light_grey      0xC618
#define dark_grey       0x7BEF
#define blue            0x001F
#define green           0x07E0
#define cyan            0x07FF
#define red             0xF800
#define magenta         0xF81F
#define yellow          0xFFE0
#define white           0xFFFF
#define orange          0xFD20
#define green_yellow    0xAFE5
#define brown           0x79E0

//definicje kierunków
#define MADCTL_MY  0x80
#define MADCTL_MX  0x40
#define MADCTL_MV  0x20
#define MADCTL_ML  0x10
#define MADCTL_RGB 0x00
#define MADCTL_BGR 0x08
#define MADCTL_MH  0x04
#define MADCTL_SS  0x02 // SP2LUB dodane dla HX8357X 16 bit interface równoległy
#define MADCTL_GS  0x01 // SP2LUB dodane dla HX8357X 16 bit interface równoległy


//definicje pomocnicze
#define swap(a, b) { int16_t t = a; a = b; b = t; }

//deklaracje zmiennych
uint16_t _width, _height;
extern const uint8_t font[];
extern int crsor_x, cursor_y;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Teraz czas na zadeklarowanie funkcji z których później będziemy korzystać. Ciała tych funkcji przedstawię przy okazji is definiowania w pliku bibliotecznym .c Funkcje tutaj przedstawione to fukcje najbardziej podstawowe czyli te związane z hardwarem. Te właśnie funkcje bezpośrednio współpracują ze sterownikiem wyświetlacza. One będą podstawowymi składnikami funkcji wyższego poziomu z których tylko kilka tutaj przedstawię.

///////////////////////////////////////////////////////////dalszy ciąg SP_HX8357B.h////////////////////////////////

// ### deklaracje funkcji ###

//funkcje sprzętowe
void writecommand( uint8_t dat );
void writedata( uint8_t dat );
void hx8357d_init ( void );//
void hx8357d_setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void hx8357d_setRotation(uint8_t rotation);
uint16_t hx8357d_color565(uint8_t r, uint8_t g, uint8_t b); //convert three 8 bit RGB levels to a 16 bit colour value
void hx8357d_pushColor(uint16_t color);

////////////////////////////////////////////////////// END ///////////////////////////////////////////////

Dwie najbardziej podstawowe funkcje które będę odpowiedzialne za transfer informacji do wyświetlacza 

Pierwsza to void writecommand( uint8_t dat ); Ta funkcja będzie służyć do wysyłania Komend które zdefiniowaliśmy sobie wcześniej w pliku nagłówkowym.

Druga to writedata( uint8_t dat ); Ta funkcja będzie służyć do wysyłania danych.

Kolejna bardzo ważna funkcja to funkcja inicjująca wyświetlacz hx8357d_init ( void );

w pliku bibliotecznym SP_HX8357B.c zawarte są ciała tych funkcji które teraz przedstawię

/////////////////////////////////////////////////SP_HX8357.c/////////////////////////////////////

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#include <util/delay.h>

#include "SP_HX8357B.h"

 

//deklaracje zmiennych
int cursor_x, cursor_y;
uint16_t _width, _height;

// wysłanie komendy
void writecommand( uint8_t cmd ) {
    CS_L;
    RS_L;
PORTA = 0;
PORTC = cmd;
    WR_STB;
    RS_H;
    CS_H;

}
 

//wysładnie danych
void writedata( uint8_t dat ) {

    CS_L;
PORTA =dat>>8;
PORTC =dat;
    WR_STB;
    CS_H;

}

// Inicjacja wyswietlacza HX8357-B 16bit
void hx8357d_init ( void ) {


        DDRA     = 0xff;
        DDRC     = 0xff;

        RST_DDR    |= RST;
        CS_DDR    |= CS;
        WR_DDR    |= WR;
        RS_DDR    |= RS;

        RST_H;
        _delay_ms (50);
        RST_L;
        _delay_ms (10);
        RST_H;
        _delay_ms (10);

        writecommand(0x11);
        _delay_ms(120);
        writecommand(0xD0); // HX8357B_SETPOWER
       writedata(0x07);
       writedata(0x42);
       writedata(0x18);
       writedata(0x00);

        writecommand(0xD1); //HX8357B_SETVCOM
       writedata(0x00);
       writedata(0x07);
       writedata(0x10);

       writecommand(0xD2); //HX8357B_SETPWRNORMAL
       writedata(0x01);
       writedata(0x02);

        writecommand(0xC0);
        writedata(0x10);
        writedata(0x3B);
        writedata(0x00);
        writedata(0x02);
        writedata(0x11);

        writecommand(0xC5);
        writedata(0x08);

        writecommand(0xC8);
        writedata(0x00);
        writedata(0x32);
        writedata(0x36);
        writedata(0x45);
        writedata(0x06);
        writedata(0x16);
        writedata(0x37);
        writedata(0x75);
        writedata(0x77);
        writedata(0x54);
        writedata(0x0C);
        writedata(0x00);

        writecommand(0x36); // HX8357_MADCTL
        writedata(0x0a);

        writecommand(0x3A); // Interface pixel format
        writedata(0x55);    // 16 bits per pixel

        writecommand(0x2A); // HX8357_CASET
        writedata(0x00);
        writedata(0x00);
        writedata(0x01);
        writedata(0x3F);

        writecommand(0x2B); // HX8357_PASET
        writedata(0x00);
        writedata(0x00);
        writedata(0x01);
        writedata(0xDF);

        _delay_ms(120);
        writecommand(0x29);
        _delay_ms(25);

 

        CS_L;
}
 

///////////////////////////////////////////////////////////////////////////////////cdn./////////////////////////////////////////////////////////////

Właściwie to co przedstawiłem powyżej już wystarczy żeby podłączyć i zainicjować wyświetlacz z Atmega32.

Potrzebne są jeszcze funkcje wyższego poziomu, czyli te które pozwolą nam na czyszczenie ekranu, ryzowanie figur geometrycznych, wysyłanie znaków i stringów... Te funkcje można w dość prosty sposób przerobić z bibliotek napisanych dla tego wyświetlacza na platformę Ardunio. Pisane są one w języku C++ ale po odrobinie wysiłku można je przerobić opierając się na bazowych funkcjach które powyżej przestawiłem. Jeżeli ktoś jest zainteresowany uzyskaniem więcej informacji o przedstawionej bibliotece, proszę o email na sp2lub@gmail.com

​© 2023 by STREET LIFE. Proudly created with Wix.com

  • Facebook Clean
  • Twitter Clean
  • Flickr Clean
  • Instagram Clean
bottom of page