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

USART - drobny problem z właczaniem portu

mały_zrw 03 Gru 2010 20:15 1639 13
REKLAMA
  • #1 8821878
    mały_zrw
    Poziom 10  
    Witam serdecznie.

    Napisałem bardzo prosty kod do obsługi UARTu. Jest on w pełni sprawny. ATmega128 z zewnętrznym kwarcem 14745600Hz.
    Problem polega na tym, że gdy komunikuję się za pomocą terminala to gdy wcisnę na klawiaturze literę "w" dioda podłączona do PD4 świeci ciągle.
    Nie chcę by świeciła ona ciągle, a jedynie wtedy, gdy przytrzymam "w". Gdy puszczę dioda ma zgasnąć.
    Stosunkowo bardzo proste się to wydaje, ale nie mogę jakoś sobie z tym poradzić :|

    Kod programu:
    /* Prędkość transmisji 9600 */
    #define BAUD 9600
    #define MYUBRR  F_CPU/BAUD/16-1
    
    #include <stdio.h>
    #include <avr/io.h>
    #include <util/delay.h>
    
    
    /************** Inicjuje port szeregowy AVRa ************/
    void USART_init(unsigned int myubrr)
    {
        /* Ustala prędkość transmisji */
        UBRR0H = (unsigned char)(myubrr>>8);
        UBRR0L = (unsigned char)myubrr;
    
        /* Włącza nadawanie i odbiór*/
        UCSR0B = (1<<RXEN) | (1<<TXEN);
      
        /* Format ramki: 1 bit stopu, 8 bitów danych */
        UCSR0C = (0<<USBS0)| (1<<UCSZ1) | (1<<UCSZ0);
    }
    
    
    /***************** Funkcja nadawania znaku ********************/
    void uart_putc(uint8_t data)
    {
    	/* Oczekiwanie na zakończenie nadawania */
    	while(!(UCSR0A & (1<<UDRE0)));
    	
    	/* Wysyłanie danych */
        UDR0 = data;
    
    }
    
    
    /***************** Funkcja odbioru znaku **********************/
    uint8_t uart_getc(void)
    {
    	/* Sprawdzanie danych w buforze */
        while ( !(UCSR0A & (1 << RXC)) );
    	
    	/* Dane z bufora */
        return UDR0;
    }
    
    
    /*************** Funkcja wysyłająca ciąg znaków ***************/
    void uart_puts(const char *s )
    {
    	while (*s) 
    		uart_putc(*s++);
    }
    
    
    /**************** Funkcja włączajaca port PD4 *****************/
    void przycisk(uint8_t c)
    {
    	if (c=='w')
    		{
    		PORTD =_BV(PD4);
    		}
    
    }
    
    /******** Głowna funkcja*******/
    int main(void)
    {
    DDRD=0xFF; //Wszystkie linie portu D będą wyjściami
    uint8_t c; //deklaracja zmiennej c
      
    USART_init(MYUBRR); //inicjalizacja UARTa
    
    
    	uart_puts("Witaj!\r\n");
    
    
        while(1)
      {
      		c = uart_getc();
    		przycisk(c);
    
      }
    }
    
  • REKLAMA
  • Pomocny post
    #2 8821944
    landy13
    Poziom 31  
    Jeśli włączysz diodę to musisz ją też wyłączyć.
    /**************** Funkcja włączajaca port PD4 *****************/
    void przycisk(uint8_t c)
    {
       if (c=='w')
          {
          PORTD |= 1<<4;
          }
       else
          {
           PORTD &= ~(1<<4);
           }
    } 
  • REKLAMA
  • #3 8822005
    mały_zrw
    Poziom 10  
    landy13
    Podmieniając moją funkcję na Twoją nic to nie dało. Program nadal działa tak jak przedtem.
    To co zaproponowałeś włączy diodę i tak, a zgasi ją w przypadku gdy zmienna "c" nie będzie już miała wartości "w". Nastąpi to dopiero gdy wcisnę każdy inny przycisk niż "w" na klawiaturze, bo "c" wtedy zostanie nadpisane.

    Problem polega na tym, by operować tylko i wyłącznie literą "w". jeśli ją trzymam na klawiaturze to na PD4 ma być stan wysoki, a gdy jest puszczony to ma być stan niski.

    Dziękuję za zainteresowanie tematem, ale nadal problem jest nierozwiązany...
  • REKLAMA
  • #4 8822038
    landy13
    Poziom 31  
    Więc w funkcji odbioru znaku jeśli bufor pusty zeruj zmienną c.
  • Pomocny post
    #5 8822065
    Andrzej__S
    Poziom 28  
    Myślę, że jedynym sposobem jest odbieranie danych z USARTa za pomocą przerwań. W programie należałoby ustawić jakieś opóźnienie i sprawdzać cyklicznie, czy nadszedł nowy znak. Jeśli w określonym czasie (zależnym od częstotliwości "powtarzania" klawiatury) nie nadejdzie nowy znak to diodę wyłączyć, jeśli nadejdzie i jest to 'w' to zapalić.

    landy13 napisał:

    Więc w funkcji odbioru znaku jeśli bufor pusty zeruj zmienną c.

    Zauważ, że w przypadku kiedy transmisja jest zatrzymana (klawisz puszczony) program ugrzęźnie na instrukcji c = uart_getc(); wewnątrz funkcji uart_getc() czekając na ustawienie flagi RXC.
  • #6 8822102
    landy13
    Poziom 31  
    Andrzej__S napisał:

    Zauważ, że w przypadku kiedy transmisja jest zatrzymana (klawisz puszczony) program ugrzęźnie na instrukcji c = uart_getc(); wewnątrz funkcji uart_getc() czekając na ustawienie flagi RXC.
    Zgdza się. Masz rację.
  • #7 8894427
    mały_zrw
    Poziom 10  
    Kombinuję by zrobić to na przerwaniach. Mam jednak problem.
    Pytania:
    1) Jak sprawdzić czy bufor jest pusty?
    2) Czym mogę wyczyścić bufor?

    Proszę o odpowiedź w postaci komend.

    Na razie jest tak:

    /***************** Funkcja odbioru znaku **********************/
    volatile uint8_t uart_getc(void)
    {	
    	/* Sprawdzanie danych w buforze */
    	while ( !(UCSR0A & (1 << RXC0)) );
    	
    	/* Dane z bufora */
        return UDR0;
    }



    /**************** Funkcja włączajaca port PD4 *****************/
    void przycisk(volatile uint8_t c)
    {
    	if (c=='w')
    		{
    		PORTD =_BV(PD4);
    		}
    	else
          	{
           	PORTD &= ~(1<<4);
           	} 
    }


    /******** Głowna funkcja*******/
    int main(void)
    {
    	DDRD=0xFF;			//Wszystkie linie portu D będą wyjściami
    	USART_init(MYUBRR); //inicjalizacja UARTa
    	uart_puts("Witaj!\r\n");
    	sei();
    
        while(1)
     	{
    	}	
    }
    
    ISR(USART0_RX_vect)
    {
    	uart_getc();
    	przycisk(UDR0);
    }


    3) Dobrze kombinuję ??

    Wskazane odpowiedzi na pytania i inne cenne uwagi i wskazówki....
  • #8 8909758
    Fredy
    Poziom 27  
    nie widzę odblokowania przerwań od odebranego znaku przez UART. Samo SEI nie wystarczy.
  • #9 8914556
    mały_zrw
    Poziom 10  
    Fredy - nie wiem o co Ci chodzi.
    Przedstawiam najnowszy program.
    Trochę pozmieniałem. Całość dlatego, by łatwiej było pomóc.
    uC sczytuje znak co 0,05s w przerwaniach. Mam jednak problem, bo zupełnie nie wiem dlaczego się tak zachowuje... dokładniej:
    Po uruchomieniu terminala nawiązaniu komunikacji, gdy wcisnę na klawiaturze coś zupełnie innego niż literę "w" dioda podłączona do PD4 nie świeci (to jest ok). Gdy wcisnę "w" jednokrotnie, to mi mrugnie i to też jest w porządku.
    Jednak, gdy wcisnę od razu "w" i trzymam to dioda LED mrugnie, wygasi się i dalej już się świeci nieustannie dopóki nie puszczę "w".
    Nie wiem jaka jest przyczyna że się nie świeci ciągle od razu a na chwilę się wygasza. Co poprawić w kodzie by to działało już dobrze??

    /* Prędkość transmisji 9600 */
    #define BAUD 9600
    #define MYUBRR  F_CPU/BAUD/16-1
    
    
    #include <stdio.h>
    #include <avr/io.h>
    #include <avr/interrupt.h> 
    
    
    #define F_CPU 14745600
    #define CZAS_PRZYCISKU 0.05
    
    volatile uint8_t a;
    
    
    /************** Inicjuje port szeregowy AVRa ************/
    void USART_init(unsigned int myubrr)
    {
        /* Ustala prędkość transmisji */
        UBRR0H = (unsigned char)(myubrr>>8);
        UBRR0L = (unsigned char)myubrr;
    
        /* Włącza nadawanie i odbiór*/
        UCSR0B = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE0);
      
        /* Format ramki: 1 bit stopu, 8 bitów danych */
        UCSR0C = (0<<USBS0)| (1<<UCSZ1) | (1<<UCSZ0);
    }
    
    
    /***************** Funkcja nadawania znaku ********************/
    void uart_putc(uint8_t data)
    {
    	/* Oczekiwanie na zakończenie nadawania */
    	while(!(UCSR0A & (1<<UDRE0)));
    	
    	/* Wysyłanie danych */
        UDR0 = data;
    
    }
    
    
    /***************** Funkcja odbioru znaku **********************/
    volatile uint8_t uart_getc(void)
    {	
    	/* Sprawdzanie danych w buforze */
    	 UCSR0A = (1 << RXC0);
    	
    	/* Dane z bufora */
    	return UDR0;
    
    }
    
    
    /*************** Funkcja wysyłająca ciąg znaków ***************/
    void uart_puts(const char *s )
    {
    	while (*s) 
    		uart_putc(*s++);
    }
    
    
    /**************** Funkcja włączajaca port PD4 *****************/
    
    void przycisk(uint8_t c)
    {
    	if (c=='w')
    		{
    		PORTD =_BV(PD4);
    		}
    	else
          	{
           	PORTD &=~_BV(PD4);
           	} 
    }
    
    
    	
    /******** Głowna funkcja*******/
    int main(void)
    {
    
    	DDRD=0xFF;			//Wszystkie linie portu D będą wyjściami
    	USART_init(MYUBRR); //inicjalizacja UARTa
    	uart_puts("Witaj!\r\n");
    
    	TCCR1B |= (1 << WGM12); 		//Ustawia TIMER1 w tryb CTC str.100
    	OCR1A = (int)((F_CPU*CZAS_PRZYCISKU)/1024)-1; 			// Ustawia ilość cykli do zliczenia str.89
    	TCCR1B |= ((1 << CS10) | (1 << CS12)); 	//Prescaler na F_CPU/1024 str.100
    	TIMSK |= (1 << OCIE1A); 		//Zezwolenie na przerwania dla CTC str.102
    	sei(); 				//Zezwolenie globalne na przerwania
    
    
        while(1)
     	{}	
    }
    
    ISR(USART0_RX_vect)
    {
    	a=uart_getc();		
    	uart_putc(a);
    }	
    
    		
    ISR(TIMER1_COMPA_vect)
    {	
    	przycisk(a);
    	a=0;
    }
    
    
    
    
  • #10 8924209
    LordBlick
    VIP Zasłużony dla elektroda
    W założeniu czai się prozaiczny błąd logiczny - skoro klawiatura jest podłączona do PC, to µC nie jest w stanie oceniać, czy dany klawisz jest wciśnięty, może jedynie dostać coś po RS. A co dostaje to już jest kwestia oprogramowania na PC, złożonego z procedur obsługi klawiatury, systemu operacyjnego i programu terminala. Jeśli chcesz badać rzeczywisty stan klawiatury, podłącz ją do mikrokontrolera i oprogramuj jej obsługę... ;)
  • REKLAMA
  • #11 8924269
    sulfur
    Poziom 24  
    Prawdopodobnie do mikrokontrolera trafia inny znak lub znaki. Obstawiam powrót karetki lub znak nowej linii. Jeśli moja teoria jest prawdziwa, poniższy kod powinien wyeliminować tą właściwość.
    if (c=='w') 
          { 
          PORTD =_BV(PD4); 
          } 
       else if(c!='\n'&&c!='\r')
             { 
              PORTD &=~_BV(PD4); 
              }
  • #12 8930478
    mały_zrw
    Poziom 10  
    Korzystam z niżej załączonego Terminala.
    Podobnie program działa na HyperTerminal w moim Systemie XP.

    sulfur
    Twoje przypuszczenia chyba są błędne. Proponowany kod się kompiluje oczywiście, ale nie przynosi rezultatu. Nadal bez zmian - dioda mignie zanim świeci się ciągle przy nieustannie wciśniętym przycisku "w".

    Problem nadal pozostaje nierozwiązany, a ja nie mam pomysłu dlaczego on się tak zachowuje i tym bardziej jak to zlikwidować :cry:
  • Pomocny post
    #13 8931358
    Andrzej__S
    Poziom 28  
    mały_zrw napisał:

    Po uruchomieniu terminala nawiązaniu komunikacji, gdy wcisnę na klawiaturze coś zupełnie innego niż literę "w" dioda podłączona do PD4 nie świeci (to jest ok). Gdy wcisnę "w" jednokrotnie, to mi mrugnie i to też jest w porządku.
    Jednak, gdy wcisnę od razu "w" i trzymam to dioda LED mrugnie, wygasi się i dalej już się świeci nieustannie dopóki nie puszczę "w".

    Terminal nie wysyła informacji o tym, czy klawisz jest wciśnięty, czy też nie jest. Terminal otrzymuje znaki z klawiatury poprzez system operacyjny i wtedy je wysyła. System operacyjny przekazuje znaki do terminala mniej więcej w następujący sposób:
    #1 Po wciśnięciu klawisza przekazuje znak do terminala.
    #2 Czeka czas określony przez parametr o nazwie "Opóźnienie powtarzania" (w systemie Windows: Panel sterowania/Klawiatura/zakładka "Szybkość"). Ten czas jest zwykle wystarczająco długi, by zauważyć mignięcie diody.
    #3 Jeśli klawisz jest nadal wciśnięty - wysyła następny znak do terminala.
    #4 Czeka czas określony przez parametr "Częstotliwość powtarzania" (w Panelu sterowania jak wyżej). Ten czas jest zwykle dosyć krótki i można mieć wrażenie, że dioda świeci cały czas.
    #5 Jeżeli klawisz jest nadal wciśnięty wraca do punktu 3 i tak w kółko.

    Reakcja mikrokontrolera jest prawidłowa, czyli odbiera znaki tak jak są wysyłane. Można oczywiście zmniejszyć "Opóźnienie powtarzania" w "Panelu sterowania" i wtedy dioda będzie gasła na krótszy czas, ale na innym komputerze w zależności od ustawień systemu operacyjnego będzie inaczej.

    Cytat:

    Nie wiem jaka jest przyczyna że się nie świeci ciągle od razu a na chwilę się wygasza. Co poprawić w kodzie by to działało już dobrze??

    Chcesz mieć pełną kontrolę nad klawiaturą - zrób tak jak wcześniej już radził Light-I - podłącz ją bezpośrednio do mikrokontrolera, bo poprzez USART i terminal nie uzyskasz zamierzonego efektu.
  • #14 8933920
    mały_zrw
    Poziom 10  
    OK.... rozumiem :|
    Dzięki wielkie za pomoc :D

    Ten temat już zamykam.
    Tak jak mówicie, wszytko działa poprawnie, jedynie problem z systemem i klawiaturą, a to już zupełnie inna bajka.
REKLAMA