Skocz do zawartości

[C/ATmega328p] Volitale memcopy i problemy


Torkness

Pomocna odpowiedź

Cześć,
Podczas odczytywania string'a przez uart (wykorzystuje przerwania) mam spory problem z przepisaniem danych do zmiennej typu char[]. Tablica źródłowa i tablica docelowa są typu volitale. Przeszukałem kilka podobnych problemów na forum jednak nie znalazłem rozwiązania. Wolałbym nie rezygnować z oznaczenia volatile, ponieważ są to zmienne obsługiwane w przerwaniu UART. Otrzymuje 3 ostrzeżenia i 3 informacje:

Warning   1   passing argument 1 of 'memcpy' discards 'volatile' qualifier from pointer target type [enabled by default]   70   3   
Message   2   expected 'void *' but argument is of type 'volatile unsigned char *'      117   14   
Warning   3   passing argument 2 of 'memcpy' discards 'volatile' qualifier from pointer target type [enabled by default]   70   3   
Message   4   expected 'const void *' but argument is of type 'volatile unsigned char *'   117   14   
Warning   5   passing argument 1 of 'memset' makes pointer from integer without a cast [enabled by default]   71   3   
Message   6   expected 'void *' but argument is of type 'unsigned char'   121   14   

(Wiersze których tyczą się ostrzeżenia/wiadomości nie pasują bo wyczyściłem z kodu poniżej nieużywane funkcje/obsługę ledów etc.)

Kod:

#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <util/delay.h>
#include <string.h>

#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1

volatile unsigned char data_in[44]; //ilość znaków jakie chcę maksymalnie przechowywać w tablicy
volatile unsigned char command_in[44];
volatile unsigned char data_count;
volatile unsigned char command_ready;

void USART_INIT(unsigned int ubrr)
{
       UBRR0H = (unsigned char)(ubrr>>8);
       UBRR0L = (unsigned char)(ubrr);

       UCSR0B = (1<<RXEN0)|(1<<RXCIE0);
       UCSR0C = (3<<UCSZ00);
}

void COPY_COMMAND()
{
       ATOMIC_BLOCK(ATOMIC_FORCEON)
       {
               memcpy(command_in,data_in,44);
               memset(data_in[0],0,44);
       }
}

ISR (USART_RX_vect)
{
       data_in[data_count]=UDR0;
       if(data_in[data_count]=='\n')
       {
               command_ready=1;
               data_count=0;
       }else
       {
               data_count++;
       }
}

int main(void)
{
       USART_INIT(MYUBRR);
       DDRD = 0x00;
       sei();

       while(1)
       {      
               if(command_ready==1)
               {      
                       //w tym miejscu chce umiescic funckje rozpoznajaca rozkaz              
                       command_ready=0;
               }
       }      
}
GeSHi

Może ktoś ma pomysł co jest tu nie tak i mógłby mi wytłumaczyć? Ja szukam i szukam i nic nie znajduję 🙁

Pozdrawiam

Link do komentarza
Share on other sites

Ostrzeżenia które dostałeś są dwojakiego rodzaju:

"passing argument 1 of 'memcpy' discards 'volatile' qualifier from pointer target type"

Te mówią o tym, że podczas analizy programu nastąpiła niezgodność typów argumentów formalnych z aktualnymi, dołączonymi do jej wywołania w Twoim kodzie. Funkcja memcpy oczekuje void * a dostała volatile unsigned char *. Jeżeli wiesz co robisz, możesz po prostu przerzutować odpowiednie wskaźniki na typ oczekiwany przez funkcję:

memcpy((void *)command_in, (void *)data_in, 44);

co powinno zadziałać bez narzekania kompilatora. Trzeba zauważyć, że nawet i bez tego zostanie wygenerowany poprawny kod

Drugi typ ostrzeżenia jest dużo groźniejszy:

"passing argument 1 of 'memset' makes pointer from integer without a cast"

bo mówi o tym, że gdzieś użyłeś zwykłej liczby int w miejscu wskaźnika i nie wstawiłeś jawnego rzutowania. Na takie coś warto zwrócić uwagę, bo jeśli nie zrobiłeś tego celowo (i nie spodziewałeś się takiego komunikatu), to może to być poważnym problemem podczas działania programu i powodować makabryczne zniszczenia w pamięci danych. Rzeczywiście, w wywołaniu funkcji:

memset(data_in[0], 0, 44);

korzystasz z wartości komórki [0] tej tablicy a przecież pierwszym argumentem musi być wskaźnik na początek wypełnianego obszaru, czyli albo

memset(&data_in[0], 0, 44);

albo po prostu

memset(data_in, 0, 44);

plus poprzednie uwagi dot. rzutowania na typ wskaźnika wymagany przez funkcję memset().

Złym pomysłem są też nic nie mówiące liczby 44 umieszczone w przypadkowychmiejscach w kodzie. Skoro znasz i używasz instrukcji preprocesora, to jeszcze jeden #define nie zaszkodzi:

#define DLUGOSC_BUFORA 44

Po co zerujesz bufor odbiornika po przepisaniu jego zawartości do command_in? Przecież nowe znaki napływające z UARTa mogą zastępować stare bez potrzeby "przygotowania" dla nich miejsca. Unikaj umieszczania długo wykonujących się funkcji (jak memcpy czy memset) w sekcjach krytycznych.

Zawsze mnie rozczulają takie wyznania:

"Ja szukam i szukam i nic nie znajduję".

A dobry podręcznik do języka C miałeś kiedyś w ręku? To zwykła książka. Wystarczy odejść od komputera, usiąść w fotelu i po dwóch dniach czytania i zastanawiania się zaczynasz rozumieć o co chodzi 🙂 Warto, zostaje do końca życia.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.