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

Problem z programem '51, przerwania od transmisji szeregowej

15 Wrz 2003 12:21 1139 5
  • Poziom 11  
    Witam,
    mam dziwny problem z moim programem na '51(w C). Bawiłem się w transmisję szregową i utknąłem.
    Programik jest prosty: bufor odbiorczy na przerwaniu - wpisuje mu coś z klawiatury (HyperTerminal)
    on odbiera i umieszcza to w buforze, potem wypisuje funkcją printf to co tam jest. Problem w tym,
    że jeśli użyje funkcji delay() to program sie wiesza przy wywolaniu następnego printf().
    Bez delay() wszystko działa tylko wypisuje na wyjście bardzo szybko zawartości bufora.

    Używam Raisonance RIDE51 6.10.10 i mam płytkę prototypową z SAB80C537N(dlatego inne rejestry np.EAL)
    Korzystałem z kursu w EP.
    Oto program:

    #pragma DEFJ(TIM1_INIT=0xFD) //COM0 - 9600, mnoznik x2 = 19200
    #include <reg_517.h>
    #include <stdio.h>
    #pragma SMALL

    char bufor[16]; // mały buforek
    unsigned char licznik = 0; //indeks
    sbit led = P1^0; //dioda

    void UART_irq(void) interrupt 4
    {

    if(TI0!=0) //tego przerwania nie używam, ale zaraz na początku programu generowało sie samo (?!)
    //i wpadał w pętle, dlatego dałem zerowanie flagi TI
    {

    TI0 = 0;

    }

    if(RI0!=0)
    {
    RI0=0;
    bufor[licznik]=S0BUF;
    licznik++;
    if(licznik == 16) licznik = 0;
    }


    }

    void delay(unsigned int k)
    {
    unsigned int i,j;
    for (j = 0; j < k; j++)
    for (i = 0; i <= 84; i++);
    }


    void UART0_init(void)
    {
    EAL=0; //ogólne zezwolenie na przerwania
    ES=0; //zezwolenie na przerwania od transmisji szer.
    PCON |= 0x80; //ustawienie mnoznika na x2
    REN0 = 1; //zezwolenie na odbior
    SM0=0;SM1=1;
    SM20=0;
    printf("\n\nZainicjowano UART0...\n");
    TI0=RI0=0;

    }

    void main(void)
    {
    UART0_init();
    EAL=1; //włączam przerwania
    ES=1;

    while(1) //to jest główna część i problem
    {
    EAL=0; //przed printf() wyłączam przerwania bo gdy nie wyłączyłem to zwis
    printf(">>%s<<",bufor); //wypisuje bufor
    EAL=1; //włączam przerwanie
    delay(5000); //bez tej funkcji program działa, z nią nie. Wykona ją - przeskoczy linijke niżej (led = 0)
    // = oświeci diodę, wróci na początek pętli i zawiesi się na funkcji printf()
    led = 0; //to dodałem żeby upewnić się w którym miejscu wiesza się
    }

    }
    ---------------------------------------------------------------
    Z funkcją delay w terminalu:

    Zainicjowano UART0...
    >><<
    (delay, potem zapala diodę)

    ...i wisi...

    a bez delay() wszystko OK tylko, że strasznie śmiga :) (ale wpisuje z klawiatury a on ładnie
    mi wypisuje co napisałem...)

    Co jest grane? Za wszelką pomoc z góry dziękuję.

    >>Lantis<<
    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
  • Poziom 33  
    Zajrzyj do biblioteki, w której jest funkcja delay(), prawdopodobnie opóźnienie jest generowane na pdostawie liczenia cykli maszynowych i dla dokładności pomiaru są wyłączane przerwania.
    Zrób sobie to opóźnienie samodzielnie (np z użyciem timera) i daj znać - w razie kłopotów będziemy myśleć dalej.
    BTW to zapis if(RI0!=0) można zastąpić czymś takim: if(RI0) - C powstało dla leniwych programisów...
    Tu też: licznik++; if(licznik == 16) licznik = 0;
    if (licznikk++ == 16) {....}
  • Poziom 11  
    Funkcję delay() zdefiniowałem sam (patrz kod programu)
    void delay(unsigned int k)
    {
    unsigned int i,j;
    for (j = 0; j < k; j++)
    for (i = 0; i <= 84; i++);
    }

    Zauważyłem też, że zamiast delay() można wstawić dowolną funkcję
    korzystającą z pętli i dzieje się to samo....

    >>Tu też: licznik++; if(licznik == 16) licznik = 0;
    if (licznikk++ == 16) {....}<< -- to by nie działało...
    a to tak: if (++licznik == 16){...} :)
  • Poziom 33  
    Fakt, przeoczyłem....
    To sprawdź czy przy asemblacji (powinien być taki plik, moliwe że z rozszeżeniem .lst, w którym jest kod asm) przy wejściu do podprogramów kompilator odkłada na stosie wszystkie używane w funkcji rejestry.
  • Poziom 11  
    Już na coś wpadłem: printf() używa putchar() a ta funkcja wygląda mniej
    więcej tak

    void putchar(char c)
    {
    do{}while(!TI)
    TI=0;
    SBUF = c;
    }

    Jeśli TI=0 to znaczy że znak nie został jeszcze nadany. Sterownik tr. szeregowej w momencie kiedy nada już znak, automatycznie ustawia
    TI na 1.Kiedy włącze przerwania TI=1, a gdy TI=1 to generowane jest przerwanie od transmisji szeregowej.W obsłudze przerwania ...if(TI!=0)...
    flaga jest zerowana. Następne wywołanie funkcji putchar() napotyka TI=0
    czyli myśli że znak nie został jeszcze nadany i utyka w ...do{}while(!TI)...
    Przydałoby się wymyślić sposób na bezkolizyjne stosowanie przerwań i funkcji printf()
  • Poziom 33  
    Jak rozumie wysyłasz te dane spowrotem do PC po RS?
    To wykozystaj do wysyłania to przerwanie, które i tak już obsługuje, tylko że wtedy twój bufor musi działaś jak kolejka (w sumie to bufor pierścieniowy). Chodzi o to, że masz dwa indeksy do tgo bufora, jeden wskazuje miejsce w które ma być wpisywana nowa dana (czyli pierwszy wolny element), a drugi index wskazuje na element do wysłania. Musisz jedynie pilnować żeby się wzajemnie nie wyorzedziły bo to spowoduje błąd. Ale w Twoim przypadku ne powinno to być takie trudne, tym bardziej, że 51 posiadają fullduplex UART i w zasadzie można to odsyłać w czasie rzeczywistym.

    BTW to z tym: "..>>Tu też: licznik++; if(licznik == 16) licznik = 0;
    if (licznikk++ == 16) {....}<< -- to by nie działało...
    a to tak: if (++licznik == 16){...} .." masz ooczywiście rację - moje przeoczenie;)