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

UART w AT89C2051 - nie działa sprzętowy UART, kod inicjalizacji i odbioru

Atlantis86 21 Mar 2017 21:49 2475 7
  • #1 16362307
    Atlantis86
    Poziom 19  
    Próbuję właśnie uruchomić pewien relatywnie prosty projekt na AT89C2051. Konieczne jest zastosowanie dwóch UART-ów, przy czym jeden z nich będzie pracował dosyć wolno, toteż w tym celu wykorzystana zostanie software'owa implementacja transmisji szeregowej. Z tym nie ma żadnego problemu - dość łatwo udało mi się przeportować bibliotekę z AVR-ów.

    Paradoksalnie nie chce jednak działać sprzętowy UART, chociaż jego obsługa mogłaby się wydawać czymś banalnym.

    Mój procedury inicjującej uart wygląda następująco:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    funkcja jest wywoływana w main(), a w pętli głownej umieściłem następujący kod:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kierunki linii portu chyba tez ustawiłem prawidłowo (P3 = 0x01).

    Niestety, znaki wysyłane do mikrokontrolera nie są odsyłane. Analizator stanów logicznych podłączony do linii TX niczego nie pokazuje.

    Projekt jest kompilowany za pomocą SDCC.

    Układ pracuje na kwarcu 11.059 MHz.

    Mam gdzieś błąd, którego nie dostrzegłem, czy winy powinienem raczej szukać po stronie sprzętowej? Fakt montażu na płytce stykowej może mieć jakieś znaczenie przy prędkości zaledwie 9600 bps?[/code]
  • #2 16362590
    JarekC
    Poziom 32  
    Odblokowujesz przerwanie od portu szeregowego:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Czy przypadkiem nie masz również odblokowanych globalnie przerwań (EA=1),
    jeżeli tak to możesz mieć sytuację że program cały czas znajduje się w obsłudze przerwania.
    Nic nie piszesz o przerwaniach ale możliwe że kompilator z automatu dodaje "pusta" obsługę wszystkich przerwań.

    JarekC
  • #3 16363235
    BlueDraco
    Specjalista - Mikrokontrolery
    Atlantis86 napisał:
    Kierunki linii portu chyba tez ustawiłem prawidłowo (P3 = 0x01).

    Niestety, znaki wysyłane do mikrokontrolera nie są odsyłane. Analizator stanów logicznych podłączony do linii TX niczego nie pokazuje.


    1. W 51 nie ustawia się kierunków portów. nie zapisuj nic do P3!
    2. Co to znaczy "nic nie pokazuje"? Coś pokazuje - zero albo jedynkę na ten przykład.
    3. Skąd Ci wyszła wartość 0xFD dla 9600?
  • #5 16363391
    Badmaneq
    Poziom 23  
    Tak jak napisał JarekC wywaliłbym odblokowanie przerwania od UART skoro nie korzystasz z przerwań dodatkowo napisałbym coś takiego:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #6 16363514
    lehastar
    Poziom 16  
    Mój kod
    
    /* UART Buffer Defines */
    #define UART_RX_BUFFER_SIZE 4     /* 2,4,8,16,32,64,128 or 256 bytes */
    #define UART_TX_BUFFER_SIZE 16
    
    
    #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
    #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
    	#error RX buffer size is not a power of 2
    #endif
    
    #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1 )
    #if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
    	#error TX buffer size is not a power of 2
    #endif
    
    //Flags
    #define UART_FLAG_TX_IN_PROGRESS	0x00
    #define UART_FLAG_TX_COMPLETE		0x01
    #define UART_FLAG_ERR			0x02
    
    volatile struct uart0_data
    {
    	unsigned char rx_buf[UART_RX_BUFFER_SIZE];
    	unsigned char rx_head; 
    	unsigned char rx_tail;
    	
    	unsigned char tx_buf[UART_TX_BUFFER_SIZE];
    	unsigned char tx_head; 
    	unsigned char tx_tail;
    	unsigned char flags;
    }uart;
    
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // Init UART0
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::
    void UART_Open(void)
    {
      SCON = 0x50;		        	//SCON: mode 1, 8-bit UART, enable rcvr
      TMOD |= 0x20;               	//TMOD: timer 1, mode 2, 8-bit reload
      TH1	= 0xFD;               		//TH1:  reload value for 9600 x 11.0592
      TR1 = 1;                  		//TR1:  timer 1 run              
      ES	= 1;						//Разрешить прерывание от UART
    }
    
    void UART_DisableReciveIRQ(void)
    {
    	REN = 0;
    }
    
    void UART_EnableReciveIRQ(void)
    {
    	RI = 0;
    	REN = 1;
    }
    
    unsigned char UART_Receive(void)
    {
      	unsigned char tmptail;
     
      	tmptail =  uart.rx_tail;
      	while (uart.rx_head == tmptail);
      	tmptail = (uart.rx_tail + 1) & UART_RX_BUFFER_MASK;
      	uart.rx_tail = tmptail;   
    
      	return uart.rx_buf[tmptail]; 
    }
    
    void UART_Transmit(unsigned char tx_data)
    {
    	unsigned char tmphead;
    
      	tmphead = (uart.tx_head + 1) & UART_TX_BUFFER_MASK;
      	while (tmphead == uart.tx_tail);
    
      	uart.tx_buf[tmphead] = tx_data;          
      	uart.tx_head = tmphead;  
    	
      	if((uart.flags & (1<<UART_FLAG_TX_IN_PROGRESS)) == 0)
    	{
    		TI = 1;
    		uart.flags |= (1<<UART_FLAG_TX_IN_PROGRESS);
    		uart.flags &= ~(1<<UART_FLAG_TX_COMPLETE);
    	}
    }
    
    void UART_Sendstr(char *strbuf)
    {
      	while (*strbuf != 0) UART_Transmit(*strbuf++);
    }
    
    unsigned char UART_DataInReceiveBuffer(void)
    {
      	unsigned char tmptail;
      	
      	tmptail =  uart.rx_tail;
      	return (uart.rx_head != tmptail); 
    }
    
    static void uart_int(void) interrupt SIO_VECTOR using 2
    {
    	volatile unsigned char tmphead;
    	volatile unsigned char tmptail;
    
    	if(RI)
    	{
    		tmphead = (uart.rx_head + 1) & UART_RX_BUFFER_MASK;
    		uart.rx_head = tmphead;
    		if(tmphead == uart.rx_tail)
    		{
    			//ERROR! Receive buffer overflow
    			uart.flags |= (1<<UART_FLAG_ERR);
    		}
    		uart.rx_buf[tmphead] = SBUF;
    
    		RI = 0;
    	 }
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    	if(TI)
    	{
    		tmptail = uart.tx_tail;
    		if(uart.tx_head != tmptail)
    		{
    			tmptail = (uart.tx_tail + 1) &	UART_TX_BUFFER_MASK;
    			uart.tx_tail = tmptail;
    			SBUF = uart.tx_buf[tmptail];
    		}
    			else
    				{
    					uart.flags &= ~(1<<UART_FLAG_TX_IN_PROGRESS);	
    					uart.flags |= (1<<UART_FLAG_TX_COMPLETE);
    				}
    		TI = 0;
    	}
    }
    
  • #7 16364797
    Atlantis86
    Poziom 19  
    [quote="BlueDraco"]
    Atlantis86 napisał:

    1. W 51 nie ustawia się kierunków portów. nie zapisuj nic do P3!


    Chwileczkę, a czy to przypadkiem nie działa analogicznie do PCF8574? To znaczy zero wpisane do rejestru Px oznacza, że dany pin jest wyjściem - to znaczy znajduje się na poziomie masy i może przyjmować prąd (więc LED-a trzeba do niego podłączyć katodą). Przy takim ustawieniu - nawet jeśli zastosuję zewnętrzny pull-up - próba odczytu zawsze zwróci zero.
    Natomiast jeśli wpiszę jedynkę, to włączy się słaby, wewnętrzny pull-up. Pin nie będzie w stanie dostarczyć większego prądu. Można go wtedy wykorzystać jako wejście, bo zwarcie pinu z masą spowoduje, że próba odczytu jego wartości zwróci zero.

    Chyba dobrze to interpretuję?

    Cytat:
    2. Co to znaczy "nic nie pokazuje"? Coś pokazuje - zero albo jedynkę na ten przykład.


    Pokazuje jeden stan (w tej chwili już nie pamiętam, a teraz nie mam pod ręką tego układu) - w każdym razie nie widać ani jednego zbocza opadającego czy narastającego. Dosłownie żadnej aktywności na pinie.

    Cytat:
    3. Skąd Ci wyszła wartość 0xFD dla 9600?


    Wartość używana praktycznie w każdym przykładzie z sieci i co najmniej jednej książce, którą miałem w dłoni.
  • #8 16364945
    BlueDraco
    Specjalista - Mikrokontrolery
    Jeśli zapiszesz do portu 0, to ustawisz jego linię w stan 0 - właśnie to zrobiłeś, więc zabiłeś transmisję. Zgaduję więc, że analizator pokazuje zero.
REKLAMA