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

[atmega8][c/c++] Problem z usart, dostaje tylko 3 znaki

chrupex 12 Lip 2009 23:50 1319 4
REKLAMA
  • #1 6771494
    chrupex
    Poziom 11  
    Witam wszystkich!
    Mam pewien problem, który co prawda rozwiązałem, ale rozwiązanie te mnie nie zadowala. Do rzeczy. Postanowiłem napisać funkcję, która jako argument pobiera napis i po znaku wklada do UDR'a. Najpierw mój program wyglądał tak:

    
    #define F_CPU 1000000L
    #define BAUD 9600
    #define MYUBRR F_CPU/16/BAUD-1
     
    #include <avr/io.h> 
    #include <util/delay.h>
    
    void USART_Init( unsigned int ubrr)
    {
    UBRRL = 0x06; // <-- baud rate == 9600
    /* Zalaczenie wysylania i odbierania */
    UCSRB = (1<<4)|(1<<3);
    }
    
    void send_txt(char text[])
    {
    	for(int i=0; i<=sizeof(text); i++) 
    	{ 
    		UDR = text[i]; 
    		_delay_ms(100); 
    	}
    }
    
    int main(void)
    {
    
    	USART_Init(MYUBRR);
    	OSCCAL=176;
    	
    	while(1)
    	{
    		send_txt("abecadlo z pieca spadlo");
    		
    		_delay_ms(1000);
    	}
    }
    


    I w takim wypadku dostaje tylko od uC tylko 3 pierwsze znaki (abc) i tak w kolko. Sprawa się rozwiazuje jesli funkcja pobiera dwa argumenty: napis i jego dlugosc... Oto dzialajacy kod:

    
    (...)
    
    void send_txt(char text[], int ileznakow)
    {
    	for(int i=0; i<=ileznakow; i++) 
    	{ 
    		UDR = text[i]; 
    		_delay_ms(100); 
    	}
    }
    
    int main(void)
    {
    
    	USART_Init(MYUBRR);
    	OSCCAL=176;
    	
    	while(1)
    	{		
    		int a = sizeof("abecadlo z pieca spadlo");
    
    		send_txt("abecadlo z pieca spadlo", a);
    		
    		_delay_ms(1000);
    	}
    }


    Aczkolwiek jak pisałem wcześniej; takie rozwiazanie mnie nie zadowala, poniewaz przed kazdym wyslaniem txtu, bede musial pisac linijke, ktora zmierzy jego dlugosc, co powoduje powiekszenie rozmiaru kodu.

    Czy macie na to jakies rozwiazanie ?
    Pozdrawiam!
  • REKLAMA
  • #2 6771558
    arrevalk
    Poziom 25  
    Przesyłaj ciąg aż do napotkania znaku o kodzie 0x00 czyli końca ciągu:
    
    void send_txt(char *text)
    {
       while(*text != 0)
       {
          UDR = *text;
          _delay_ms(100);
         text++;
       }
    } 
    

    A wysłanie znaku lepiej sprawdzić poprzez flage UDRE (USART Data Register Empty) z rejestru UCSRA. Jeżeli jest ustawiona to można do rejestru UDR wpisywać następny bajt. A najlepiej całość w przerwaniach zrobić.
  • REKLAMA
  • #3 6771599
    chrupex
    Poziom 11  
    Super... teraz chodzi jak marzenie :) Co do sprawdzania UDRE to mialem go tez w kodzie, ale z nim, czy bez niego, kod chodzil tak samo, wiec nie wklajalem go. Tylko nie rozumiem co masz na myśli pisząc
    Cytat:
    A najlepiej całość w przerwaniach zrobić.

    Byłbyś tak miły rozwinąć tą myśl ? :)

    Sorki, ze moze tak troche offtopic pytanie jeszcze zadam, ale dlaczego funkcja sizeof() w mojej funkcji zwracala mi zawsze wartosc 3, natomiast w funkcji main dzialala normalnie?? Potrafi ktos mi to wytlumaczyc ?
  • REKLAMA
  • #4 6771648
    arrevalk
    Poziom 25  
    chrupex napisał:

    Sorki, ze moze tak troche offtopic pytanie jeszcze zadam, ale dlaczego funkcja sizeof() w mojej funkcji zwracala mi zawsze wartosc 3, natomiast w funkcji main dzialala normalnie?? Potrafi ktos mi to wytlumaczyc ?

    A to akurat bardzo proste jest ;) Do swojej funkcji przekazujesz zmienną char text[] jest to nic innego jak wskaźnik na pierwszy element ciągu znaków. Można to też napisać tak: char *text są to w C zapisy równoważne.
    Teraz wywołując sizeof(text) prosisz ją aby wyznaczyła ci jaki rozmiar ma wskaźnik a nie tablica znajdująca się pod tym adresem, w związku z tym funkcja ta zwraca wartość 2 (a wsyła 3 znaki bo w petli przeglądasz o jeden znak więcej). Krótko mówiąc do mierzenia długości ciągów znaków lepiej jest wykorzystywać fakt że są to tzw null terminated strings czyli ciągi znaków zakańczane zerem. Można też wykorzystać funkcje biblioteczną strlen().
    chrupex napisał:

    A najlepiej całość w przerwaniach zrobić.

    Byłbyś tak miły rozwinąć tą myśl ? Smile

    Jeżeli nie spotkałeś się z takim pojęciem jak przerwanie (interrupt) to poszukaj informacji na ten temat, pełno tego jest na elektrodzie i w każdej książce o programowaniu uC.
  • #5 6771669
    chrupex
    Poziom 11  
    kurde... faktycznie masz racje, ze tez na to nie wpadlem :) Dzienx wielkie za pomoc, a o interruptach sobie chetnie poczytam :)
    Pozdro!
REKLAMA