logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

89s52 - UART przerwanie - program wchodzi w pętlę, działa tylko w debugerze

max666 21 Sie 2006 22:14 1925 7
REKLAMA
  • #1 2939065
    max666
    Poziom 13  
    Posty: 94
    Pomógł: 2
    Ocena: 8
    Witam.
    Mam malutki problem z przerwaniem z UART'a. Otoz program wchodzi do przerwania i w nim zostaje, wykonujac je ciagle. W debugerze wszystko dziala swietnie a w rzeczywistosci ... niestaty nie. Nizej zalaczam listing programu. Srodowisko keil, procek 89s52.

    Cytat:
    #include <AT89X52.H>
    #include <stdio.h>
    #define FREQ 3686400L //czestotliwosc Rezonatora

    //#define AdresR 0xD0;
    //#define AdresW 0xD1;

    sbit przek2=P2^0;
    sbit przek1=P2^1;
    sbit dioda3=P2^5;
    sbit dioda2=P2^6;
    sbit dioda1=P2^7;
    sbit SDA=P1^2;
    sbit SCL=P1^1;
    unsigned char bufor[10]=0;

    void uart_ini(void) //inicjalizacja uart
    {
    SCON = 0x52; //52
    TMOD = 0x20;
    TCON = 0x69;
    TH1=0xF8; //predkosc 1200bps
    TR1=1;

    }

    void Delay (unsigned int k)
    {
    unsigned int i,j;
    for (j=0; j<k; j++)
    for (i=0; i <=50; i++); //standart 24
    }


    void UART_irq(void) interrupt 4 using 2
    {
    unsigned char bufor;
    if (RI == 1) {
    RI=0; //zerowanie flagi “do_odbioru”
    //ES=0; //probowalem blokowac przerwania z RS - bez skutecznie
    printf("odebrano znak \n"); //zadanie mialo tylko informowac o odebranym znaku
    //Delay(100);
    //bufor=getchar();
    }

    //ES=1;
    }


    void main () // petla glowna programu
    {
    uart_ini();
    RI=0;
    EA=1; //zezwolenie na przerwania
    ES=1; //przerwanie z uartu.


    while (1)
    {

    printf("r \n");
    Delay(100);
    } //koniec petli programu


    } //koniec programu
  • REKLAMA
  • #2 2939132
    mskalski
    Poziom 14  
    Posty: 106
    Pomógł: 9
    Ocena: 7
    A jak jest zaimplementowany printf() w Keil-u? Z tego co pamiętam, to w Keil-u domyślna implementacja polegała na sformatowaniu tekstu i wysłaniu go do RS-a (dawno nie ruszałem Keila ani C dla 51, w sumie nigdy go nie używałem, gdyż dla mnie UART był wtedy niedostępny, więc mogę sie mylić).

    Jeśli tak jest, a z drugiej strony w Twoim kodzie w obsłudze przerwania brak jest zerowania flagi potwierdzenia wysłania znaku TI w rejestrze SCON, więc co chwila zgłaszane jest przerwanie. Możliwe też, że Twoja procedura zakłóca implementację printf() w Keil-u.

    Myślę, że bezpieczniej byłoby podłączyć do którejś nóżki procesora diodę i nią "mrygać" w takt odbieranych znaków, ewentualnie zrobić echo. :-)
  • REKLAMA
  • #3 2939392
    max666
    Poziom 13  
    Posty: 94
    Pomógł: 2
    Ocena: 8
    dorzucilem jeszcze w petli przerwania to:

    if (TI != 0)
    {
    TI = 0;
    }


    efekt ten sam. Odnosnie printf to juz probowalem nawet z putchar'em i bez wysylania znaku w petli while (1).

    Koniec nie na moje zdolnosci. Prosze o pomoc

    dzieki
  • REKLAMA
  • #4 2939474
    mskalski
    Poziom 14  
    Posty: 106
    Pomógł: 9
    Ocena: 7
    Tu nie chodzi o nie wysyłanie znaku w pętli głównej programu, tylko o nie używanie go w przerwaniu. Sam printf chyba nic nie miesza, jako, że operuje tylko na pamięci, znaki wypisuje używając właśnie putchar().
    Jedyna rzecz, która mogłaby być niewskazana jest taka, że funkcja printf() chyba nie jest wielowejściowa (reentrant), czyli jednoczesne wywołanie z głównego kodu a potem z przerwania może coś namieszać.

    Właśnie obejrzałem kod funkcji putchar (z jakiejś starej wersji Keil'a):
    
    /***********************************************************************/
    /*  This file is part of the C51 Compiler package                      */
    /*  Copyright KEIL ELEKTRONIK GmbH 1990 - 1999                         */
    /***********************************************************************/
    /*                                                                     */
    /*  PUTCHAR.C:  This routine is the general character output of C51.   */
    /*                                                                     */
    /*  To translate this file use C51 with the following invocation:      */
    /*                                                                     */
    /*     C51 PUTCHAR.C <memory model>                                    */
    /*                                                                     */
    /*  To link the modified PUTCHAR.OBJ file to your application use the  */
    /*  following L51 invocation:                                          */
    /*                                                                     */
    /*     L51 <your object file list>, PUTCHAR.OBJ <controls>             */
    /*                                                                     */
    /***********************************************************************/
    
    #include <reg51.h>
    
    #define XON  0x11
    #define XOFF 0x13
    
    char putchar (char c)  {
    
      if (c == '\n')  {
        if (RI)  {
          if (SBUF == XOFF)  {
            do  {
              RI = 0;
              while (!RI);
            }
            while (SBUF != XON);
            RI = 0; 
          }
        }
        while (!TI);
        TI = 0;
        SBUF = 0x0d;                         /* output CR  */
      }
      if (RI)  {
        if (SBUF == XOFF)  {
          do  {
            RI = 0;
            while (!RI);
          }
          while (SBUF != XON);
          RI = 0; 
        }
      }
      while (!TI);
      TI = 0;
      return (SBUF = c);
    }
    


    Jak widać ewidentnie mieszane jest coś z flagami od portu UART - nie wiem, czy właśnie tego putchar() używasz.

    Ja bym to zrobił tak, że w przerwaniu tylko ustawiałbym jakiś znacznik bitowy, że jakiś znak nadszedł, zaś ten znacznik byłby sprawdzany w pętli głównej programu i ewentualnie wypisywany. Choć w sumie można w takim wypadku zrezygnować z przerwań i sprawdzać bit RI w pętli głównej :-).
  • REKLAMA
  • #5 2942193
    max666
    Poziom 13  
    Posty: 94
    Pomógł: 2
    Ocena: 8
    Miales racje z tym printf. Wywalilemn z petli przerwania i zaczelo dzialac, chodz nie tak jak bym sobie zyczyl. Za kazdym razem czyta petle przerwania. Nie wiem dlaczego ciagle jest w tym przerwaniu. Jakies pomysly?

    pozdrawiam MB
  • #6 2942301
    mskalski
    Poziom 14  
    Posty: 106
    Pomógł: 9
    Ocena: 7
    Możesz pokazać, jaki asembler jest generowany z tego pliku w "C" - może po tym da się dojść do rozwiązania?

    Nie pamiętam tylko, jakie opcje trzeba dać kompilatorowi, by uzyskać ten plik asemblerowy.

    Może też pomóc mapa pamięci.
  • #7 2943182
    szymtro
    Poziom 30  
    Posty: 1421
    Pomógł: 101
    Ocena: 59
    Z tego co widać w pokazanym fragmencie to procedurka putchar i printf działa niezależnie od przerwań. Schemat jest zawsze taki sam.
    Najpier poczeka na gotowosc portu do wysyłania (aż TI bediz emiało 0) następnie wysyła do sbuf znak i znowu czeka na zmianę TI na zero (wysłanie znaku). printf dodatkowo ma pętlę i licznik powtórzeń/znaków do wysłąnia.

    Z tego co widac to próbujesz pomieszać sprzętowy uart z softwareowym - dlatego takie dziwne sytuacje.

    Moja rada - albo całkowicie przejdź na software i wyłącz przerwanie uart albo napisz całe wysyłanie na przerwaniach (bufory wysyłajacy i odbierajacy plus liczniki znaków do tego)
  • #8 2953492
    max666
    Poziom 13  
    Posty: 94
    Pomógł: 2
    Ocena: 8
    Mala korekta (REN=1) i juz wchodzi do przerwania ale co dziwne, tylko raz. Nastepnie aby znow wszedl, reset i jest ok. Aktualnie kod wyglada tak:

    #include <AT89X52.H>
    #include <stdio.h>
    #define FREQ 3686400UL //czestotliwosc Rezonatora

    //#define AdresR 0xD0;
    //#define AdresW 0xD1;

    sbit przek2=P2^0;
    sbit przek1=P2^1;
    sbit dioda3=P2^5;
    sbit dioda2=P2^6;
    sbit dioda1=P2^7;
    sbit SDA=P1^2;
    sbit SCL=P1^1;
    unsigned char bufor[10]=0;

    void uart_ini(void) //inicjalizacja uart
    {
    SCON = 0x52; //52
    TMOD = 0x20;
    TCON = 0x69;
    REN=1;
    TH1=0xF8; //predkosc 1200bps
    TR1=1;

    }

    void Delay (unsigned int k)
    {
    unsigned int i,j;
    for (j=0; j<k; j++)
    for (i=0; i <=50; i++); //standart 24
    }



    void UART_irq(void) interrupt 4 using 2
    {
    unsigned char bufor;


    RI=0;
    P2=0;
    P2=255;
    Delay(1000);
    P2=0;


    }

    void main () // petla glowna programu
    {
    uart_ini();
    RI=0;
    TI=0;
    EA=1;
    ES=1;


    while (1)
    {
    P2=0;
    Delay(100);
    P2=0x80;
    Delay(100);

    } //koniec petli programu


    } //koniec programu

    Dziekuje i prosze o dalsze podpowiedzi.


    Dalsze perypetie i doswiadczenie wreszcie czyms zaowocowaly. Przerwanie dziala, problem jedynie w tym iz, gdy dam w niej putchara, getchara, lub printf to sie wieza w tym miejscu.

    Szafa gra, nie dopatryzlem ale tda5051 powoduje efekt echa lokalnego, odbiera znak ktory sam nadal, i to bylo problemem wskoku do petli i pozostawania w niej.

    Pozdrawiam i dziekuje.

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemu z przerwaniem UART w mikrokontrolerze 89S52 programowanym w środowisku Keil. Program wchodzi do procedury przerwania i pozostaje w niej, wykonując ją ciągle, co nie występuje podczas debugowania. Przyczyną jest brak odpowiedniego zerowania flagi TI w rejestrze SCON, co powoduje ciągłe wywoływanie przerwania. Używanie funkcji printf() lub putchar() w obsłudze przerwania jest niewskazane, ponieważ printf nie jest reentrantny i może kolidować z przerwaniem. Zalecane jest unikanie wywołań printf w przerwaniu lub całkowite przejście na obsługę UART wyłącznie sprzętową lub programową z odpowiednimi buforami i licznikami. Po poprawieniu ustawienia bitu REN i zerowaniu flag przerwań, przerwanie UART wchodzi poprawnie, ale nadal pojawia się problem z ciągłym pozostawaniem w procedurze przerwania. Wskazano potrzebę analizy generowanego kodu asemblerowego i mapy pamięci w celu dalszej diagnostyki. Przykładowy kod inicjalizacji UART i obsługi przerwania został przedstawiony, gdzie w przerwaniu zerowana jest flaga RI i wykonywana jest prosta sekwencja sygnalizująca odbiór danych.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA