[AVR-GCC] jak korzystać z printf

Jun 06, 2004 17 Replies

Witam



Wie może ktoś jak zmienić działanie funkcji printf tak aby działała tak jak sobie ktoś zamarzy (chodzi o miejsce gdzie wysyłane są dane) bo ja chce zapisywać je tą funkcją w zewnętrznej pamięci, a nie wysyłać na UART. Na początku wydawało mi się to proste bo już coś takiego robiłem tyle że na kompilatorze rainsonance w którym można nadpisywać funkcje i wystarczyło napisać funkcje putchar w taki oto sposób:



int putchar(const int c) { send2mem(c); // ta funkcja wysyłała by wskazany bajt do pamięci return (0); }



Jednak niestety z tego co widzę w AVC-GCC nie da się nadpisywać funkcji ;( także nie zabardzo wiem jak się do tego zabrać.


chyba kombinujesz jak koń pod górę. Od tego jest sprintf. Dajesz jako pierwszy parametr adres pamięci i już masz co trzeba.

Waldek

Aby stosować printf w avr-gcc, musisz najpierw wywołać funkcję fdevopen, której podajesz m.in. adres funkcji wypisującej jeden znak (poczytaj helpa do avr libc). Stąd już krótka droga do robienia z tym znakiem, co tylko ci się zamarzy, np. wysłania go w kosmos drogą radiową. ;) Albo zapisania w zewnętrznej pamięci.

Ale to chyba nie jest najlepszy pomysł na programowanie np. zewn. Flasha albo karty MMC - printf przekaże do twojej funkcji każdy znak oddzielnie, a najczęściej znacznie lepiej jest zapisywać pamięć od razu całymi blokami.

Dzięki obczaiłem o co chodzi poprostu zrobili to na wskaźniku do funkcji. Inna sprawa to to że jest to nikompatybilme z językiem ANSI C no ale ważne że da się zrobić to co trzeba. Szkoda tylko że w AVR-GCC nie pomyśleli o nadpisywaniu funkcji bo jest to często bardzo przydatne.

Tak masz racje ale to był tylko taki przykład tak naprawdę jest mi to potrzebne to zapisania wewnętrznego EEPROMu w Atmega8 poporstu wymyśliłem sobie że nie będę stosował wyświetlacza w swojej aplikacji, a dane o działaniu programu będę sobie zapisywał w EEPROMie a później sczytywał programatorem aby je przeanalizować i obejrzeć na monitorze komputera. Także wysoka wydajność nie jest mi potrzebna. A w całym układzie nie musze robić wejścia na wyświetlacz którego i tak w przyszłości aplikacja nie potrzebowała by do prawidłowego działania.

Tak masz racie ale trochę nakłamałem ;) bo tak naprawdę chodzi o zapisywanie do wewnętrznego EEPROMU. Pozdrawiam

Mozna spytac o standard jaki wymaga ansi C ?

J.

Trochę nie rozumie twojego pytania, w każdym razie chodzi mi o to, że w ANSI C nie ma w ogóle funkcji fdevopen ;) i lepiej chyba było by zrobić AVR-GCC tak aby było w nim wszystko zrobione tak samo jak w ANSI C (wiadomo nie wszystko się da przenieść na uC),ale zamiast robić jakieś dziwolągi w stylu fdevopen, mogli by rozwiązać ten problem tak jak w innych kompilatorach. Zresztą z tego co przeczytałem to twórcy AVR-GCC mają zamiar to zrobić.

w ANSI-C nie ma też printf. Wogóle funkcje nie są standaryzowane ANSI. Ale w każdym kompilatorze jest printf ;-)

Waldek

dziwne. JanB pisał o tej funkcji w książce ,,Język C. Interpretacja standardu'' już w latach 80-tych. nawet na okładce jest przykład.

formatting link
w.

potem robić protezy, jeśli chciałoby się używać funkcji stdio dla UARTa, wyświetlacza? przyznaję, że nie wiem jak to wygląda w innych kompilatorach, ale możliwość wyboru w avr-libc jest całkiem miłym ficzerem.

w.

IMHO to w standardzie ANSI w ogole nie ma zadnych funkcji zdefiniowanych, ale moze sie myle. No - stringi formatujace do printf to byc moze standard obejmuje :-)

A biblioteke to raczej standaryzuje POSIX.

Tzn jak ? fopen ?

Drobny niuans - nie przypominam sobie zadnej funkcji w typowych C [juz nawet nie wymagam zeby to bylo opisane w standardzie], ktora umozliwialaby wstawienie wlasnej funkcji "drukujacej". Czyli co byc nie wymyslil, to bedzie niekompatybilne :-)

Mozesz natomiast poslugiwac sie sprintf .. ale na maluchach zdecydowanie odradzam - bufor w pamieci za duzo jej zuzywa :-)

Mozna tez przeprosic sie z funkcjami itoa, ftoa, ltoa ..

J.

trochę się krzywo wyraziłem: nie jest w definicji języka, czyli w tzw raporcie, jest jednak w opisie języka jako jedna z funkcji, które język powinien mieć. Pracowałem jednak kiedyś z kompilatorem (na szczęście nie długo), który tej funkcji nie miał (Intel na 8096, chyba)

Waldek

Chodzi mi o nadpisywanie.

No ale wystarczyło by zrobić możliwość nadpisywania funkcji putchar i już po nadpisaniu tej funkcji miałbyś możliwość wysyłania danych gdzie tylko chcesz (tak jest właśnie w innych kompilatorach). Nie jestem pewien czy takie rozwiązanie jest kompatybilne z C (bo na codzień używam C++) i szczerze powiedziawszy nie pamiętam czy w zwykłym C jest coś takiego jak mechanizm nadpisywania, ale w C++ oczywiście jest, a ani w C ani w C++ nie ma funkcji fdevopen czyli z tego wynika że jest to dziwoląg wymyślony przez autorów AVR-GCC a nadpisywanie było by bardziej zgodne.

Narazie się martwie tym że po dadaniu math.h ;) mój program zajmuje już 4k ;-) a jak narazie to właściwie nie robi nic poza odbieraniem sygnałów DTMF i dzwonieniem pod dany nymer. A z printf i tak ostatecznie zrezygnowałem bo ta funkcja nie działa prawidłowo (czyli tak samo jak w języku C) wszystko jest dobrze jeśli wpisuje się do niej stringi ale jak zacznie się podawać parametry np. typu double itp. to zamiast zapisać ten prametr to wiesza cały uC ;-) Także tak jak napisałeś ostatecznie przeprosiłem się z funkcjami itoa, ftoa, ltoa ;-) i zrobiłem sobie własną funkcje która zapisuje to co trzeba w pamięci.

Nadpisywanie IMHO nigdy nie bylo zestandaryzowane w ANSI. I chyba nigdy nie bylo wymogu zeby printf poslugiwal sie wewnetrznie putch.

A napisywanie to kwestia linkera i bibliotek - jesli zdefiniujesz wlasna funkcje putch, to nie bedzie przeszukiwana biblioteka. Ale dla printf zostanie sciagniety caly modul z biblioteki - i kto wie czy nie zawiera takze putch, a wtedy linker zglosi konflikt.

I ja tylko w kwestii tej kompatybilnosci. Ale to ty zaczales "jak w ANSI C", a nie "jak w Keilu" :-)

No wiesz - jak sie chce uzywac printf ... to jest funkcja-kombajn, robi wszystko i duza jest :-)

Samodzielnie wylawiasz DTMF z sygnalu ? To sie zastanow nad programem, ale imho - na zmiennym przecinku bedzie za wolne, na stalym .. nie potrzebne ci zadne bilbioteki.

Nie bardzo rozumiem - chyba za latwo sie poddajesz, jakie C jest takie jest, ale co ma to ma dzialac .. na uC warto sie doczytac - z reguly sa dwie wersje printf - z obsluga zmiennego przecinka i bez. Pierwsza dwa razy dluzsza :-)

J.

No właśnie zgłasza ;). No tak w AVR-GCC nie ma mechanizmu który by się o to zatroszczył. A może jednak jest ale też w formie jakiegoś dziwoląga ;-) ? coś w stylu że trzeba ręcznie wyrzucić z biblioteki oryginalne putchar i wstawić tam swoje ;) tylko nie zabardzo się da bo biblioteki są pokompilowane.

No ja rozumiem dziękuje wszystkim za pomoc i za podanie rozwiązania w postaci fdevopen ;-).

No wiem wiem jeszcze za czasów C dość często jej używałem, teraz jak się bawię C w uC zrezygnowałem z niej bo jednak pamięć się kurczy 8Kb to nie dużo, a funkcjonalność też nie taka jak w C.

Tak wyławiam DTMF z sygnału. Nie wiem czy dobrze rozumie co do mnie piszesz ;) ale mam wrażenie że chcesz mi powiedzieć że obiczenia zmiennoprzecinkowe zajmują dużo więcej czasu niż na liczbach całkowitych. Ja do wyławiania DTMF używam algorytmu goertzla (zresztą podpowiedziano mi go na tej grupie ;). I mniej więcej jestem zadowolony na Atmega8 z 16Mhz uzyskuje próbkowanie tak no oko to jakieś 100ms (przy przeszukiwaniu 7 częstotliwości), najwięcej w tym algorytmie czasu zajmują funkcje sin i cos. Narazie algorytm mi działa ale nie sprawdziłem go jeszcze w praktyce bo mam kłopoty z przetwornikiem AC ;-) coś nie mogę go prawidłowo uruchomić w AVR-GCC. Także nie potrafie powiedzieć czy przy próbkowaniu 100ms będzie mi to prawidłowo wyłapywać sygnały DTMF, jak się okaże że 100ms to za dużo to zacznę jakoś optymalizować ten algorytm np. tak jak sugerujesz wywalę obliczenia zmiennoprzecinkowe i zatąpie je jakoś całkowitymi. Oraz zamiast używać funkcji sin zapisze sobie sinusa w jakiejś tablicy i pewnie wtedy uda się zejść może nawet do 10ms. Tylko narazie musze uruchomić ten przeklęty przetwornik ;-)

No pewnie masz racje i jakoś to printf działa pewnie także z double.Ale pewnie jak jeden parametr jest double a drugi int to już się rozłoży ;-). Dokumentacja do AVR-GCC jest raczej na niskim poziomie i raczej nie chce się za bardzo w niej zagłębiać ;) Jest tam za dużo opisu a za mało przykładów ;( kto by miał czas na czytanie tego wszystkiego, a i tak poza skromnym opisem funkcji to nic tam nie ma.

I o tym wlasnie pisze :-)

- algorytm goertzla nie wymaga zadnych sin i cos. Wymaga kilku stalych wspolczynnikow, ktore obliczyc sobie mozesz na kalkulatorze i wpisac w program. I juz sie rozmiar progamu zmniejsza.

- 100ms .. ale ty masz probkowac co najmniej 3.5kHz [najwiekszy sygnal 1633Hz]. Doradzam wieksza czestotliwosc. Wiec masz gora 200us na obrobke probki. To ci chyba troche czasu zabraknie :-)

- obliczenia proste i zakres w miare znany - mozesz to zrobic na liczbach calkowitych [bedzie troche zabawy, bo 16 bit moze byc za malo] - na oko ten procek ma szanse sie zmiescic, ale byc moze trzeba sie bedzie z assemblerkiem przeprosic.

Trzeba zajrzec do zrodla ... avr/include/stdio.h:

" Since the full implementation of all the mentioned features becomes fairly large, three different flavours of vfprintf() can be selected using linker options. [...]

If the full functionality including the floating point conversions is required, the following options should be used: \code -Wl,-u,vfprintf -lprintf_flt -lm \endcode

"

J.

W artykule <ca98gd$ovi$ snipped-for-privacy@atlantis.news.tpi.pl> autorem którego mieni się BT, napisano:

[...]

To działa, ale powinieneś dostarczyć definicję funkcji fputc (a nie putchar), bo printf właśnie w ten sposób wyprowadza znaki.

Przeglądałem wersję opisu standardu C (draft) - powiedziane jest tam, że printf pisze do stdout, ale nie ma nic na temat sposobu, w jaki to robi (przynajmniej nie rzuciło mi się to w oczy).

potrzebujesz rozdzielczosc ok 70Hz, co wymaga jakis 15ms, no w szczegolnych przypadkach 7. Jesli to ma odrozniac halasy inne, nastepny odstepy sa inne - to sugeruje dluzszy czas - 30, moze nawet

50ms. Przez ten czas musisz zbierac probki - rozmawiamy o ok 120 - 400 probkach [pamiec!].

Ile probek ci obrabia w 100ms ? Bo nie bardzo wierze w ta setke probek. Z sin i cos to raczej jedna probke :-)

Uwazaj, bo ten ulamek musi byc dosc dokladny.

J.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required