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.

RS-232 + PC<->AVR + Simple Terminal

Ganz 05 Lis 2006 13:48 3557 15
  • #1 05 Lis 2006 13:48
    Ganz
    Poziom 17  

    Witam!

    Mam problrm ze skomunikowaniem ze sobą AT90S2313 z PC. Dysponuję zestawem uruchomieniowym ZL1AVR dedykowanym do książki J. Dolińskiego "Mikrokontrolery AVR w praktyce". W jednym z ćwiczeń przedstawionych w tej książce jest opisana właśnie komunikacja PC z AVR i sterowanie obrotami silnika prądu stałego.

    Dokumentacja płytki znajduje się tutaj:
    http://www.btc.pl/pdf/zl1avr.pdf

    Do procka wgrałem program. Do komunikacji używam prostego programu Simple Terminal i tu pojawia się problem. Nie mogę za nic przesłać żadnej wiadomości do uC. Program wypisuje mi komunikat, że nie ma urządzenia, albo że nie jest włączone.

    Czy ktoś wie gdzie może być przyczyna problemu?

    Ustawienia programu wyglądają tak:

    Port name: COM1
    Baud rate: 38400
    Data bits: 8
    Parity: none
    Stop bits: 1
    Hardware flow: none
    Software flow: none
    DTR control: Standard
    Device check: yes

    Natopmiast sam program wygląda następująco:

    Code:


    /********************************************************************/
    /* Ćwiczenie 8 - Zdalna regulacja obrotów silnika DC z komputera PC */
    /*               Modulacja PWM przy użyciu timera1                  */
    /*               Wykorzystanie UART-a do transmisji z komputerem    */
    /* J.D. '2003                                                       */
    /********************************************************************/

    #include <io.h>
    #include <progmem.h>
    #include <stdlib.h>
    #include <interrupt.h>
    #include <signal.h>

    #define FCPU      8000000    //częstotliwość oscylatora CPU
    #define VUART     38400      //prędkość transmisji [bit/s]
    #define VUBRR     FCPU/(VUART*16)-1    //wpis do UBRR dla VUART

    unsigned char romram;        //romram=1 => dane z pamięci programu
                                 //romram=0 => dane z RAM-u
    char *pfifosio;              //wskaźnik na kolejkę UART-u
    unsigned char volatile fodbznak=0;    //flaga: "odebrano znak"
    char komenda;                //odebrana komenda z PC-ta
    char *fifosio[];            //wskaźnik na kolejkę UART-u






    SIGNAL(SIG_UART_RECV)        //procedura obsługi odbiornika UART-u
    {
     komenda=UDR;                //zapamiętaj odebraną komendę
     fodbznak=1;                 //ustaw flagę odebrania znaku
    }

    SIGNAL(SIG_UART_TRANS)       //procedura obsługi nadajnika UART
    {                            //wywoływana po wysłaniu znaku
     char znak;

     if(romram)                  //skąd pobierać dane?
     {
      znak=PRG_RDB(pfifosio++); //pobierz daną z pamięci programu
     }
     else
     {
      znak=*pfifosio++;         //pobierz dane z pamięci RAM
     }
     if(znak!=0)                 //czy koniec pobierania danych?
     {
      UDR=znak;                  //nie, wyślij znak pobrany z kolejki
     }
     else
     {
      cbi(UCR,TXEN);             //tak, wyłącz nadajnik
     }
    }

    void czekaj(unsigned long zt) //procedura wytracania czasu
    {
     #define tau 10.38
     unsigned char zt1;
     for(;zt>0;zt--)
     {
      for(zt1=255;zt1!=0;zt1--);
     }
    }

    void wyslijtekstROM(char *tekst)  //wysyłanie danych z pamięci programu
    {
     romram=1;                   //dane będą z pamięci programu
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     sbi(UCR,TXEN);              //włącz nadajnik
     UDR=PRG_RDB(pfifosio++);   //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }

    void wyslijtekst(char *tekst)     //wysyłanie danych z pamięci programu
    {
     romram=0;                   //dane będą z pamięci danych
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     sbi(UCR,TXEN);              //włącz nadajnik
     UDR=*pfifosio++;           //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }

    int main(void)               
    {
     unsigned char i;
     unsigned char volatile licznikkl=0;  //zmienna wykorzystywana do pomiaru czasu
                                 //naciśnięcia przycisków

     char volatile przyrost=1;  //przyrost zmiany współczynnika wypełnienia sygnału PWM
     //tablica komunikatów do wysłania
     char *info[7]={
                    PSTR("\n\rRegulator obrotów silnika DC\n\r"),
                    PSTR(", - zmniejszanie obrotów\n\r"),
                    PSTR(". - zwiększanie obrotów\n\r"),
                    PSTR("0 - zatrzymanie silnika\n\r"),
                    PSTR("1 - start z max. obrotami\n\r"),
                    PSTR("N - podaj aktualne parametry sterownika\n\r\n"),
                    PSTR("\n\rAktualne parametry PWM:")
                   };

     union                       //unia pozwala na bajtowy dostęp do zmiennej int
          {
           unsigned int pwm;
           unsigned char pwmc[2];
          }volatile upwm;        //aktualny współczynnik wypełnienia sygn. PWM

     DDRB=0xff;    //PORTB - wy
     PORTB=0xff;   
     DDRD=0x02;    //PD1 - wy (RXD), pozostałe we
     PORTD=0x02;   //podciągania wejścia PD1 (RXD)
     UBRR=VUBRR;   //ustaw prędkość transmisji
     UCR=1<<RXCIE | 1<<TXCIE  | 1<<RXEN;   //zezwolenie na przerwania od
                       //odbiornika i nadajnika, zezwolenie na odbiór i nadawanie
     TCCR1A=0x83;      //PWM 10 bitowy
                       //zerowanie OC1 po spełnieniu warunku równości podczas liczenia
                       //w górę, ustawiane podczas liczenia w dół
     TCCR1B=0x01;      //preskaler=3, co przy 10-bit PWM daje Fwy=ok. 61Hz @8MHz
     TCNT1L=0x00;      //wstępne ustawienie licznika 1
     TCNT1H=0x00;
     upwm.pwm=0x3ff;   //początkowo silnik włączony, wartość TOP odpowiada wysokiemu
                       //poziomowi na wyjściu OC1 (PB3)
     OCR1H=upwm.pwmc[1];         //wpisz aktualnie ustawiony współczynnik do rejestrów
     OCR1L=upwm.pwmc[0];         //OCR1 timera1
     sei();            //włącz przerwania

     for(i=0;i<5;i++) //wyślij winietkę
     {
      wyslijtekstROM(info[i]);   //wysłanie pojedynczej linii tekstu
      while(bit_is_set(UCR,TXEN));    //trzeba zaczekać, aż zostanie wysłana do końca
     }

     while(1)          //główna pętla programu
     {
      if(fodbznak)          //czy odebrano jakiś znak?
      {
       fodbznak=0;          //tak
       switch (komenda)     //interpretacja komendy i wykonanie odpowiedniej akcji
       {
        case '.':                 //odebrano "." - zwiększ prędkość
                  upwm.pwm+=przyrost;       //zwiększ PWM
                  if(upwm.pwm>0x3ff)
                  {
                   upwm.pwm=0x3ff;    //jeśli przekroczono wartość TOP, to ustaw TOP
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;              //mierz długość naciśnięcia przycisku
                  break;
        case ',':                 //odebrano "," - zmniejsz prędkość
                  upwm.pwm-=przyrost;      //zmniejsz PWM
                  if(upwm.pwm>0x3ff)
                  {
                   upwm.pwm=0;        //jeśli przekroczono wartość zero to ustaw zero
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;        //mierz długość naciśnięcia przycisku
                  break;
        case '0':                //odebrano "0" - zatrzymaj silnik
                  upwm.pwm=0;    //silnik STOP
                  break;
        case '1':                //odebrano "1" - ustaw max obroty silnika
                  upwm.pwm=0x3ff;     //silnik na MAX
                  break;
        case 'n':
        case 'N':
                  wyslijtekstROM(info[6]);      //wysłanie pojedynczej linii tekstu
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  wyslijtekst("0x");       //wyślij prefiks dla liczb heksadecymalnych
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  itoa(upwm.pwm,fifosio,16);   //konwersja liczby int (hex)
                                                //na łańcuch znakowy
                  wyslijtekst(fifosio);        //wyślij aktualną wartość PWM do PC-ta
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  break;
       }
       if(licznikkl>6)
       {
        przyrost=+16;             //wykryto długie naciśnięcie klawisza,
                                  //zwiększ krok regulacji
        licznikkl=6;              //dalej już nie zwiększaj kroku
        cbi(PORTB,1);             //zapal diodę LED2
       }
       OCR1H=upwm.pwmc[1];        //wpisz aktualnie ustawiony współczynnik do rejestrów
       OCR1L=upwm.pwmc[0];        //OCR1 timera1
      }
      else
      {                           //jeśli cisza na linii, ustaw parametry spoczynkowe
       licznikkl=0;
       przyrost=1;
       sbi(PORTB,1);              //zgaś diodę LED2
      }
     }
    }



    Jeśłi ktoś jest w stanie pomóc mi dobrać ustawienia terminala to będę bardzo wdzięczny. To jest moje pierwsze podejście do RS-232 i w tym temacie nie orientuję się jeszcze najlepiej.

    P.S. Czy przyczyną problemu może być źłe polutowany kabel?
    U mnie jeśli spojrzeć na piny od strony zew. (nie tej po której się lutuje) to połączenia wyglądają następująco:
    2-2,
    3-3,
    5-5.
    Czy nie trzeba np. skrosować lini 2 i 3 (RXD iTXD)?

    0 15
  • #2 05 Lis 2006 15:56
    mirekk36
    Poziom 42  

    ... kolego - to oczywiste, że nie możesz łączyć wyjścia TxD AT90S2313 z wyjściem Tx na RS232 z PCta. TAK TRZEBA to skrosować ;) a poza tym zrób jeszcze tak:

    połącz we wtyczce (jeśli masz DB9) Pin6 z Pinem4 a następnie Pin7 z Pinem8. Poza tym podłącz swoją masę układu GND z Pinem5

    i transmisja powinna działać poprawnie (jeśli chodzi o hardware - bo nie analizowałem tego programu) ;)

    pozdrówka

    0
  • #3 05 Lis 2006 16:39
    Ganz
    Poziom 17  

    mirekk36 napisał:
    ... kolego - to oczywiste, że nie możesz łączyć wyjścia TxD AT90S2313 z wyjściem Tx na RS232 z PCta. TAK TRZEBA to skrosować ;) a poza tym zrób jeszcze tak:

    połącz we wtyczce (jeśli masz DB9) Pin6 z Pinem4 a następnie Pin7 z Pinem8. Poza tym podłącz swoją masę układu GND z Pinem5

    i transmisja powinna działać poprawnie (jeśli chodzi o hardware - bo nie analizowałem tego programu) ;)

    pozdrówka


    Witam!

    Od strony płytki wygląda to tak.

    RS-232 + PC<->AVR + Simple Terminal

    Jak widać są wykonane zapętlenia sygnałów na pinach 7 i 8 oraz 1,4 i 6. Przy wtyczne na PC tych zapętleń nie ma. Pin 5 jest podłączony do masy układu.

    Natomiast same połączenia kabelków na wtyczkach wyglądają następująco:

    RS-232 + PC<->AVR + Simple Terminal

    Jak widać połączone są piny 5-5, 2-2 i 3-3. Czy tak ma być?

    0
  • #4 05 Lis 2006 17:05
    kaczepa
    Poziom 19  

    Wersja uproszczone RS232 zlacze 9 pin

    DS9 DS9
    pin 5 <> pin 5 (Ground-Ground)
    pin 3 <> pin 2 (Transmit-Receive)
    pin 2 <> pin 3 (Receive-Transmit)
    Ekran <> Obudowa

    dodatkowo w kazdym ze zlacz zwieramy : pin4 z pin 6, pin7 z pin8.

    0
  • #5 05 Lis 2006 17:24
    mirekk36
    Poziom 42  

    ... teraz widzę w czym twój problem ;)

    ... otóż rysunek z tymi kabelkami jak go nazwałeś jest odnośnie połączeń jest poprawny - aczkolwiek opisy kierunków Rx i Tx są troszkę porąbane ;)

    ... u ciebie skrosowanie następuje już na twojej płytce - więc kabla nie musisz ruszać.

    nóżka T1OUT (14) z MAXa232 wychodzi na pin.2 we wtyczce DB9 czyli sygnał Tx z twojego układu idzie na Rx w PC , natomiast nóżka R1IN (13) z MAXa232 wychodzi na pin.3 we wtyczce DB9 czyli sygnał Tx z PC idzie do RxD twojego układu. Tu jest ten kros - spójrz sobie w notę katalogową MAX232 i wszystko stanie się jasne ;)

    zatem jeśli nic nie zmieniałeś w układzie ani w kablach to wszystko od strony sprzętowej powinno ci działać poprawnie a jeżeli tak nie jest to szukaj błędu po stronie programu ;)

    pozdrówka

    0
  • #6 05 Lis 2006 17:35
    kaczepa
    Poziom 19  

    Tak dla zasady , czy zworki JP2 i JP3 sa włożone prawidłowo ?

    Pozdrawiam

    0
  • #7 05 Lis 2006 21:47
    Ganz
    Poziom 17  

    kaczepa napisał:
    Tak dla zasady , czy zworki JP2 i JP3 sa włożone prawidłowo ?

    Pozdrawiam


    Na pewno są dobrze włożone. ;-)

    Cytat:

    zatem jeśli nic nie zmieniałeś w układzie ani w kablach to wszystko od strony sprzętowej powinno ci działać poprawnie a jeżeli tak nie jest to szukaj błędu po stronie programu


    Program wgrałem już skompilowany w takiej wersji, jaka jest zamieszczona na stronie. Nie komplilowałem i nie pisałem programu sam. Może problem tkwi w ustawieniach terminala? Czy ktoś używał tego programu i może mi pomóc go skonfigurować?

    0
  • #8 05 Lis 2006 22:12
    McRancor
    VIP Zasłużony dla elektroda

    Zrób prosty i znany test. Tam gdzie masz zworki J2 i J3 zewrzyj jedną z drugą, oby zewrzeć tym samym pin 11 i 12 Max232, wtedy powinieneś w oknie przychodzącym terminala otrzymać dokładnie to samo co wysyłasz, nie pamiętam jak wygląda ten terminal, ale poza otwarciem portu całą resztą możesz się na początku nie przejmować.

    Tym sposobem sprawdzisz poprawność pracy interfejsu, bo może to w nim tkwi błąd.

    Takie zwarcie nie zaszkodzi ani PCtowi, ani maxowi, ani AVRowi, jeśli zwarłbyś przez przypadek jego Tx i Rx

    0
  • #9 05 Lis 2006 22:35
    Ganz
    Poziom 17  

    McRancor napisał:
    Zrób prosty i znany test. Tam gdzie masz zworki J2 i J3 zewrzyj jedną z drugą, oby zewrzeć tym samym pin 11 i 12 Max232, wtedy powinieneś w oknie przychodzącym terminala otrzymać dokładnie to samo co wysyłasz, nie pamiętam jak wygląda ten terminal, ale poza otwarciem portu całą resztą możesz się na początku nie przejmować.

    Tym sposobem sprawdzisz poprawność pracy interfejsu, bo może to w nim tkwi błąd.

    Takie zwarcie nie zaszkodzi ani PCtowi, ani maxowi, ani AVRowi, jeśli zwarłbyś przez przypadek jego Tx i Rx


    Wykonałem ten test i niestety program nie reaguje. Nie widzę w oknie przychodzącym nic. :( Termina nawet nie widzi urządzenia. :(

    0
  • Pomocny post
    #10 05 Lis 2006 22:56
    McRancor
    VIP Zasłużony dla elektroda

    Czyli czeka Cie teraz kombinowanie z kablem, pewnie masz zamienione w kablu Rx z Txem (2 i 3 noga złącza 9-pinowego), sprawdź czy złącze odpowiedniej płci (takie jak producent płytki podał) bo może się okazać że masz przeciwne i przez to sygnały są na złych przewodach.

    Zacznij od zwarcia 2 i 3 nogi w porcie COM komputera, powinno być echo (to co nadajesz to dostajesz) i po kolei wyeliminujesz w ten sposób błędy...

    Sterowanie przepływem ustaw na brak i upewnij się że COM odpowiedni (czy nie masz go przełączonego w biosie na IrDA) i musi działać.

    0
  • #11 05 Lis 2006 23:42
    Ganz
    Poziom 17  

    McRancor napisał:
    Czyli czeka Cie teraz kombinowanie z kablem, pewnie masz zamienione w kablu Rx z Txem (2 i 3 noga złącza 9-pinowego), sprawdź czy złącze odpowiedniej płci (takie jak producent płytki podał) bo może się okazać że masz przeciwne i przez to sygnały są na złych przewodach.

    Zacznij od zwarcia 2 i 3 nogi w porcie COM komputera, powinno być echo (to co nadajesz to dostajesz) i po kolei wyeliminujesz w ten sposób błędy...

    Sterowanie przepływem ustaw na brak i upewnij się że COM odpowiedni (czy nie masz go przełączonego w biosie na IrDA) i musi działać.


    Więc tak. Złączki są dobrych płci. Dokładnie takie jak przewidział producent, ale z tego co przed chwilą wywnioskowałem numeracja żeńskich jest odbiciem lustrzanych męskich. Kiedy teraz zwieram pin 3 i 4, czyli 2 i 3 w odbiciu lustrzanym końcówki męskiej to wraca echo. To co wysyłam to odbieram.

    To może być dobry trop. :D

    Na razie idę spać. Jutro może skończę tą nierówną walkę.

    0
  • #12 06 Lis 2006 03:15
    mirekk36
    Poziom 42  

    Cytat:
    Kiedy teraz zwieram pin 3 i 4, czyli 2 i 3 w odbiciu lustrzanym


    pisząc to - pomyliłeś się? jak to zwierasz pin 3 i 4 ? nie może po drugiej stronie pin 2 i 3 zamienić się na 3 i 4 ;) chyba że coś z kablem jest źle. ;)

    weź sobie miernik i zmierz "zwarciowo" po jednej i drugiej stronie kabla powinieneś mieć zwarcie na pinach nr 2 oraz zwarcie na pinach nr 3

    pozdrówka

    0
  • #13 06 Lis 2006 12:29
    McRancor
    VIP Zasłużony dla elektroda

    Jak wsadzi się męskie złącze zamiast żeńskiego to właśnie taki cyrk powstaje, pamiętaj jeszcze o połączeniu mas! (w "oryginale" 5 noga COMa)

    0
  • #14 06 Lis 2006 16:57
    Ganz
    Poziom 17  

    No coż problem się rozwiązał głównie dzięki pomocy McRancor. Przyczyna problemów tkwiła w źle polutowanym przewodzie do RSa. Nie wziołem poprawki na to, że numeracja końcówki żeńskiej jest odbiciem lustrzanym męskiej.

    0
  • #15 07 Lis 2006 17:08
    Ganz
    Poziom 17  

    No coż transmisja działa na skompilowanym programie aż miło.

    Teraz przechodzę do napisania programu pod moje potrzeby. Na początek chciałem przenieść program napisany w starszej wersji kompilatora na nowszy. Chciałem, bo niestety mi się to nie udało. :( Naniosłem poprawki i skompilowałem program. Po wgraniu na uC silnik kręci się dość wolno, a powinien startować z max prędkością. Nie mogę też nim sterować. Oto miejsca, gdzie dokonałem zmian:

    1)

    Stara wersja:

    Code:

    #include <io.h>
    #include <progmem.h>
    #include <stdlib.h>
    #include <interrupt.h>
    #include <signal.h>


    Nowa:

    Code:

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


    2)

    Stara:
    Code:

    SIGNAL(SIG_UART_TRANS)       //procedura obsługi nadajnika UART
    {                            //wywoływana po wysłaniu znaku
     char znak;

     if(romram)                  //skąd pobierać dane?
     {
      [b]znak=PRG_RDB(pfifosio++); //pobierz daną z pamięci programu[/b]
     }
     else
     {
      znak=*pfifosio++;         //pobierz dane z pamięci RAM
     }
     if(znak!=0)                 //czy koniec pobierania danych?
     {
      UDR=znak;                  //nie, wyślij znak pobrany z kolejki
     }
     else
     {
      [b]cbi(UCR,TXEN);             //tak, wyłącz nadajnik[/b]
     }
    }


    Nowa:
    Code:

    SIGNAL(SIG_UART_TRANS)       //procedura obsługi nadajnika UART
    {                            //wywoływana po wysłaniu znaku
     char znak;

     if(romram)                  //skąd pobierać dane?
     {
      [b]znak=pgm_read_byte(pfifosio++); //pobierz daną z pamięci programu[/b]
     }
     else
     {
      znak=*pfifosio++;         //pobierz dane z pamięci RAM
     }
     if(znak!=0)                 //czy koniec pobierania danych?
     {
      UDR=znak;                  //nie, wyślij znak pobrany z kolejki
     }
     else
     {
      [b]UCR = (UCR & 0xF7);//cbi(UCR,TXEN);             //tak, wyłącz nadajnik[/b]
     }
    }


    3)

    Stara
    Code:

    void wyslijtekstROM(char *tekst)  //wysyłanie danych z pamięci programu
    {
     romram=1;                   //dane będą z pamięci programu
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     [b]sbi(UCR,TXEN);              //włącz nadajnik
     UDR=PRG_RDB(pfifosio++);   //wyślij pierwszy znak, pozostałe będą pobierane[/b]
                                 //w procedurze obsługi przerwania TXC
    }

    void wyslijtekst(char *tekst)     //wysyłanie danych z pamięci programu
    {
     romram=0;                   //dane będą z pamięci danych
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     [b]sbi(UCR,TXEN);              //włącz nadajnik[/b]
     UDR=*pfifosio++;           //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }


    Nowa:

    Code:

    void wyslijtekstROM(char *tekst)  //wysyłanie danych z pamięci programu
    {
     romram=1;                   //dane będą z pamięci programu
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     [b]UCR = (UCR | 0x08);//sbi(UCR,TXEN);              //włącz nadajnik
     UDR=pgm_read_byte(pfifosio++);   //wyślij pierwszy znak, pozostałe będą pobierane[/b]
                                 //w procedurze obsługi przerwania TXC
    }

    void wyslijtekst(char *tekst)     //wysyłanie danych z pamięci programu
    {
     romram=0;                   //dane będą z pamięci danych
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     [b]UCR = (UCR | 0x08);//sbi(UCR,TXEN);              //włącz nadajnik
     UDR=*pfifosio++;           //wyślij pierwszy znak, pozostałe będą pobierane[/b]
                                 //w procedurze obsługi przerwania TXC
    }


    4)
    Stara:
    Code:

    char *info[7]={
                    PSTR("\n\rRegulator obrotów silnika DC\n\r"),
                    PSTR(", - zmniejszanie obrotów\n\r"),
                    PSTR(". - zwiększanie obrotów\n\r"),
                    PSTR("0 - zatrzymanie silnika\n\r"),
                    PSTR("1 - start z max. obrotami\n\r"),
                    PSTR("N - podaj aktualne parametry sterownika\n\r\n"),
                    PSTR("\n\rAktualne parametry PWM:")
                   };


    Nowa:

    Code:

    char *info[7]={
                    "\n\rRegulator obrotów silnika DC\n\r",
                    ", - zmniejszanie obrotów\n\r",
                    ". - zwiększanie obrotów\n\r",
                    "0 - zatrzymanie silnika\n\r",
                    "1 - start z max. obrotami\n\r",
                    "N - podaj aktualne parametry sterownika\n\r\n",
                    "\n\rAktualne parametry PWM:"
                   };


    Podejrzewam, że problem może tkwić w funkcjach pgm_read_byte i PRG_RDB, a dokładnie w ich kompatybilności. W starszej wersji kompilatora była biblioteka <progmem.h>. W nowszej jej nie ma, ale szperając znalazłem <pgmspace.h>, ale nie wiem czy są to odpowiedniki. Jeśli ktoś ma pomysł gdzie może tkwić błąd to proszę o pomoc. Zmian w porównaniu z oryginałem nie ma dużo, więc dla takich specjalistów jak Wy nie będzie to problem. ;-)

    A pełne programy wyglądają nstępująco:

    Stara wersja:
    Code:

    #include <io.h>
    #include <progmem.h>
    #include <stdlib.h>
    #include <interrupt.h>
    #include <signal.h>

    #define FCPU      8000000    //częstotliwość oscylatora CPU
    #define VUART     38400      //prędkość transmisji [bit/s]
    #define VUBRR     FCPU/(VUART*16)-1    //wpis do UBRR dla VUART

    unsigned char romram;        //romram=1 => dane z pamięci programu
                                 //romram=0 => dane z RAM-u
    char *pfifosio;              //wskaźnik na kolejkę UART-u
    unsigned char volatile fodbznak=0;    //flaga: "odebrano znak"
    char komenda;                //odebrana komenda z PC-ta
    char *fifosio[];            //wskaźnik na kolejkę UART-u


    SIGNAL(SIG_UART_RECV)        //procedura obsługi odbiornika UART-u
    {
     komenda=UDR;                //zapamiętaj odebraną komendę
     fodbznak=1;                 //ustaw flagę odebrania znaku
    }

    SIGNAL(SIG_UART_TRANS)       //procedura obsługi nadajnika UART
    {                            //wywoływana po wysłaniu znaku
     char znak;

     if(romram)                  //skąd pobierać dane?
     {
      znak=PRG_RDB(pfifosio++); //pobierz daną z pamięci programu
     }
     else
     {
      znak=*pfifosio++;         //pobierz dane z pamięci RAM
     }
     if(znak!=0)                 //czy koniec pobierania danych?
     {
      UDR=znak;                  //nie, wyślij znak pobrany z kolejki
     }
     else
     {
      cbi(UCR,TXEN);             //tak, wyłącz nadajnik
     }
    }

    void czekaj(unsigned long zt) //procedura wytracania czasu
    {
     #define tau 10.38
     unsigned char zt1;
     for(;zt>0;zt--)
     {
      for(zt1=255;zt1!=0;zt1--);
     }
    }

    void wyslijtekstROM(char *tekst)  //wysyłanie danych z pamięci programu
    {
     romram=1;                   //dane będą z pamięci programu
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     sbi(UCR,TXEN);              //włącz nadajnik
     UDR=PRG_RDB(pfifosio++);   //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }

    void wyslijtekst(char *tekst)     //wysyłanie danych z pamięci programu
    {
     romram=0;                   //dane będą z pamięci danych
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     sbi(UCR,TXEN);              //włącz nadajnik
     UDR=*pfifosio++;           //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }

    int main(void)               
    {
     unsigned char i;
     unsigned char volatile licznikkl=0;  //zmienna wykorzystywana do pomiaru czasu
                                 //naciśnięcia przycisków

     char volatile przyrost=1;  //przyrost zmiany współczynnika wypełnienia sygnału PWM
     //tablica komunikatów do wysłania
     char *info[7]={
                    PSTR("\n\rRegulator obrotów silnika DC\n\r"),
                    PSTR(", - zmniejszanie obrotów\n\r"),
                    PSTR(". - zwiększanie obrotów\n\r"),
                    PSTR("0 - zatrzymanie silnika\n\r"),
                    PSTR("1 - start z max. obrotami\n\r"),
                    PSTR("N - podaj aktualne parametry sterownika\n\r\n"),
                    PSTR("\n\rAktualne parametry PWM:")
                   };

     union                       //unia pozwala na bajtowy dostęp do zmiennej int
          {
           unsigned int pwm;
           unsigned char pwmc[2];
          }volatile upwm;        //aktualny współczynnik wypełnienia sygn. PWM

     DDRB=0xff;    //PORTB - wy
     PORTB=0xff;   
     DDRD=0x02;    //PD1 - wy (RXD), pozostałe we
     PORTD=0x02;   //podciągania wejścia PD1 (RXD)
     UBRR=VUBRR;   //ustaw prędkość transmisji
     UCR=1<<RXCIE | 1<<TXCIE  | 1<<RXEN;   //zezwolenie na przerwania od
                       //odbiornika i nadajnika, zezwolenie na odbiór i nadawanie
     TCCR1A=0x83;      //PWM 10 bitowy
                       //zerowanie OC1 po spełnieniu warunku równości podczas liczenia
                       //w górę, ustawiane podczas liczenia w dół
     TCCR1B=0x01;      //preskaler=3, co przy 10-bit PWM daje Fwy=ok. 61Hz @8MHz
     TCNT1L=0x00;      //wstępne ustawienie licznika 1
     TCNT1H=0x00;
     upwm.pwm=0x3ff;   //początkowo silnik włączony, wartość TOP odpowiada wysokiemu
                       //poziomowi na wyjściu OC1 (PB3)
     OCR1H=upwm.pwmc[1];         //wpisz aktualnie ustawiony współczynnik do rejestrów
     OCR1L=upwm.pwmc[0];         //OCR1 timera1
     sei();            //włącz przerwania

     for(i=0;i<5;i++) //wyślij winietkę
     {
      wyslijtekstROM(info[i]);   //wysłanie pojedynczej linii tekstu
      while(bit_is_set(UCR,TXEN));    //trzeba zaczekać, aż zostanie wysłana do końca
     }

     while(1)          //główna pętla programu
     {
      if(fodbznak)          //czy odebrano jakiś znak?
      {
       fodbznak=0;          //tak
       switch (komenda)     //interpretacja komendy i wykonanie odpowiedniej akcji
       {
        case '.':                 //odebrano "." - zwiększ prędkość
                  upwm.pwm+=przyrost;       //zwiększ PWM
                  if(upwm.pwm>0x3ff)
                  {
                   upwm.pwm=0x3ff;    //jeśli przekroczono wartość TOP, to ustaw TOP
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;              //mierz długość naciśnięcia przycisku
                  break;
        case ',':                 //odebrano "," - zmniejsz prędkość
                  upwm.pwm-=przyrost;      //zmniejsz PWM
                  if(upwm.pwm>0x3ff)
                  {
                   upwm.pwm=0;        //jeśli przekroczono wartość zero to ustaw zero
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;        //mierz długość naciśnięcia przycisku
                  break;
        case '0':                //odebrano "0" - zatrzymaj silnik
                  upwm.pwm=0;    //silnik STOP
                  break;
        case '1':                //odebrano "1" - ustaw max obroty silnika
                  upwm.pwm=0x3ff;     //silnik na MAX
                  break;
        case 'n':
        case 'N':
                  wyslijtekstROM(info[6]);      //wysłanie pojedynczej linii tekstu
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  wyslijtekst("0x");       //wyślij prefiks dla liczb heksadecymalnych
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  itoa(upwm.pwm,fifosio,16);   //konwersja liczby int (hex)
                                                //na łańcuch znakowy
                  wyslijtekst(fifosio);        //wyślij aktualną wartość PWM do PC-ta
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  break;
       }
       if(licznikkl>6)
       {
        przyrost=+16;             //wykryto długie naciśnięcie klawisza,
                                  //zwiększ krok regulacji
        licznikkl=6;              //dalej już nie zwiększaj kroku
        cbi(PORTB,1);             //zapal diodę LED2
       }
       OCR1H=upwm.pwmc[1];        //wpisz aktualnie ustawiony współczynnik do rejestrów
       OCR1L=upwm.pwmc[0];        //OCR1 timera1
      }
      else
      {                           //jeśli cisza na linii, ustaw parametry spoczynkowe
       licznikkl=0;
       przyrost=1;
       sbi(PORTB,1);              //zgaś diodę LED2
      }
     }
    }


    Nowa wersja:

    Code:

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

    #define FCPU      8000000    //częstotliwość oscylatora CPU
    #define VUART     38400      //prędkość transmisji [bit/s]
    #define VUBRR     FCPU/(VUART*16)-1    //wpis do UBRR dla VUART

    unsigned char romram;        //romram=1 => dane z pamięci programu
                                 //romram=0 => dane z RAM-u
    char *pfifosio;              //wskaźnik na kolejkę UART-u
    unsigned char volatile fodbznak=0;    //flaga: "odebrano znak"
    char komenda;                //odebrana komenda z PC-ta
    char *fifosio[];            //wskaźnik na kolejkę UART-u


    SIGNAL(SIG_UART_RECV)        //procedura obsługi odbiornika UART-u
    {
     komenda=UDR;                //zapamiętaj odebraną komendę
     fodbznak=1;                 //ustaw flagę odebrania znaku
    }

    SIGNAL(SIG_UART_TRANS)       //procedura obsługi nadajnika UART
    {                            //wywoływana po wysłaniu znaku
     char znak;

     if(romram)                  //skąd pobierać dane?
     {
      znak=pgm_read_byte(pfifosio++); //pobierz daną z pamięci programu
     }
     else
     {
      znak=*pfifosio++;         //pobierz dane z pamięci RAM
     }
     if(znak!=0)                 //czy koniec pobierania danych?
     {
      UDR=znak;                  //nie, wyślij znak pobrany z kolejki
     }
     else
     {
      UCR = (UCR & 0xF7);//cbi(UCR,TXEN);             //tak, wyłącz nadajnik
     }
    }

    void czekaj(unsigned long zt) //procedura wytracania czasu
    {
     #define tau 10.38
     unsigned char zt1;
     for(;zt>0;zt--)
     {
      for(zt1=255;zt1!=0;zt1--);
     }
    }

    void wyslijtekstROM(char *tekst)  //wysyłanie danych z pamięci programu
    {
     romram=1;                   //dane będą z pamięci programu
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     UCR = (UCR | 0x08);//UCR = 1 << TXEN;//sbi(UCR,TXEN);              //włącz nadajnik
     UDR=pgm_read_byte(pfifosio++);   //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }

    void wyslijtekst(char *tekst)     //wysyłanie danych z pamięci programu
    {
     romram=0;                   //dane będą z pamięci danych
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     UCR = (UCR | 0x08);//UCR = 1 << TXEN;//sbi(UCR,TXEN);              //włącz nadajnik
     UDR=*pfifosio++;           //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }

    int main(void)               
    {
     unsigned char i;
     unsigned char volatile licznikkl=0;  //zmienna wykorzystywana do pomiaru czasu
                                 //naciśnięcia przycisków

     char volatile przyrost=1;  //przyrost zmiany współczynnika wypełnienia sygnału PWM
     //tablica komunikatów do wysłania
     char *info[7]={
                    "\n\rRegulator obrotów silnika DC\n\r",
                    ", - zmniejszanie obrotów\n\r",
                    ". - zwiększanie obrotów\n\r",
                    "0 - zatrzymanie silnika\n\r",
                    "1 - start z max. obrotami\n\r",
                    "N - podaj aktualne parametry sterownika\n\r\n",
                    "\n\rAktualne parametry PWM:"
                   };

     union                       //unia pozwala na bajtowy dostęp do zmiennej int
          {
           unsigned int pwm;
           unsigned char pwmc[2];
          }volatile upwm;        //aktualny współczynnik wypełnienia sygn. PWM

     DDRB=0xff;    //PORTB - wy
     PORTB=0xff;   
     DDRD=0x02;    //PD1 - wy (RXD), pozostałe we
     PORTD=0x02;   //podciągania wejścia PD1 (RXD)
     UBRR=VUBRR;   //ustaw prędkość transmisji
     UCR=1<<RXCIE | 1<<TXCIE  | 1<<RXEN;   //zezwolenie na przerwania od
                       //odbiornika i nadajnika, zezwolenie na odbiór i nadawanie
     TCCR1A=0x83;      //PWM 10 bitowy
                       //zerowanie OC1 po spełnieniu warunku równości podczas liczenia
                       //w górę, ustawiane podczas liczenia w dół
     TCCR1B=0x01;      //preskaler=3, co przy 10-bit PWM daje Fwy=ok. 61Hz @8MHz
     TCNT1L=0x00;      //wstępne ustawienie licznika 1
     TCNT1H=0x00;
     upwm.pwm=0x3ff;   //początkowo silnik włączony, wartość TOP odpowiada wysokiemu
                       //poziomowi na wyjściu OC1 (PB3)
     OCR1H=upwm.pwmc[1];         //wpisz aktualnie ustawiony współczynnik do rejestrów
     OCR1L=upwm.pwmc[0];         //OCR1 timera1
     sei();            //włącz przerwania

     for(i=0;i<5;i++) //wyślij winietkę
     {
      wyslijtekstROM(info[i]);   //wysłanie pojedynczej linii tekstu
      while(bit_is_set(UCR,TXEN));    //trzeba zaczekać, aż zostanie wysłana do końca
     }

     while(1)          //główna pętla programu
     {
      if(fodbznak)          //czy odebrano jakiś znak?
      {
       fodbznak=0;          //tak
       switch (komenda)     //interpretacja komendy i wykonanie odpowiedniej akcji
       {
        case '.':                 //odebrano "." - zwiększ prędkość
                  upwm.pwm+=przyrost;       //zwiększ PWM
                  if(upwm.pwm>0x3ff)
                  {
                   upwm.pwm=0x3ff;    //jeśli przekroczono wartość TOP, to ustaw TOP
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;              //mierz długość naciśnięcia przycisku
                  break;
        case ',':                 //odebrano "," - zmniejsz prędkość
                  upwm.pwm-=przyrost;      //zmniejsz PWM
                  if(upwm.pwm>0x3ff)
                  {
                   upwm.pwm=0;        //jeśli przekroczono wartość zero to ustaw zero
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;        //mierz długość naciśnięcia przycisku
                  break;
        case '0':                //odebrano "0" - zatrzymaj silnik
                  upwm.pwm=0;    //silnik STOP
                  break;
        case '1':                //odebrano "1" - ustaw max obroty silnika
                  upwm.pwm=0x3ff;     //silnik na MAX
                  break;
        case 'n':
        case 'N':
                  wyslijtekstROM(info[6]);      //wysłanie pojedynczej linii tekstu
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  wyslijtekst("0x");       //wyślij prefiks dla liczb heksadecymalnych
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  itoa(upwm.pwm,fifosio,16);   //konwersja liczby int (hex)
                                                //na łańcuch znakowy
                  wyslijtekst(fifosio);        //wyślij aktualną wartość PWM do PC-ta
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  break;
       }
       if(licznikkl>6)
       {
        przyrost=+16;             //wykryto długie naciśnięcie klawisza,
                                  //zwiększ krok regulacji
        licznikkl=6;              //dalej już nie zwiększaj kroku
       // cbi(PORTB,1);             //zapal diodę LED2
       }
       OCR1H=upwm.pwmc[1];        //wpisz aktualnie ustawiony współczynnik do rejestrów
       OCR1L=upwm.pwmc[0];        //OCR1 timera1
      }
      else
      {                           //jeśli cisza na linii, ustaw parametry spoczynkowe
       licznikkl=0;
       przyrost=1;
    //   sbi(PORTB,1);              //zgaś diodę LED2
      }
     }
    }
    [/b]

    0
  • #16 08 Lis 2006 16:33
    Ganz
    Poziom 17  

    No coż po całodziennych bojach udało mi się samemu dojść do rozwiązania problemu. Wreszcie mogę sobie sterować silnikiem. :) Kod programu zamieszczam poniżej. Może się komuś kiedyś przyda.

    W zasadzie jedyną rzeczą z którą nie mogę się sam uporać jest napisanie funkcji wysyłającej ciągi znaków. W starej wersji wyglądały one następująco:

    Code:

    SIGNAL(SIG_UART_TRANS)       //procedura obsługi nadajnika UART
    {                            //wywoływana po wysłaniu znaku
     char znak;

     if(romram)                  //skąd pobierać dane?
     {
      znak=PRG_RDB(pfifosio++); //pobierz daną z pamięci programu
     }
     else
     {
      znak=*pfifosio++;         //pobierz dane z pamięci RAM
     }
     if(znak!=0)                 //czy koniec pobierania danych?
     {
      UDR=znak;                  //nie, wyślij znak pobrany z kolejki
     }
     else
     {
      cbi(UCR,TXEN);             //tak, wyłącz nadajnik
     }
    }

    void wyslijtekstROM(char *tekst)  //wysyłanie danych z pamięci programu
    {
     romram=1;                   //dane będą z pamięci programu
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     sbi(UCR,TXEN);              //włącz nadajnik
     UDR=PRG_RDB(pfifosio++);   //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }

    void wyslijtekst(char *tekst)     //wysyłanie danych z pamięci programu
    {
     romram=0;                   //dane będą z pamięci danych
     pfifosio=tekst;            //ustaw wskaźnik na dane do wysłania
     sbi(UCR,TXEN);              //włącz nadajnik
     UDR=*pfifosio++;           //wyślij pierwszy znak, pozostałe będą pobierane
                                 //w procedurze obsługi przerwania TXC
    }


    a ich przykładowe wywołania

    Code:

    wyslijtekstROM(info[6]);      //wysłanie pojedynczej linii tekstu
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  wyslijtekst("0x");       //wyślij prefiks dla liczb heksadecymalnych
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  itoa(upwm.pwm,fifosio,16);   //konwersja liczby int (hex)
                                                //na łańcuch znakowy
                  wyslijtekst(fifosio);        //wyślij aktualną wartość PWM do PC-ta
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,


    Jeśłi ktoś ma jakieś fukcje realizujące podobne zadania to chętnie je wkomponuję w swój program. ;-) Sam nie mogę tego przejść. :/

    A to już mój sprawdzony i przetestowany program:

    Code:

    #include <avr\io.h>
    #include <stdlib.h>
    #include <avr\interrupt.h>
    #include <avr\signal.h>
    #include <avr\delay.h>

    #define FCPU 8000000 //częstotliwość oscylatora CPU
    #define VUART 38400 //prędkość transmisji [bit/s]
    #define VUBRR FCPU/(VUART*16)-1 //wpis do UBRR dla VUART

    unsigned char volatile odebrano_znak = 0; //flaga: "odebrano znak"
    char komenda; //odebrana komenda z PC-ta
    char znak = 'S';

    SIGNAL(SIG_UART_RECV) //procedura obsługi odbiornika UART-u
    {
     komenda = UDR;                //zapamiętaj odebraną komendę
     odebrano_znak = 1;                 //ustaw flagę odebrania znakuu
    }

    SIGNAL(SIG_UART_TRANS) //procedura obsługi nadajnika UART
    {

    }

    void czekaj(unsigned long zt) //procedura wytracania czasu
    {
     #define tau 10.38
     unsigned char zt1;
     for(;zt>0;zt--)
     {
      for(zt1 = 255;zt1 != 0;zt1--);
     }
    }

    void UART_out ( char data)    // wysłanie znaku
    {
       UCR = (UCR | 0x08);
       UDR = data;
       UCR = (UCR & 0xF7); 
    }

    int main(void)
    {
     // Konfiguracja portów
     DDRB = 0xff; //PORTB - wy
     PORTB = 0xff;
     DDRD = 0x02; //PD1 - wy (RXD), pozostałe we
     PORTD = 0x02; //podciągania wejścia PD1 (RXD)
     
     // Konfiguracja UARTA
     UBRR = VUBRR; //ustaw prędkość transmisji
     UCR = 1<<RXCIE | 1<<TXCIE | 1<<RXEN; //zezwolenie na przerwania od
     //odbiornika i nadajnika, zezwolenie na odbiór i nadawanie
     
     // Konfiguracja PWM
     unsigned char volatile licznikkl = 0;  //zmienna wykorzystywana do pomiaru czasu
                                 //naciśnięcia przycisków

     char volatile przyrost=1;  //przyrost zmiany współczynnika wypełnienia sygnału PWM
     
     union                       //unia pozwala na bajtowy dostęp do zmiennej int
     {
      unsigned int pwm;
      unsigned char pwmc[2];
     } volatile upwm;        //aktualny współczynnik wypełnienia sygn. PWM
     
     TCCR1A = 0x83;      //PWM 10 bitowy
                       //zerowanie OC1 po spełnieniu warunku równości podczas liczenia
                       //w górę, ustawiane podczas liczenia w dół
     TCCR1B = 0x01;      //preskaler=3, co przy 10-bit PWM daje Fwy=ok. 61Hz @8MHz
     TCNT1L = 0x00;      //wstępne ustawienie licznika 1
     TCNT1H = 0x00;
     upwm.pwm =0x000;   //początkowo silnik włączony, wartość TOP odpowiada wysokiemu
                       //poziomowi na wyjściu OC1 (PB3)
     OCR1H = upwm.pwmc[1];         //wpisz aktualnie ustawiony współczynnik do rejestrów
     OCR1L = upwm.pwmc[0];         //OCR1 timera1

     sei(); //włącz przerwania
     UART_out(znak);
     
     while(1) //główna pętla programu
     {
      if(odebrano_znak)          //czy odebrano jakiś znak?
      {
       odebrano_znak = 0;          //tak
       UART_out(komenda);
       switch (komenda)     //interpretacja komendy i wykonanie odpowiedniej akcji
       {
        case '.':                 //odebrano "." - zwiększ prędkość
                  upwm.pwm += przyrost;       //zwiększ PWM
                  if(upwm.pwm > 0x3ff)
                  {
                   upwm.pwm = 0x3ff;    //jeśli przekroczono wartość TOP, to ustaw TOP
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;              //mierz długość naciśnięcia przycisku
                  break;
        case ',':                 //odebrano "," - zmniejsz prędkość
                  upwm.pwm-=przyrost;      //zmniejsz PWM
                  if(upwm.pwm > 0x3ff)
                  {
                   upwm.pwm = 0;        //jeśli przekroczono wartość zero to ustaw zero
                  }
                  czekaj(150*tau);    //eliminacja powtórnej interpretacji
                                      //naciśnięcia przycisku
                  licznikkl++;        //mierz długość naciśnięcia przycisku
                  break;
        case '0':                //odebrano "0" - zatrzymaj silnik
                  upwm.pwm = 0;    //silnik STOP
                  break;
        case '1':                //odebrano "1" - ustaw max obroty silnika
                  upwm.pwm = 0x3ff;     //silnik na MAX
                  break;
        /*case 'n':
        case 'N':
                  wyslijtekstROM(info[6]);      //wysłanie pojedynczej linii tekstu
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  wyslijtekst("0x");       //wyślij prefiks dla liczb heksadecymalnych
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  itoa(upwm.pwm,fifosio,16);   //konwersja liczby int (hex)
                                                //na łańcuch znakowy
                  wyslijtekst(fifosio);        //wyślij aktualną wartość PWM do PC-ta
                  while(bit_is_set(UCR,TXEN));  //trzeba zaczekać,
                                                //aż zostanie wysłana do końca
                  break;*/
       }
       if(licznikkl>6)
       {
        przyrost =+ 20;             //wykryto długie naciśnięcie klawisza,
                                  //zwiększ krok regulacji
        licznikkl = 6;              //dalej już nie zwiększaj kroku
       }
       OCR1H = upwm.pwmc[1];        //wpisz aktualnie ustawiony współczynnik do rejestrów
       OCR1L = upwm.pwmc[0];        //OCR1 timera1
      }
      else
      {                           //jeśli cisza na linii, ustaw parametry spoczynkowe
       licznikkl = 0;
       przyrost = 1;
      }
     }
    }

    0