Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Wyświetlanie paska postępu w trybie tekstowym

pmmisiek 23 Lis 2006 00:38 1272 4
  • #1 23 Lis 2006 00:38
    pmmisiek
    Poziom 15  

    Witam.
    Chciałbym wyświetlać taki pasek postępu (w trybie tekstowym) który zobrazował by wartość jakiejś zmiennej przeskalowanej na %.

    Proszę o jakieś przykładowe procedury, głównie chodzi mi o to jak wyświetlać i czyścić pola, w których będą pojawiać się np. prostokąty.

    PS. Program piszę w Bascomie na uC ale jeśli ktoś napisze tu jakąś procedurkę choćby w C to będę wdzięczny.

    Dodam jeszcze, że chciałbym wyświetlać to na LCD i zdefiniować sobie prostokąt który wypełni pół jednego pola tekstowego oraz całe pole tekstowe, tak żeby zwiększyć nieco rozdzielczość tego paska postępu.

    Pozdrawiam

    0 4
  • #2 23 Lis 2006 01:40
    prokopcio
    Poziom 29  

    Witam. Pisze w asm ale idea taka sama:

    przykład dla wyświetlenia zmiennej z zakresu 0-32 na wyświetlaczu 16 znaków:

    1. skalujesz zmienną "a" do postaci z zakresu 0-32
    2. dzielisz "a/2" ( w assemblerze komenda div ab przy b=2 )
    3. wyświetlasz a pełnych kwadratów
    4. jeśli była reszta z dzielenia (w asm b<>0) to wyświetlasz jeszcze pół kwadratu
    5. wyświetlasz "16-a" spacji
    6. cofasz kursor o 16 pozycji i operacje powtarzasz od 1.

    Dodano po 4 [minuty]:

    poprawka:
    6. cofasz kursor do pozycji HOME i operacje powtarzasz od 1.

    0
  • #3 23 Lis 2006 09:10
    szelus
    Specjalista - Mikrokontrolery

    Witam. Proszę bardzo - kawałek mojego programu (w C). Pasek postępu z dokładnością do jednego piksela i ramką. Głowy teraz nie dam, że wszystko jest uruchomione (ostatnio mam mało czasu i musiałem odłożyć zabawki), ale raczej powinno działać.

    Code:

    #define LCD_STATUS_ROW          1
    #define LCD_TEXT_ROW            0
    #define LCD_TEXT_LINE_SIZE      20

    #define LCD_STATUS_NUM_START    0
    #define LCD_STATUS_BAR_START    5           
    #define LCD_STATUS_TIME_START   13


    #define LCD_CHAR_BEGIN_BAR      0
    #define LCD_CHAR_END_BAR        1
    #define LCD_CHAR_FULL_BAR       2
    #define LCD_CHAR_EMPTY_BAR      3



    static const PROGMEM unsigned char BarChars[] =
    {
       0x1F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, /* BEGIN BAR */
       0x1F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x00, /* END BAR */
       0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, /* FULL BAR */
       0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, /* EMPTY BAR */
    };

    static const PROGMEM unsigned char BarMask[] =
    {
        0x10, 0x18, 0x1c, 0x1e
    };


    void InitBarChars(void)
    {
        int i;

        lcd_command(_BV(LCD_CGRAM) + (LCD_CHAR_BEGIN_BAR * 8));  /* set CG RAM start address 0 */
        for (i = 0; i < sizeof(BarChars); ++i)
        {
            lcd_data(pgm_read_byte_near(&BarChars[i]));
        }
           
       
    }


    //static void lcd_data_5(uint8_t byte) __attribute__ ((noinline));

    static void lcd_data_5(uint8_t byte)
    {
        uint8_t i;
        for (i = 0; i < 5; ++i)
        {
            lcd_data(byte);
        }   
    }

    static void SetBarBeginChar(uint8_t bars)
    {
        uint8_t mask = pgm_read_byte_near(&BarMask[bars]);

        lcd_command(_BV(LCD_CGRAM) + (LCD_CHAR_BEGIN_BAR * 8) + 1);  /* set CG RAM start address 0 */
        lcd_data_5(mask);
    }

    static void SetBarEndChar(uint8_t bars)
    {
        static uint8_t current = 0;
        uint8_t mask;

        if (bars != current)
        {




            mask = pgm_read_byte_near(&BarMask[bars]);

            mask |= 0x01;
            lcd_command(_BV(LCD_CGRAM) + (LCD_CHAR_END_BAR * 8) + 1);  /* set CG RAM start address 0 */
                lcd_data_5(mask);
        }   
    }


    static void PutStringToLCD(uint8_t x, uint8_t y,
                               uint8_t len, uint8_t maxlen,
                               int (*pGetC)())
    {
        uint8_t i;

        if (len > maxlen)
        {
            len = maxlen;
        }

        lcd_gotoxy(x, y );

        for (i = 0; i < len; ++i)
        {
            lcd_putc((char)(*pGetC)());
        }

        for (; i < maxlen; ++i)
        {
            lcd_putc(' ');
        }
     
    }


    /*
     * Progress Bar functions
     */

    void DisplayProgressBarSet(uint8_t percentage)
    {
        int8_t  bars;
        int     i;

        bars = percentage / 3;

        lcd_gotoxy(LCD_STATUS_BAR_START, LCD_STATUS_ROW);
        for (i = 0; i < 6; ++i)
        {
            if (bars >= 4)
            {
                lcd_putc(LCD_CHAR_FULL_BAR);
                bars -= 5;
            }
            else if (bars > 0 || i == 0)
            {
                //install char with specified number of bars
                SetBarBeginChar(bars);
                lcd_gotoxy(LCD_STATUS_BAR_START + i, LCD_STATUS_ROW);
                lcd_putc(LCD_CHAR_BEGIN_BAR);
                bars = 0;
            }
            else
            {
                lcd_putc(LCD_CHAR_EMPTY_BAR);
            }
        }
        // last char is special
        SetBarEndChar(bars);
        lcd_gotoxy(LCD_STATUS_BAR_START + 6, LCD_STATUS_ROW);
        lcd_putc(LCD_CHAR_END_BAR);
    }

    0
  • #4 23 Lis 2006 20:03
    pmmisiek
    Poziom 15  

    Dzięki @szelus za listing programu, myślałem że dam rade zrozumieć coś z C ale myliłem się :) nie rozumię tego programiku.

    Mam jeszcze pytanie odnośnie:

    Cytat:
    1. skalujesz zmienną "a" do postaci z zakresu 0-32
    2. dzielisz "a/2" ( w assemblerze komenda div ab przy b=2 )
    3. wyświetlasz a pełnych kwadratów
    4. jeśli była reszta z dzielenia (w asm b<>0) to wyświetlasz jeszcze pół kwadratu
    5. wyświetlasz "16-a" spacji
    6. cofasz kursor o 16 pozycji i operacje powtarzasz od 1.





    Jak wyświetlać określoną liczbę pełnych kwadratów czy w pętli czy jakoś tak na if-ag czy jak?

    Pozdrawiam

    0
  • Pomocny post
    #5 24 Lis 2006 11:39
    szelus
    Specjalista - Mikrokontrolery

    Dobra, to teraz dam opis szczegółowy :)
    Wyświetlam pasek z dokladnością do 1 piksela (w poziomie) rezerwując do tego cztery znaki definiowane przez użytkownika. Dodatkowo cały pasek ma jednopikselową ramkę. Cały pasek zajmuje u mnie 7 znaków - czyli 35 pikseli. Minus po jednym pikselu z każdej strony na ramkę daje 33 piksele na pasek - akurat. :)
    Na wejściu podaję na ile procent pokazać pasek. Możesz to odpowiednio przeskalować.
    Na dzień dobry liczę ile pasków (pikseli) trzeba będzie wyświetlić:

    Code:

        bars = percentage / 3;

    Dla 100% ostatni pasek wlezie na ramkę, ale w tym wypadku to nie przeszkadza.
    Teraz pierwsze sześć znaków - ponieważ wyświetlam ramkę to i tak zawsze muszę wyświetlić wszystkie znaki, tylko trzeba wybierać odpowiednie.
    (Bez ramki możesz np. na początku wyczyścić odpowiedni kawałek wyświetlacza (np. spacjami), a potem w pętli wyświetlać tylko tyle znaków, ile trzeba.)
    W pętli zmienna bars pokazuje ile jeszcze pasków pozostało do wyświetlenia.
    Code:

        lcd_gotoxy(LCD_STATUS_BAR_START, LCD_STATUS_ROW);
        for (i = 0; i < 6; ++i)
        {

    O, tu jest bug! Czasami wyświetli o jeden pasek za dużo. Powinno się na początku dodać do bars 1 i tu sprawdzać na >= 5. Chodzi o to, czy wyświetlać cały pełny kwadrat, czy kawałek.
    Code:

            if (bars >= 4)
            {
                lcd_putc(LCD_CHAR_FULL_BAR);
                bars -= 5;
            }
            else if (bars > 0 || i == 0)
            {
                //install char with specified number of bars
                SetBarBeginChar(bars);
                lcd_gotoxy(LCD_STATUS_BAR_START + i, LCD_STATUS_ROW);
                lcd_putc(LCD_CHAR_BEGIN_BAR);
                bars = 0;
            }
            else
            {
                /* wyświetl tylko ramkę */
                lcd_putc(LCD_CHAR_EMPTY_BAR);
            }
        }

    Ostatni znak jest specjalny z uwagi na ramkę (ostatni pasek z prawej zawsze zapalony).
    Code:

        SetBarEndChar(bars);
        lcd_gotoxy(LCD_STATUS_BAR_START + 6, LCD_STATUS_ROW);
        lcd_putc(LCD_CHAR_END_BAR);

    Jak widać, graniczne znaki są zawsze kreowane dynamicznie, w zależności od tego, ile kresek trzeba wyświetlić.
    Bez ramki sprawa byłaby dużo prostsza - wystarczy jeden znak specjalny na granicy pola czarnego i białego, do którego przed wyświetleniem trzeba załadować takie wypełnienie, jakie jest potrzebne.
    Pozdrawiam.

    0