Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[At90S2313] [C] [VMLAB] Zapętla się GCC nadpisuje wskaź. SPL

Pawel1812 09 Oct 2008 02:16 1574 1
Testo
  • #1
    Pawel1812
    Level 26  
    Witam
    Od kilku dni staram się uruchomić program z książki Mikrokontrolery AVR w praktyce. Po dodaniu makr sbi i cbi program się skompilował, ale kompilator zwracał ostrzeżenia:
    
    Repeated variable name __c
    Repeated variable name __c within block. Rename it
    typedef debugging not supported
    COFF file contains inconsistencies or unsupported features. Debug info could be wrong or incomplete
    


    A w czasie wykonywania takie:
    
    [PC = $0156, Time =    3.62 ms, {MEM}]: Attempt to read in a forbidden/reserved position
    [PC = $0166, Time =    3.64 ms, {UND}]: Load indirect. Y index is undetermined
    [PC = $0067, Time =    3.76 ms, {UND}]: Stack pointer contains unknown data (X)
    

    W pewnym momencie kodu generowanego przez kompilator pojawia się komenda assemblerowa:
    
    out $3D, R28   
                          

    a w tym momencie zawartość rejestru R28 jest xxxxxxxx W kodzie asemblera umieściłem komentarze, co zapętla program.

    W rezultacie wskaźnik stosu przyjmuje wartość xxxxxxxx, dzięki czemu po instrukcji ret program nie może się połapać i się zapętla, gdyż nie jest w stanie wyjść z żadnej procedury.

    Byłbym bardzo wdzięczny za pomoc, gdzie leży błąd - program jest ok, wklejony ze strony www wydawnictwa BTC.

    Program wyglada tak:
    
    //#include <c:\winavr\avr\include\avr\io.h>
    //#include <c:\winavr\avr\include\avr\pr.h>
    //#include <c:\winavr\avr\include\avr\signal.h>
    #include <c:\winavr\avr\include\avr\io.h>
    #include <c:\winavr\avr\include\avr\pgmspace.h>
    #include <c:\winavr\avr\include\stdlib.h>
    #include <c:\winavr\avr\include\avr\sfr_defs.h>
    #define    PRG_RDB(addr)   pgm_read_byte(addr)
    
    #define lcd_rs 2             //definicja bitu portu dla linii RS
    #define lcd_e 3              //definicja bitu portu dla linii E
    #define CR 0x0a              //definicja znaku CR (przejście do nowej linii)
                #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) //definicja cbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    unsigned char wiersz=0;
    unsigned char kolumna=0;
    
    void czekaj(unsigned long pt) //procedura wytracania czasu
    {
    #define tau 10.38             //przybliżony przelicznik argumentu na ms
     unsigned char tp1;
    
     for(;pt>0;pt--)
     {
      for(tp1=255;tp1!=0;tp1--);
     }
    }
    
    void piszilcd(unsigned char instr) //zapisz instrukcję sterującą do LCD
    {
     cbi(PORTB,lcd_rs);
     sbi(PORTB,lcd_e);
     PORTB=(PORTB&0x0f)|(instr&0xf0);  //przygotuj starszy półbajt do LCD
     asm("nop");                       //wymagane wydłużenie impulsu
     asm("nop");
     asm("nop");
     cbi(PORTB,lcd_e);                 //impuls strobujący
     czekaj(10L);                      //czekaj na gotowość LCD ok. 100us
     sbi(PORTB,lcd_e);
     PORTB=(PORTB&0x0f)|((instr&0x0f)<<4);  //przygotuj młodszy półbajt do LCD
     asm("nop");
     asm("nop");
     asm("nop");
     cbi(PORTB,lcd_e);                 //impuls strobujący
     czekaj(10L);                      //czekaj na gotowość LCD ok. 100us
    }
    
    void piszdlcd(char dana)           //zapisz daną do LCD
    {
     sbi(PORTB,lcd_rs);
     sbi(PORTB,lcd_e);
     PORTB=(PORTB&0x0f)|(dana&0xf0);   //przygotuj starszy półbajt do LCD
     asm("nop");                       //wymagane wydłużenie impulsu
     asm("nop");
     asm("nop");
     cbi(PORTB,lcd_e);                 //impuls strobujący
     czekaj(10L);                      //czekaj na gotowość LCD
     sbi(PORTB,lcd_e);
     PORTB=(PORTB&0x0f)|((dana&0x0f)<<4); //przygotuj młodszy półbajt do LCD
     asm("nop");
     asm("nop");
     asm("nop");
     cbi(PORTB,lcd_e);                 //impuls strobujący
     czekaj(10L);                      //czekaj na gotowość LCD
    }
    
    void czysclcd(void)                //czyść ekran
    {
     piszilcd(0x01);      //polecenie czyszczenia ekranu dla kontrolera LCD
     czekaj(1.64*tau);    //rozkaz 0x01 wykonuje się 1.64ms
     wiersz=0;
     kolumna=0;
    }
    
    void piszznak(char znak)    //procedura umieszcza znak na wyświetlaczu
    {
     piszdlcd(znak);            //wyświetl znak na LCD
     if(++kolumna==16)          //czy bieżąca kolumna mieści się na wyświetlaczu?
     {
      kolumna=0;                //jeśli nie, to ustaw początkową...
      if(++wiersz==2)           //i przejdź do nowego wiersza
      {
       wiersz=0;       //jeśli nowy wiersz jest poza wyświetlaczem, ustaw początkowy
      }
     }
    }
    
    void lcdxy(unsigned char w, unsigned char k)    //ustaw współrzędne kursora
    {
     piszilcd((w*0x40+k)|0x80);  //standardowy rozkaz sterownika LCD
                                 //ustawiający kursor w określonych współrzędnych
    }
    
    void pisztekst(char *tekst)  //pisz tekst na LCD wskazywany pointerem *tekst
    {                 // ZAPĘTLENIE
     char zn;
     char nr=0;
    
     while(1)
     {
      zn=PRG_RDB(&tekst[nr++]);  //pobranie znaku z pamięci programu
      if(zn!=0)                  //czy nie ma końca tekstu?
      {
       if(zn==CR)                //czy znak nowej linii
       {
        wiersz==1?wiersz=0:++wiersz; //przejdź do nowej linii
        kolumna=0;
        lcdxy(wiersz,kolumna);   //ustaw obowiązujące po zmianie współrzędne na LCD
       }
       else
       {
        piszdlcd(zn);            //umieść pojedynczy znak tekstu na LCD
       }
      }
      else
      {
       break;                    //zakończ pętlę, jeśli koniec tekstu
      }
     }
    }
    
    void klawisz(unsigned char pozkl)  //czekaj na naciśnięcie określonego klawisza
                                       //klawisz jest wybierany poprzez argument pozkl
    {
     while(PIND&pozkl);                //czekaj na naciśnięcie klawisza
     czekaj(30*tau);                   //odczekaj aż ustaną zakłócenia
     while(!(PIND&pozkl));             //czekaj na zwolnienie klawisza
    }
    
    int main(void) //program główny
    {
     unsigned char i;
     //>>>>>>>>>>>>>    definicje tekstów wyświetlanych na LCD   <<<<<<<<<<<<<<
     char *tekst1=PSTR("kursor, mruga");
     char *tekst2=PSTR("bez kursora\nbez mrugania");
                                       // \n oznacza znak CR (przejście do nowej linii)
    
     //>>>>>>>>>>>>>>>>>>>>    konfigurowanie portów <<<<<<<<<<<<<<<<<<<<<<<<<<
     PORTD=0xff;   //port z podciąganiem
     PORTB=0x03;   //port z podciąganiem
     DDRD=0x00; //PORTD - we
     DDRB=0xff; //PORTB - wy
    
     //>>>>>>>>>>>>>>>>>>   inicjacja wyświetlacza LCD   <<<<<<<<<<<<<<<<<<<<<<
     czekaj(45*tau);        //opóźnienie ok. 45ms dla ustabilizowania się napięcia
                            //zasilania LCD (katalogowo min. 15 ms)
                            //lcd_rs już wcześniej było ustawione w stanie "0"
     for(i=0;i<3;i++)       //3-krotne wysłanie 3-
     {
      sbi(PORTB,lcd_e);
      PORTB=(PORTB&0x0f)|0x30; //wyślij 3- do LCD
      asm("nop");
      asm("nop");
      asm("nop");
      cbi(PORTB,lcd_e);
      czekaj(5*tau);      //ok. 5ms
     }
     sbi(PORTB,lcd_e);
     PORTB=(PORTB&0x0f)|0x20;  //wyślij 2- do LCD
     asm("nop");               //wymagane wydłużenie impulsu
     asm("nop");
     asm("nop");
     cbi(PORTB,lcd_e);
     czekaj(10L);        //od tego momentu można sprawdzać gotowość LCD
                         //w tym programie nie będzie sprawdzania gotowości
    
     piszilcd(0x28);     //interfejs 4-bitowy, 2 linie, znak 5x7
     piszilcd(0x08);     //wyłącz LCD, wyłącz kursor, wyłącz mruganie
     piszilcd(0x01);     //czyść LCD
     czekaj(1.64*tau);   //wymagane dla instrukcji czyszczenia ekranu opóźnienie
     piszilcd(0x06);     //bez przesuwania w prawo
    
     while(1)
     {
    //>>>>>>>>>>>>   EFEKT 1   <<<<<<<<<<<<<<<
      piszilcd(0x0f);    //włącz LCD, włącz kursor, włącz mruganie
      pisztekst(tekst1);
      klawisz(2);
      czysclcd();
    
    //>>>>>>>>>>>>   EFEKT 2   <<<<<<<<<<<<<<<
      piszilcd(0x0c);    //włącz LCD, bez kursora, bez mrugania
      pisztekst(tekst2);
      klawisz(2);
      czysclcd();
     }
    }
    


    A oto ten program w disassemblerze:
    
    ;    Generated by VMLAB AVR disassembler
    ;    ===================================
    ;
    
    .org $00
    l_0000:
       rjmp  l_001f
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       rjmp  l_0039
       ori   R22, $52
       and   R7, R10
       andi  R22, $5B
       andi  R23, $32
       andi  R22, $2F
       sbc   R6, R17
       ori   R22, $52
       and   R7, R10
       andi  R22, $2D
       ori   R23, $75
       ori   R22, $E1
       ori   R22, $19
       ori   R16, $B0
       andi  R23, $25
       ori   R23, $F3
       mov   R7, R2
       ori   R18, $D0
       andi  R23, $52
       ori   R22, $17
       nop
    l_001f:
       clr   R1
       out   $3F, R1
       ldi   R28, $DF
       out   $3D, R28
       ldi   R17, $00
       ldi   R26, $60
       ldi   R27, $00
       ldi   R30, $B6
       ldi   R31, $04
       rjmp  l_002c
    l_0029:
       lpm
       adiw  R30, $01
       st    X+, R0
    l_002c:
       cpi   R26, $60
       cpc   R27, R17
       brne  l_0029
       ldi   R17, $00
       ldi   R26, $60
       ldi   R27, $00
       rjmp  l_0034
    l_0033:
       st    X+, R1
    l_0034:
       cpi   R26, $62
       cpc   R27, R17
       brne  l_0033
       rcall main
       rjmp  l_0259
    l_0039:
       rjmp  l_0000
    
    
    
    czekaj:
       push  R29
       push  R28
       rcall l_003d
    l_003d:
       rcall l_003e
    l_003e:
       push  R0
       in    R28, $3D
       in    R29, $3E
       std   Y+2, R22
       std   Y+3, R23
       std   Y+4, R24
       std   Y+5, R25
       rjmp  l_005a
    l_0046:
       ldi   R24, $FF
       std   Y+1, R24
       rjmp  l_004c
    l_0049:
       ldd   R24, Y+1
       subi  R24, $01
       std   Y+1, R24
    l_004c:
       ldd   R24, Y+1
       tst   R24
       brne  l_0049
       ldd   R24, Y+2
       ldd   R25, Y+3
       ldd   R26, Y+4
       ldd   R27, Y+5
       sbiw  R24, $01
       sbc   R26, R1
       sbc   R27, R1
       std   Y+2, R24
       std   Y+3, R25
       std   Y+4, R26
       std   Y+5, R27
    l_005a:
       ldd   R24, Y+2
       ldd   R25, Y+3
       ldd   R26, Y+4
       ldd   R27, Y+5
       sbiw  R24, $00
       cpc   R26, R1
       cpc   R27, R1
       brne  l_0046
       pop   R0
       pop   R0
       pop   R0
       pop   R0
       pop   R0
       pop   R28
       pop   R29
       ret               Z POWODU WSKAŹNIKA STOSU BRAK REAKCJI NA RET
    piszilcd:
       push  R29
       push  R28
       push  R0
       in    R28, $3D
       ...
       ....
       st    X, R24
       ldi   R22, $0A
       ldi   R23, $00
       ldi   R24, $00
       ldi   R25, $00
       rcall czekaj         I TU POWRÓT DO PROCEDURY CZEKAJ W KÓŁKO
       ldi   R26, $38
       ldi   R27, $00
       ldi   R30, $38
       ldi   R31, $00
       ld    R24, Z
       ori   R24, $08
       st    X, R24
    
       ret
    pisztekst:
       push  R29
       push  R28
       in    R28, $3D
       in    R29, $3E
       sbiw  R28, $07
       in    R0, $3F
       cli
       out   $3E, R29
       out   $3F, R0
       out   $3D, R28 POLECENIE, KTÓRE ZAPĘTLA
       std   Y+7, R25
       std   Y+6, R24
       std   Y+4, R1
    l_017c:
       ldd   R24, Y+4
       mov   R18, R24
       ldi   R19, $00
       ldd   R24, Y+6
       ldd   R25, Y+7
       add   R24, R18
       adc   R25, R19
       std   Y+3, R25
       std   Y+2, R24
       ldd   R24, Y+4
       subi  R24, $FF
       std   Y+4, R24
       ldd   R30, Y+2
       ldd   R31, Y+3
       lpm
       mov   R24, R0
       std   Y+1, R24
       ldd   R24, Y+1
       std   Y+5, R24
       ldd   R24, Y+5
       tst   R24
       breq  l_01ae
       ldd   R24, Y+5
       cpi   R24, $0A
       brne  l_01ab
       lds   R24, $0060
       cpi   R24, $01
       brne  l_019c
       sts   $0060, R1
       rjmp  l_01a1
    l_019c:
       lds   R24, $0060
       subi  R24, $FF
       sts   $0060, R24
    l_01a1:
       sts   $0061, R1
       lds   R24, $0061
       lds   R25, $0060
       mov   R22, R24
       mov   R24, R25
       rcall lcdxy
       rjmp  l_017c
    l_01ab:
       ldd   R24, Y+5
       rcall piszdlcd
       rjmp  l_017c
    
       ...
    
  • Testo
  • Helpful post
    #2
    marek-c
    Level 19  
    
    
    Repeated variable name __c
    Repeated variable name __c within block. Rename it
    typedef debugging not supported
    COFF file contains inconsistencies or unsupported features. Debug info could be wrong or incomplete
    


    to musi zniknąć - pewnie jakieś problemy z bibliotekami...


    
    void czekaj(unsigned long pt) //procedura wytracania czasu
    {
    #define tau 10.38             //przybliżony przelicznik argumentu na ms
     unsigned char tp1;
    
     for(;pt>0;pt--)
     {
      for(tp1=255;tp1!=0;tp1--);
     }
    } 
    


    
     czekaj(1.64*tau);
    


    to ... moim skromnym zdaniem:
    1. zdaje się nie zadziała przez optymalizację, i ta pętla for(;pt>0;pt--)
    2. argument???? longint

    zamiast tego 'czekaj'

    
    #include avr/delay.h  //a może util/delay.h ??
    
    _delay_ms(x_ms);  //czeka x_ms milisekund
    
    _delay_us(x_us);  //czeka x_us mikrosekund
    


    Marek