NApisy z flash i ostrzeżenia

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
slawek55
Użytkownik
Posty: 475
Rejestracja: 16 sie 2005, 11:47
Lokalizacja: Szczecin

NApisy z flash i ostrzeżenia

Post autor: slawek55 » 07 gru 2006, 7:30

Cześć.
Możecie mi wytłumaczyć taką zezc.
Jest sobie funkcja wyświetlająca na lcd napisy z pamięci Flash.

Kod: Zaznacz cały

void print(prog_char* str) 
{ 
char znak; 
while( 0 != (znak = pgm_read_byte(str++)) ) 
LCDdata(znak); 
}
A wywołanie jej w postaci:

Kod: Zaznacz cały

print(PSTR("napis"))
Generuje ostrzeżenie:

warning: passing arg 1 of `print' discards qualifiers from pointer target type

Tylko dlaczego skoro makro PSTR zwraca wskażnik do obszaru Flash, który jest akceptowalny przez funkcję. Dlaczego rzutownie, skoro funkcja print przyjmuje wskaźnik prog_char *

Zmiana w funkcji void print(char* ptr){ ... (usunięto prog_ ) nic nie wprowadza daje ten sam efekt ostrzeżenia. Pomaga dopiero rzutowanie.


P.S.
Sprawdziłem też taką sytuację

Kod: Zaznacz cały

prog_char g_napispgm[] = "Lancuch ";
i wywołanie

Kod: Zaznacz cały

print(g_napispgm);

I niezależnie czy funkcja jest zadeklarowania jako void print(char *ptr) czy jako void print(prog_char *ptr) to też jest ten sam komunikat

Awatar użytkownika
Koppel
Użytkownik
Posty: 500
Rejestracja: 24 lip 2005, 18:05
Lokalizacja: Gliwice

Post autor: Koppel » 07 gru 2006, 16:02

PSTR nie zwraca wskaźnika prog_char*. Zwraca wskaźnik: const prog_char*. Jeśli funkcja będzie miała taki typ argumentu ostrzeżenie nie pojawia się.

Mogłem wspomnieć o tym w kursie... ale chyba sprawa mi umknęła. Ogólnie zwykle we własnych programch stosuję rozwiązanie z rzutowaniem, chociaż faktycznie nie jest to idealne rozwiązanie.

slawek55
Użytkownik
Posty: 475
Rejestracja: 16 sie 2005, 11:47
Lokalizacja: Szczecin

Post autor: slawek55 » 07 gru 2006, 16:55

Czyli można zadeklarować funkcję jako

Kod: Zaznacz cały

void print( const prog_char*)
A czy to dotyczy również napisów z flash

Kod: Zaznacz cały

prog_char g_napispgm[] = "Lancuch ";
bo tu już nie ma const?

Awatar użytkownika
Koppel
Użytkownik
Posty: 500
Rejestracja: 24 lip 2005, 18:05
Lokalizacja: Gliwice

Post autor: Koppel » 07 gru 2006, 17:09

Można, ale nie jest to konieczne. Można do funkcji która ma parametr typu const przypisać wskaźnik na parametr bez tego kwalifikatora. Chodzi o to, że const znaczy, że wartość zmiennej ukrytej pod wskaźnikiem nie będzie zmieniana. Można więc dla funkcji która mówi, że nie zmienia zawartości podać wskaźnik do zmiennej w której zmiana wartości jest możliwa. Inaczej jest w drugą stronę - jeśli zmienna została określona jako taka której wartości nie wolno zmieniać nie możemy wysyłać jej do funkcji która nie ma jawnie zaznaczonego faktu, że nie rusza zawartości zmiennej wskazywanej przez wskaźnik.

Trochę to chyba zamotanie brzmi ale jak się chwilę przemyśli to powinno być logiczne.

slawek55
Użytkownik
Posty: 475
Rejestracja: 16 sie 2005, 11:47
Lokalizacja: Szczecin

Post autor: slawek55 » 08 gru 2006, 6:08

Cześć.
Porobiłem parę ćwiczeń i, jeśli mam łancóch w pamięci Flesh zadeklarowany jako

Kod: Zaznacz cały

prog_char g_napispgm[] = "Lancuch z FLASHa";
A funkcja ma definicję typu

Kod: Zaznacz cały

void lcd(prog_char *ptr) { ..
to pojawia się ten komunikat warning: passing arg 1 of `lcd' discards qualifiers from pointer target type
Natomiast jak w funkcji zmienię na

Kod: Zaznacz cały

void lcd(const prog_char *ptr) { ...
To już nic się nie pojawia. :shock:

Przy okazji zapytam o jeszczejedno (zainteresowało mnie to). W częci 10 opisana była tablica wskażników.

Poszczególne napisy były tworzone poprzez:

Kod: Zaznacz cały

prog_char napis1[] = "Napis w pamięci programu 1";
prog_char napis2[] = "Napis w pamięci programu 2";
Natomiast tablica tych wskaźników :

Kod: Zaznacz cały

const prog_char* strTab5[] PROGMEM = 
{
	napis1,
	napis2
};
Dlaczego const i dlaczego pojawiło się PROGMEM ?

W części 3 było opisane o tworzeniu "stałych łańcuchów" w pamięci Flash i opisane były dwie metody umieszczenia tzn.
1. prog_char napis[]="napis1";
2. char napis2[] PROGMEM = "napis2";

CZyli jakby PROGMEM był równoważny typowi prog_char, a tu występuje zarówno prog_char jak i PROGMEM. Dlaczego? A dodatkowo jeszcze const

Awatar użytkownika
Koppel
Użytkownik
Posty: 500
Rejestracja: 24 lip 2005, 18:05
Lokalizacja: Gliwice

Post autor: Koppel » 08 gru 2006, 18:31

slawek55 pisze:Dlaczego const i dlaczego pojawiło się PROGMEM
Więc po koleji.
const ogólnie dobrze umieścić wszędzie tam gdzie mamy do czynienia z danymi co do których wiemy, że nie będziemy ich zmieniać. Gdyby brakło tego const'a, mógłyby pojawić się ostrzeżenia identyczne jak w pierwszej wypowiedzi w temacie. Moglibyśmy się ratować przez rzutowanie, jednak stwierdziłem już wyżej, że to jednak nie jest zbyt eleganckie rozwiązanie.

Samo istnienie PROGMEM powinna wyjaśnić ramka na stronie 39. Chociaż rzeczywiście chyba nie rozwiewa wszyskich wątpliwości. Sprawa wygląda tak, że bez słowa PROGMEM zostanie utworzona tablica wskaźników na napisy znajdujące się w pamięci programu (tablice zmiennych typu prog_char). Jednak sama tablica zostanie utworzona w pamięci RAM!. Pojawiające się tutaj słowo PROGMEM odnosi się do tablicy wskaźników a nie do samych napisów. Przypominam, że prog_char - to znak 8 bitowy umieszczony w pamięci programu. Jednak już prog_char* to wskaźnik do niego. I wskaźnik taki wcale nie ma "wbudowanego" modyfikatora mówiącego, że znajduje się on w pamięci programu.

Uff... mam nadzieję, że wyjaśniłem wątpliwości.

PS. Pracuję powoli nad utworzeniem FAQ w połączeniu z rodzajem erraty. Tak więc wszelkie pytania takie jak to bardzo pomagają mi w znalezieniu miejsc problemowych a czasem nawet drobnych błędów rodzaju takiego jak z przedstawionym rzutownaniem.

slawek55
Użytkownik
Posty: 475
Rejestracja: 16 sie 2005, 11:47
Lokalizacja: Szczecin

Post autor: slawek55 » 09 gru 2006, 17:12

Cześc.
jeśli mogę coś zasugerować do tego FAQ to, czy możliwe jest poruszenie jeszcze takich tematów jak:
1. Wybór optymalizacji przy kompilacji. Zauważyłem sam, że czasami różne rzeczy wychodzą.
2. Przerwania, które są przerywane przez inne o większym piorytecie. Nastąpiły tam pewne zmiany (tyle co ja wiem) i trochę się to różni od poprzedniej wersji.
3. Obsługa ziennych np 32 bitowych (powyżej 8 bitów) i rozkładanie na pojedyncze bajty. Chodzi mi o Big Endian (bo chyba taki jest stosowany w AVR-GCC). W każdym razie jeśli jest zmienna o większej liczbie bitów i potrzeba rozłożyć ją na składowe to jak po piewsze jest to w pamięci lokowane i to zarówno we flash jak i RAM a po drógie jak się dostać do składowych.


To są moję takie propozycje, które nasunęły mi się teraz.

ODPOWIEDZ