Sterowanie wyświetlaczem LED w asemblerze

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
Matrix86
-
Posty: 8
Rejestracja: 07 mar 2008, 13:50
Lokalizacja: Nowy Sącz

Sterowanie wyświetlaczem LED w asemblerze

Post autor: Matrix86 » 07 mar 2008, 15:30

Witam Wszystkich Forumowiczów
Chciałem się poradzić i prosić o pomoc ponieważ mam taki oto problem.
Mam zbudowany system mikroprocesorowy (układ główny wraz mikrokontrolerem atmega32 + układ wyświetlacza diodowego - tak jak na rys. poniżej). Układ z mikrokontrolerem ma za zadanie tak sterować wyświetlaczem aby wyświetlić na nim ciąg znaków (10 znaków). Dane do wyświetlenia są zapisane w wewnętrznej pamięci mikrokontrolera (EEPROM).
Wyświetlacz stanowi 10 modułów matryc LED o organizacji 5x8 (układy o wspólnej katodzie).
Mój problem jest związany z programową obsługą wyświetlacza. :sad: Czy ktoś ma jakieś doświadczenie w programowaniu w asemblerze sterowania matrycami LED? Poszukiwałem po internecie i w książkach...i niestety niewiele jest projektów tego typu. Nie chodzi mi o to by ktoś mi zrobił cały program, zależy mi tylko na zapisaniu procedury, która będzie sekwencyjnie przełączać poszczególne kolumny matryc (10x5 kolumn).
Wiele na ten temat czytałem...sterowanie w moim projekcie ma wyglądać tak:
1) wiersze anod są sterowane z wyjść PA0-7 atmegi32 poprzez stopień wzmacniający udn2981. To właśnie na te wyjścia będę "wystawiał" odpowiednie sygnały.
2) kolumny katod są z kolei sterowane poprzez interfejs SPI procka i poprzez rejestry przesuwne szeregowo-równoległe. To właśnie dzięki tym sygnałom będę wybierał kolumnę która ma się świecić. Przykładowo podając "0" będę je następnie przesuwał poprzez poszczególne rejestry aż do wybranej kolumny którą chcę zaświecić.
Z materiałów które dotychczas udało mi sie znaleźć wyczytałem że do sterowania jest potrzebny programowy bufor w którym będą przechowywane sygnały sterujące. Czy wobec tego muszę stworzyć w programie bufor na sygnały sterujące kolumnami i osobny bufor na sygnały dla wierszy?
Rozumiem, że aby wyświetlanie było płynne poszczególne kolumny muszę wyświetlać z częstotliwością ok 100 Hz by było to niezauważalne dla ludzkiego oka. Czy to 100 Hz wykorzystujemy w programie w momencie, gdy konfigurujemy licznik procka, który odmierza upływający czas pomiędzy poszczególnymi przerwaniami w obsłudze wyświetlacza?
Tabelę znaków (kolumny matrycy składające sie na znak) oraz odczyt z pamięci EEPROM już mam wykonaną.
Proszę o pomoc i dziękuję za wszelkie wskazówki :grin:
Załączniki
DISPLAY.JPG
układ wyświetlacza matrycowego
UKŁ_GŁ.JPG
Układ mikrokontrolera sterującego wyświetlaczem

ZbeeGin

Re: Sterowanie wyświetlaczem LED w asemblerze

Post autor: ZbeeGin » 07 mar 2008, 17:17

Matrix86 pisze:Z materiałów które dotychczas udało mi sie znaleźć wyczytałem że do sterowania jest potrzebny programowy bufor w którym będą przechowywane sygnały sterujące. Czy wobec tego muszę stworzyć w programie bufor na sygnały sterujące kolumnami i osobny bufor na sygnały dla wierszy?
Proponuję utworzyć sobie bufor o długości jednej linii takiego wyświetlacza. Dlaczego? Robiłem coś podobnego, zbudowane to było z ośmiu wyświetlaczy 8x8 ale ze sterowaniem rówoległym. Całość miała działać na przerwaniach z licznika. Niestety czas wyświetlania całego wyświetlacza był strasznie długi w stosunku do innych zadań jakie miał wykonywać cały układ. Wpadłem zatem na pomysł by w jednym przerwaniu generować obraz tylko dla jednej linii! Interwał przerwań zwiększyłem do takiej wartości by nie było widać ani przeplotu ani migotania wyświetlaczy. Nie powodowało to jednak zakłóceń w pracy reszty programu gdyż czas przygotowania danych dla jednej linii i jej wyświetlenie był bardzo krótki.
U ciebie z racji sterowania szeregowego rejestrami 4094 znacznie się on wydłuży (ok. 8 krotnie), a zatem wyświetlanie całego obszaru obrazu nie ma tutaj sensu. Prosto jest przygotować bufor 8 bajtowy - nie zajmując przy tym znacznego obszaru pamięci - plus parę bajtów by liczyć linie i przetwarzać bitmapy znaków.
Sprawa ulegnie dalszemu skompilkowaniu gdy zamierzasz wyświetlać na tym urządzeniu także grafikę. Wtedy przechowywanie w pamięci całego obrazu jest konieczne.

Sygnały sterujące można przecież generować na bieżąco, są to przecież proste operacje na portach - z tą różnicą, że zsynchronizowane w czasie. Zatem nie ma problemu dorobić tych paru instrukcji dodatkowych.
Matrix86 pisze:Rozumiem, że aby wyświetlanie było płynne poszczególne kolumny muszę wyświetlać z częstotliwością ok 100 Hz by było to niezauważalne dla ludzkiego oka. Czy to 100 Hz wykorzystujemy w programie w momencie, gdy konfigurujemy licznik procka, który odmierza upływający czas pomiędzy poszczególnymi przerwaniami w obsłudze wyświetlacza?
Nie do końca tak. Licznik należy tak zaprogramować by czas pomiędzy początkiem pełnej operacji wyświetlania a kolejną taką operacją wynosił odwrotność 100Hz. Te 100Hz to jest nieco nad wyrost myślę. Wystarczy mniej. Przy 35Hz już nie widać aż tak, że wyświetlacze mrugają. Przy sterowaniu liniowym oczywiście częstotliwość przerwań wzrasta.


Na dokładkę przedstawię program który napisałem do sterowania węża świetlnego. Jest on w asemblerze 8051 (kod przeznaczony do AT89c2051), ale zobaczysz w nim jak sterowałem rejestrami 4094.
Ostatnio zmieniony 28 sie 2008, 21:57 przez ZbeeGin, łącznie zmieniany 1 raz.

Matrix86
-
Posty: 8
Rejestracja: 07 mar 2008, 13:50
Lokalizacja: Nowy Sącz

Post autor: Matrix86 » 08 mar 2008, 23:03

Wielkie dzięki ZbeeGin
Wiele razy czytałem i analizowałem...twoje programy...ale...
Mam nadzieję że się nie pogniewasz ale niezbyt są te dla mnie zrozumiałe te programy..pewnie dlatego że jestem w "tych klockach" nowicjuszem. Wiele rzeczy jest dla mnie niewiadomych jak choćby "tryb 2 z Autowpisem" w sterowniku świetlnym..myślę że jakbym Cię wypytywał po kolei co się skąd wzięło zapewne straciłbyś cierpliwość..podczas tłumaczenia.

Ale mimo wszystko wielkie dzięki.

Co do mojego projektu to raczej odpuszczę sobie grafikę skoro mam problemy z zbudowaniem podstawowej procedury sterowania wierszami i kolumnami...;- :cry:
pozdrawiam

[ Dodano: 2008-03-08, 23:46 ]
troszkę mnie olśniło... :grin:

Kod: Zaznacz cały

_WYSL_BIT:
        RLC     A               ;wystaw bit
        CLR     DSP_CLK         ;zero na zegarze
        MOV     DSP_DAT,C       ;prze˜lij ten bit
        SETB    DSP_CLK         ;
        SETB    DSP_CLK         ;stan wysoki
        SETB    DSP_CLK         ;
        CLR     DSP_CLK         ;przej˜cie w niski i wpis
        CLR     DSP_CLK         ;
        DJNZ    R7,_WYSL_BIT    ;
        ;koniec przesyłaˆania - ustaw wyj˜cia
        SETB    STORE           ;przepisz
        SETB    STORE           ;z bufora na wyj˜cia
        SETB    STORE           ;(CD 4094)
        CLR     STORE           ;
        CLR     STORE           ;
        RET
Czy zmienna STORE w tej funkcji oznacza bufor, do którego wpisujemy sygnały załączające określoną kolumnę? Zastanawia mnie dlaczego 3 razy zmienne DSP_CLK oraz STORE...czy dlatego że wysysłasz 3 bity (3 "1nki")?
Ostatnio zmieniony 19 kwie 2008, 13:36 przez Matrix86, łącznie zmieniany 1 raz.

ZbeeGin

Post autor: ZbeeGin » 09 mar 2008, 9:41

Matrix86 pisze:Wiele rzeczy jest dla mnie niewiadomych jak choćby "tryb 2 z Autowpisem" w sterowniku świetlnym...
Jest to specjalny tryb pracy licznika TIMER0 gdzie jedna jego połówka zlicza impulsy, a druga jest magazynem skąd licznik przeładowywuje się automatycznie podczas przepełnienia. Czyli licznik rusza, liczy w górę w rejestrze TL0 a jak osiągnie 256 to zawartość magazynu TH0 zostanie przepisana do TL0 i cykl się powtarza. To takie perpetum mobile do generacji przerwań w ściśle określonych interwałach czasowych.
Matrix86 pisze:Co do mojego projektu to raczej odpuszczę sobie grafikę skoro mam problemy z zbudowaniem podstawowej procedury sterowania wierszami i kolumnami...;- :cry:
Jesteś jeszcze na początku a już odrzucasz możliwości? Sterowanie to tylko wystawianie stanów logicznych w odpowiednim czasie...
Matrix86 pisze:troszkę mnie olśniło... :grin:

Kod: Zaznacz cały

_WYSL_BIT:
        RLC     A               ;wystaw bit
        CLR     DSP_CLK         ;zero na zegarze
        MOV     DSP_DAT,C       ;przeslij ten bit
        SETB    DSP_CLK         ;
        SETB    DSP_CLK         ;stan wysoki
        SETB    DSP_CLK         ;
        CLR     DSP_CLK         ;przej˜cie w niski i wpis
        CLR     DSP_CLK         ;
        DJNZ    R7,_WYSL_BIT    ;
        ;koniec przesyłaˆania - ustaw wyj˜cia
        SETB    STORE           ;przepisz
        SETB    STORE           ;z bufora na wyj˜cia
        SETB    STORE           ;(CD 4094)
        CLR     STORE           ;
        CLR     STORE           ;
        RET
Czy zmienna STORE w tej funkcji oznacza bufor, do którego wpisujemy sygnały załączające określoną kolumnę?
Nie. Chodzi tu o wewnętrzny bufor układów CD4094. Bez impulsu przeładowywującego na STB stan wyjść się nie zmieni.
Matrix86 pisze:Zastanawia mnie dlaczego 3 razy zmienne DSP_CLK oraz STORE...czy dlatego że wysysłasz 3 bity (3 "1nki")?
Nie. Mylisz pojęcia.
- STORE - syboliczna nazwa końcówki podłączonej do STB w 4094
- DSP_CLK - symboliczna nazwa końcówki podłączonej do CLK w 4094
- DSP_DAT - symboliczna nazwa końcówki podłączonej do DATA w 4094

Zamiast pisać za każdym razem SETB P1.4 piszę SETB STORE i wiem o co chodzi. Instrukcje są powtórzone, by wydłużyć czas trwania impulsu na danej linii. Jest to jeden ze sposobów. Dlatego w komentarzach pisze np. "stan wysoki".

Matrix86
-
Posty: 8
Rejestracja: 07 mar 2008, 13:50
Lokalizacja: Nowy Sącz

Post autor: Matrix86 » 29 mar 2008, 14:37

Witam

Dzięki ZbeeGin za przykłady które opublikowałeś przydały się.
Napisałem malutki programik, który ma za zadanie wyświetlić mi na jednym module matrycy LED jedną kolumnę w całości, jedna pusta a następnie ma wyświetlić górną polówkę kolumny.
Tak jak to przedstawiono na rys. poniżej:

Program wygląda następująco:

Kod: Zaznacz cały

    .include "m32def.inc" 
    .list 

    .def acc = r16 
    .def acc2 = r17 
    .def param = r18 
    .def licznik = r19 

    .cseg 

    .org  0                  ; 
    rjmp  ResetProcessor     ; 
    
    ...... 
    ; Tablica wektorów przerwań; 
    ...... 

Wyslij_bit0:                 ; poczatek petli 
       
    ; W tej petli za "1" wpisujemy do rejestru "0" 
    ; logiczne...x razy. Odpowiada to sytuacji wpisania 
    ; do rejestru 4094 słowa w postaci np: 0..0000001 
    ; jedynka wędruje od Q1 do Q8        Q1.....Q8..itd 
    
    cbi   PORTB,5            ; DATA = 0 i ta "0" bedzie się 
                             ; przesuwać od Q1 DO Q7    pierwszego rej. 4094        
    cbi   PORTB,7            ; CLOCK = 0  / 
    sbi   PORTB,7            ; CLOCK = 1    / skok zegara z 0 na 1 

    sbi   PORTB,4            ; STROBE = 1 - wpisanie do pamięci rejestru 

    dec   param              ; zmniejsz parametr 
    cpi   param,0            ; porównaj z zerem 
    brne  Wyslij_bit0        ; jeśli nie jest = 0 to powtórz pętle 
    ret 

Wyslijbit: 
    mov   param, licznik 
    sbi   PORTB,5            ; DATA = 1 i ta "1" bedzie się 
                             ; przesuwać od Q1 DO Q8    pierwszego rej. 4094 
    cbi   PORTB,7            ; CLOCK = 0  / 
    sbi   PORTB,7            ; CLOCK = 1    / skok zegara z 0 na 1 
    sbi   PORTB,4            ; STROBE = 1 - wpisanie do pamięci rejestru 
        
    rcall Wyslij_bit0 
    ret 
;----------------------------------------------------------------------------- 

ResetProcessor:              ; 
    cli                      ; 
    ldi   r16,LOW(RAMEND)    ; 
    out   SPL,r16            ; 
    ldi   r16,HIGH(RAMEND)   ; 
    out   SPH,r16            ;        
    sei        

    ldi   r16,0xFF           ; 
    out   DDRA,r16           ; PORTA - port wyjscia 
                             ; 
    ldi   r16,0 
    out   PORTA,r16        

    ldi   r16,0xFF           ; 
    out   DDRB,r16           ; PORTB - jako wyjscie 

    ldi   r16,0              ; 
    out   PORTB,r16          ; 
        
    ldi   licznik,50         ; Podaję liczbę bitów z "0" które 
                             ; mam wpisać do jednego rejestru..(50 kolumn) 
    cbi   PORTB,4            ; STROBE = 0 
        
    mov   param,licznik      ; Czyszczenie wyświetlacza 
    rcall Wyslij_bit0        ; Na wszystkie kolumny podajemy "0". 

;*******************************************************************        
    ldi   licznik,1          ; tyle zer wpiszemy do rejstru pomiędzy 
                             ; jedynkami logicznymi 
    ldi   r16,0xFF           ; Podajemy jedynki na wszystkie wiersze 
    out   PORTA,r16          ; modułów LED 
    rcall Wyslijbit 

    ldi   r16,0x0F           ; Podajemy 4 jedynki logiczne na górną cześć 
    out   PORTA,r16          ; kolumny...po to by zaświecić górną połówkę 
    rcall Wyslijbit          ; pojedynczej kolumny matrycy 

koniec:                      ; koniec petli 
    rjmp  koniec             ; niekończąca się pętla...stosujemy po to by 
                             ; kolumny były wyświetlone na jednym module, 
                             ; a nie na wszystkich
			     
;----------------------------------------------------------------------------- 
    .exit
Mój problem polega na tym, że zamiast się wyświetlać tak jak chcę tzn. jedna cała kolumna - pusta kolumna - połowa kolumny wyświetla sie: pół kolumny przerwa i pól kolumny (tak jak na rys.). Mimo że sprawdzałem kod programu kilkakrotnie to w dalszym ciągu nie wiem co może być tego przyczyną. Tak jakby pierwsza cała kolumna była kasowana kolejną tym razem połówka kolumny.
Proszę o pomoc jak wyeliminować ten problem.

[ Dodano: 2008-04-08, 09:00 ]
Mam pytanie nad którym teraz pracuję...mój problem polega na tym, że nie bardzo sie orientuje jak zapisać polskie znaki w pamięci EEPROM. Normalne znaki zapisuje w pamięci poprzez zapisanie ich szesnastkowych kodów ASCII...ale jak zapisać znaki z ogonkami ą,ę, ś ó..itd?
będę bardzo wdzięczny za jakieś rady.
Załączniki
MATRIX.JPG
Ostatnio zmieniony 29 mar 2008, 15:17 przez Matrix86, łącznie zmieniany 1 raz.

ZbeeGin

Post autor: ZbeeGin » 19 kwie 2008, 13:54

Aby była jasność:
1. Chcesz ułożyć matrycę w taki sposób, aby wyświetlać tekst w postaci jak na załączonym obrazku?
2. UDN steruje anodami, a ULN+CD4094 katodami w matrycach?

Matrix86 pisze:Mimo że sprawdzałem kod programu kilkakrotnie to w dalszym ciągu nie wiem co może być tego przyczyną. Tak jakby pierwsza cała kolumna była kasowana kolejną tym razem połówka kolumny.
Tak skonstruowałeś program, że najpierw wysyłasz 0xFF do UDN i aktywujesz kolumny, a potem zaraz wysyłasz 0x0F do UDN który... przykrywa poprzednio wysłaną wartość. I na koniec generujesz pustą pętlę. Błąd!

Przecież układ UDN to nie jest układem pamięciowym, aby pamiętał Twoje kolejne sekwencje. Właśnie sekwencyjnego sterowania tutaj brakuje. Trzeba wprowadzić pętlę, która najpierw ustawi rejestr przesuwny pierwszy na wartość 0b00010000, potem do UDN wprowadzisz 0xFF, małe opóźnienia, a następnie do rejestru przesuwnego pierwszego wpiszesz 0b0100000 i do UDN wprowadzisz 0x0F, i znów małe opóźnienie. I tak w kółko. Wtedy dopiero będzie obraz taki jak chcesz.

Tylko, że za każdym razem będzesz musiał wpisać cały zestaw bitów do rejestrów przesuwnych, inaczej całość będzie się przesuwać po wyświetlaczach i powstanie mętlik.
Zatem najpierw ciąg:

00010000 00000000 00000000 00000000 00000000 00000000 00000000

potem:

01000000 00000000 00000000 00000000 00000000 00000000 00000000

Na niebiesko zaznaczyłem dane które są znaczące, a na czerwono dane które musisz wpisać by dopełnić wszystkie bity z dostępnych 7 układów CD4049. Chyba, że dziwnym trafem masz ich mniej. :)
A teraz najgorsze: Najpierw wjedzie ostatnie zero z czerwonych itd w lewo! Zatem trzeba będzie jakby odwrócić ciąg w trakcie wysyłania. W programie zmienia się tylko kierunek pobierania danych (trzeba skorzystać z instrukcji ror), zatem nie jest to w żaden sposób skomplikowana sprawa.
Matrix86 pisze:Mam pytanie nad którym teraz pracuję...mój problem polega na tym, że nie bardzo sie orientuje jak zapisać polskie znaki w pamięci EEPROM. Normalne znaki zapisuje w pamięci poprzez zapisanie ich szesnastkowych kodów ASCII...ale jak zapisać znaki z ogonkami ą,ę, ś ó..itd?
Dokładnie tak samo jak zapisujesz normalne znaki. Od Ciebie zależy jak je zakodujesz. Czy skorzystasz z dziur w kodach ASCII (na zbędne znaki), czy ze standardowego kodowania obowiązującego w komputerach (CP-852, CP-1250, ISO-8859-2). Problemem jest tylko rozmiar matryc wzorcowych znaków i czy możesz sobie pozwolić na 2KB z danymi znaków.

Matrix86
-
Posty: 8
Rejestracja: 07 mar 2008, 13:50
Lokalizacja: Nowy Sącz

Post autor: Matrix86 » 24 kwie 2008, 14:39

Dzięki za odpowiedź
Już się szczerze mówiąc uporałem z tym problemem. Napisałem program który mi wyświetla znaki ..tylko że te znaki wrzucam na sztywno do programu. W chwili obecnej pracuje nad 2-oma innymi problemami. Po pierwsze napisałem część programu który działa z wykorzystaniem bufora w którym przechowuje pobrane z pamięci programu wzory znaków które chcę wyświetlić na matrycach. A więc odczytuję odebrany kod znaku z USART-a, kod znaku mam w rejestrze dajmy na to że to będzie np. r18. Następnie na podstawie tego kodu odczytuję z pamięci programu 5 kolejnych kodów dla 5 kolumn (cały znak na jednej matrycy) i wpisuje je do bufora...i tak kilka razy w zależności od liczby znaków w łańcuchu. Bufor zawierający kody kolumn liczy 50 bajtów po bajcie na każdą kolumnę. Jeśli znaków jest mniej niż 10...to pozostałe matryce będą puste czyli będą przedstawiać spacje. W buforze w tych miejscach będziemy mieli kody kolumn odzwierciedlających spacje (zerowe kolumny).
Spotkałem się z opcją że można to zrobić łatwiej tzn. przy wykorzystaniu bufora 10 bajtowego, ale niestety nie bardzo "widzę" ta koncepcje. Tutaj zwracam się do Kolegi Zbeegin który wcześniej wspominał mi o 8 bajtowym buforze. Czy mógłbyś to jakoś uszczegółowić? Czy ten bufor miałby przechowywać kody znaków i i na ich podstawie pobierać 5 kolumn z pamięci programu i od razu wysyłać do wyświetlacza? Czy też jakoś inaczej...Jak wtedy by przebiegało wybieranie kolumn czy tez wszystko po kolei by wyglądało tak jak w przedstawionej przeze mnie opcji?
Drugi problem z jakim się teraz zetknąłem to właśnie pozycjonowanie kolumn na wyświetlaczu. Chodzi mi o to że jak będę chciał wyświetlić np. słowo "MATRIX" wyświetlić je dokładnie na środku wyświetlacza a nie żeby było "wyjustowane" do lewej lub do prawej strony..(chodzi mi o wyśrodkowanie tekstu). Kombinowałem to w taki sposób żeby pozycjonować wyświetlanie kolumn poprzez modulo 5, ale niestety nie bardzo mi to wychodzi. Byłbym wdzięczny za jakiekolwiek wskazówki.
pozdrawiam

ZbeeGin

Post autor: ZbeeGin » 24 kwie 2008, 17:51

Matrix86 pisze:Czy ten bufor miałby przechowywać kody znaków i i na ich podstawie pobierać 5 kolumn z pamięci programu i od razu wysyłać do wyświetlacza? Czy też jakoś inaczej...
Inaczej. Są dwa bufory: 1. znaków do wyświetlenia. 2. Jednej linii z wyświetlacza.
Linia ta wyświetla się w każdym przerwaniu - za każdym razem następna, i co przerwanie to do bufora 2 lądują nowe dane na podstawie danych z bufora 1 po przekształceniu kodów znaków na ich matryce.
Ale lepiej odrzucić taką możliwość, gdyż warto przygotować pełen obraz matrycy w pamięci RAM i rzutować na ekran - jak procesor się wyrobi to cały obraz, a jak nie to linia po linii. Wtedy dodatkowo można przygotować sobie jeden nadmiarowy znak (5 kolumn) gdzie tymczasowo będzie można wpisać obraz znaku poza ekranem i wsuwać go kolumna po kolumnie na ekran, razem z rotowaniem całego bufora. Jak wszystkie 5 bitów się wysunie to wpisać tam następny znak itd. Utworzysz wtedy animowany obraz przesuwającego się tekstu w lewo.
Matrix86 pisze:Drugi problem z jakim się teraz zetknąłem to właśnie pozycjonowanie kolumn na wyświetlaczu. Chodzi mi o to że jak będę chciał wyświetlić np. słowo "MATRIX" wyświetlić je dokładnie na środku wyświetlacza a nie żeby było "wyjustowane" do lewej lub do prawej strony..(chodzi mi o wyśrodkowanie tekstu). Kombinowałem to w taki sposób żeby pozycjonować wyświetlanie kolumn poprzez modulo 5, ale niestety nie bardzo mi to wychodzi. Byłbym wdzięczny za jakiekolwiek wskazówki.
Musisz policzyć ile kolum (pikseli) zajmuje tekst. Liczbę tą odjąć od rzeczwystej dostępnej długości obrazu w kolumnach (50), a resztę podzielić przez dwa i tyle kolumn opuścić (czyli przesunąć bitowo bufor w prawo). To najprostsze rozwiązanie.

ODPOWIEDZ