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

[Atmega8][C] Obsługa przerwań.

twierzbik 02 Cze 2008 12:00 4590 18
  • #1 5205746
    twierzbik
    Poziom 10  
    Jestem początkujący w programowaniu mikrokontrolerów i mam problem z obsługą przerwań w Atmega8. Mam taki oto, bardzo prosty program znaleziony w sieci:

    #include <avr/io.h> 
    #include <avr/delay.h>
    #include <avr/interrupt.h> 
    
    #define F_CPU 1843200
    #define USART_BAUDRATE 19200 
    #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 
    
    int main (void) 
    { 
       UCSRB |= (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry 
       UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes 
    
       UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
       UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 
    
       UCSRB |= (1 << RXCIE); // Enable the USART Recieve Complete interrupt (USART_RXC) 
       sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed 
    
    	unsigned char i;
    	while (1) {
    		for (i='a';i<'z'+1;i++) 
    			{ 
    				while ( !( UCSRA & (1<<UDRE)) );
    				/* Put data into buffer, sends the data */
    				UDR = i;
    				_delay_ms(2000);
    			}
    		}
    } 
    
    ISR(USART_RXC_vect) 
    { 
       char ReceivedByte; 
       ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
       UDR = ReceivedByte; // Echo back the received byte back to the computer 
    }



    Program według mnie powinien wypisywać co 2 sekundy kolejną literkę i odpisywać znak, który odbierze na wejściu.
    Problem w tym, że nie odpisuje, lecz się resetuje- wnioskuję to po tym, że zaczyna od początku wysyłać alfabet. Wydaje mi się że chodzi o to że wywołuję przerwanie, ale go nie obsługuję- podobny efekt miałem przy wywołaniu przerwania na pinie INT0.

    Czy ktoś mógłby mi coś doradzić? Przeszukałem już pół internetu i każdy program realizujący odpisywanie na znak pojawiający się na wejściu wygląda niemal identycznie, ale u mnie nie działa.
    Pozdrawiam

    Poprawiłem tytuł:
    https://www.elektroda.pl/rtvforum/topic1015361.html
    Proszę umieszczać listingi programów w znacznikach "Code".
    [c_p]
  • #2 5205774
    don diego
    Poziom 32  
    Czy Twoja Mega8 pracuje z taką częstotliwością, jak zadeklarowałeś w programie?
  • #3 5205792
    twierzbik
    Poziom 10  
    Sądzę że tak- mam podłączony kwarc 1,8432 i fuse bits CKSEL3..0 1101
  • #5 5205966
    twierzbik
    Poziom 10  
    Echa tego, co przesyłam mu z komputera nie ma.
  • #7 5206292
    twierzbik
    Poziom 10  
    alfabet wypisuje, po wysłaniu do niego jakiegoś znaku następuje wypisywanie alfabetu od nowa. Czyli jak był na przykład przy literce 'p' 'q' 'r' to po wysłąniu do niego jakiegoś znaku wysyła 'a' 'b' 'c'...
  • #8 5211707
    bobbyAIR
    Poziom 20  
    Po pierwsze powinieneś pisać kod bardziej po bożemu czyli stosować rzutowania. Po drugie Atmega 8 domyślnie pracuje na 8 znakach i nie trzeba tego ustawiać. Upewnij się że masz wyłączoną w komputerze kontrole przepływu. Funkcja _delay_ms przeznaczona jest do pisania własnych opóźnień bo sama jest ograniczona i 2000 jako argument nie przyjmie. Według ciebie program wysyła co 2 sekundy. Według mnie cały czas bez przerwy ( dokumentacja _delay_ms:
    
       \ingroup util_delay
    
       Perform a delay of \c __ms milliseconds, using _delay_loop_2().
    
       The macro F_CPU is supposed to be defined to a
       constant defining the CPU clock frequency (in Hertz).
    
       The maximal possible delay is 262.14 ms / F_CPU in MHz.
    

    Niestety twój terminal na komputerze może mieć bufor. Do tego wyświetlanie trochę zajmuje. i po wysłaniu znaku możesz mieć tylko wrażenie że restartuje procesor. Choć nie mówię że tak nie może być. Warto jeszcze podwiesić reset procesora jeśli tego nie zrobiłeś. Dociągnąć masę z komputera do płytki ( nóżka 5 DB9)

    Kod warto napisać ładniej
    
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    
    #define F_CPU 1843200
    #define UART_BAUD         19200ul
    #define UART_CONST        (F_CPU/(16ul*UART_BAUD)-1)
    
    ISR(USART_RXC_vect)
    {
       char ReceivedByte;
       ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived"
       UDR = ReceivedByte; // Echo back the received byte back to the computer
    }
    void delay_ms(int ms){
    volatile unsigned int i;
    	for(i=0;i<ms;i++){
    		_delay_ms(1);
    }
    }
    int main (void)
    {
    
    UBRRH = (unsigned char)(UART_CONST>>8);
    UBRRL = (unsigned char)UART_CONST;
    UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
    SREG |= (1<<SREG_I);
    while(1){
          for (i='a';i<'z'+1;i++)
    {
                while ( !( UCSRA & (1<<UDRE)) );
                /* Put data into buffer, sends the data */
                UDR = i;
                delay_ms(2000);
    } 
    }
    return 0;
    }
    
    
    
    
  • #9 5212428
    twierzbik
    Poziom 10  
    Przepisałem Twój kod, nóżka 5 z DB9 jest podpięta do masy płytki. Dołożyłem do programu zapalanie diody na początku funkcji main() i wygląda na to, że program się po odebraniu znaku resetuje, bo dioda się zapala?


    #include <avr/io.h> 
    #include <avr/delay.h> 
    #include <avr/interrupt.h> 
    
    #define F_CPU 1843200 
    #define UART_BAUD         19200ul 
    #define UART_CONST        (F_CPU/(16ul*UART_BAUD)-1) 
    #define LED_ON DDRB |=1<<PB1;PORTB|=1<<PB1
    #define LED_OFF DDRB |=1<<1; DDRB&=~1<<PB1
    
    
    ISR(USART_RXC_vect) 
    { 
       char ReceivedByte; 
       ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
       UDR = ReceivedByte; // Echo back the received byte back to the computer 
    } 
    void delay_ms(int ms){ 
    volatile unsigned int i; 
       for(i=0;i<ms;i++){ 
          _delay_ms(1); 
    } 
    } 
    int main (void) 
    { 
    
    UBRRH = (unsigned char)(UART_CONST>>8); 
    UBRRL = (unsigned char)UART_CONST; 
    UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE); 
    SREG |= (1<<SREG_I); 
    
    LED_ON;
    delay_ms(500);
    LED_OFF;
    
    while(1){ 
    	volatile unsigned int i;
          for (i='a';i<'z'+1;i++) 
    { 
                while ( !( UCSRA & (1<<UDRE)) ); 
                /* Put data into buffer, sends the data */ 
                UDR = i; 
                delay_ms(2000); 
    } 
    } 
    return 0; 
    } 
    
    
  • #10 5217664
    bobbyAIR
    Poziom 20  
    A jak podłączyłeś konwerter napięć? Czy podwiesiłeś pin resetu ?
  • #11 5217726
    twierzbik
    Poziom 10  
    Konwerter napięć? Mam zasilanie z dwóch baterii- paluszków (Atmega 8L) lub zasilacza bezpośrednio do pinu zasilania. Pin reset dołączony do zasilania.
  • #12 5217964
    mirekk36
    Poziom 42  
    twierzbik kolega powyżej pytając cię o konwerter napięć miał na myśli to czy zastosowałeś po bożemu na linii RS232 pomiędzy prockiem a PC'tem konwerter w postaci np układu MAX232 (albo MAX3232 w twoim przypadku jeśli zasilasz układ z 3V) albo chociaż jakiś prosty tranzystorowy - a nie o jakieś zasilanie z paluszków, baterii itp - to po pierwsze

    .... a pin reset czy jest "podwieszony" czyli czy jest podłączony przez jakiś rezystor do VCC

    pozdr
  • #13 5217982
    twierzbik
    Poziom 10  
    Na oba pytania odpowiedź twierdząca- podłączone do PC przez MAX3232, ewentualnie (bo o to chodzi w projekcie) bezpośrednio do modułu Bluetooth. W obu przypadkach efekt ten sam- reset mikroprocesora po wysłaniu doń znaku lub wywołaniu przerwania INT0. Pin reset- podwieszony.
  • #15 5218029
    twierzbik
    Poziom 10  
    A patrząc na kod programu?
  • #16 5219705
    BoskiDialer
    Poziom 34  
    w kodzie programu jedyne niepokojące jest to, że F_CPU jest deklarowane PO dołączeniu delay.h (ja to deklaruję na poziomie pliku Makefile "-D F_CPU=$(F_CPU)"). Sprawdź też, czy plik jest kompilowany na atmega8, bo jeśli wybierzesz inny, to kompilator nie zaprotestuje, a wektory przerwań mogą się różnić, tudzież wywołanie przerwania bez kodu obsługi przerwania doprowadzi do resetu (tablica wektorów przerwań wypełniona skokami [pośrednio] pod adres 0) jeśli chcesz, to możesz też przetestować mój kod, który raczej będzie działał.
  • #17 5229874
    twierzbik
    Poziom 10  
    Znalazłem wreszcie źródło problemów. Wynikały one z jakości wykonanej przeze mnie płytki uruchomieniowej- miałem zwarcie na RXD i RESET. Wiem- żenada. Bardzo dziękuję wszystkim za pomoc.
  • #18 5229906
    BoskiDialer
    Poziom 34  
    U mnie ten makefile nie działa, nie ma tam opisane jak zbudować plik '.o'. Po poprawieniu binarka wychodzi taka sama twoim makefilem jak i moim (kompilując mój soft), więc nie wiem co może być nie tak.

    Wrzucam soft+makefile oraz hex i bin skompilowane (dla kwarcu 1843200) u mnie. Jeśli to będzie działać, znaczy problem z makefile lub środowiskiem, jeśli nie, to coś z układem, chyba, że coś jednak zrobiłem nie tak w sofcie (chociaż na symulatorze wygląda na to, że wszystko powinno działać).
  • #19 5232606
    zumek
    Poziom 39  
    twierzbik napisał:
    ... Bardzo dziękuję wszystkim za pomoc.


    Zamykam.
REKLAMA