Wpis z mikrobloga

No witam AVRowe świry! Jestem mirkiem, ale nie Kardasiem #pdk i przechodzę od razu do konkretów:

Gdyby do momentu publikacji ktoś mi zarzucił że nic nie zrobiłem dla Polaków(jakby głosowanie w każdych wyborach na JKM nie wystarczyło), to wstawiam tu ten wydaje mi się wartościowy wpis z prawdziwym OPUS MAGNUM w kucowaniu na platformę #avr i nie tylko - biblioteką xprintf.

Jak mawiał klasyk i mój mentor Klocuch12:

Mało ludzi wie, a dużo ludzi nie wie


I jak wykazała sonda uliczna - tak wygląda świadomość polskiego społeczeństwa na temat biblioteki xprintf:
https://www.youtube.com/watch?v=OO3FANjwKHY

No więc - xprintf to odpowiednik funkcji printf na dużych systemach dla mirkokontrolerów, jej autorem jest Pan posługujący się nickiem ChaN - bardzo utalentowany Japończyk, fan minimalizmu, ponadto twórca innej znanej biblioteki FatFS oraz Petit FatFS. Omawiana w tym wpisie wersja xprintf jest napisana w assemblerze, co oznacza że zajmuje minimum miejsca, i jest bardzo wydajna.
Co prawda jego strona http://elm-chan.org/ nie wygląda szałowo, ale content bardzo dobry, nawet chińskie bajki można mu wybaczyć.

Przeciętny nieświadomy kuc zapyta: NA CO MI TO?

Jak znam życie, to ten właśnie kuc pisząc swoje programy gdy będzie potrzebował wypisać przez UART choćby ilość załączeń swojego e-papierosa z grzałką sterowaną Arduino #pdk to będzie robił coś takiego:

char buf[16];
uart_print_str("eFajka start count: ");
itoa(cig_on, buf,10));
uart_print_str(buf);
uart_print_str("\n");

A tacy arduinowcy to myślicie lepsi? Gdzie tam, zrobią tak:

Serial.print("eFajka start count: ");
Serial.print(cig_on, DEC);
Serial.print("\n");

Posłuchajmy co na ten temat sądzi Pan Mariusz Pudzianowski - znany programista AVR:
https://www.youtube.com/watch?v=GisG7HRk-3k

Wiecie dlaczego pisanie jak wyżej jest #!$%@?? Z dwóch względów:
- do wypisania jednej liczby potrzebujecie 3, może 6 linijek kodu
- bajty z tego tekstu("eFajka start count:") lądują w cennej pamięci RAM
Jak wiadomo w niepisanych zasadach piwnicy jest taka jedna:
https://www.wykop.pl/cdn/c3201142/comment_rKQ6nslA6spAbP6l2a9Nu1BFP8ihzHX3.jpg

OSZCZĘDZAJ RAM GDZIEKOLWIEK JESTEŚ!

Na ten problem są 3 rozwiązania:
- w czystym C: dołożyć funkcję do wypisywania tekstów z pamięci programu i teksty obkładać makrem PSTR()
- w Arduino: dołożyć F() wokół tekstu: Serial.print(F(“Hello World”))
- użyć biblioteki xprintf jak człowiek z RiGCZem

Aby wypisać to co wyżej - na scenę wchodzi xprintf - cała na biało i myk:

xprintf(PSTR("eFajka start count: %d"), cig_on);
I tyle. Spoko nie?

Jak to tera uruchomić w moim projekcie?

Otóż wszystko czego potrzebuje ta biblioteka to funkcja putc wysyłająca znak przez dane medium - tak, dobrze czytacie, tu nie jesteśmy ograniczeni do UARTu, jak chcemy pisać po wyświetlaczu, to trzeba funkcji do wysłania znaku na wyświetlacz, jak chcemy drukować po betonie piaskiem to trzeba funkcji która wysypie jeden znak, xprintf zajmie się resztą.
No więc jak już mamy naszą funkcję do wysyłania znaku(może być z gotowej biblioteki):

void uartputc(unsigned char data)

załączamy nagłówek

#include "xprintf_asm/xprintf_asm.h"
inicjalizujemy normalnie nasz UART

uart_init(UART_BAUD_SELECT_DOUBLE_SPEED(19200,F_CPU));
I teraz najważniejsze - podajemy naszą funkcję do pisania bibliotece xprintf:

xdev_out(uart_putc);
Od tej pory możemy sobie wypisywać teksty tak jak na dużych systemach używając printf:

xputs(PSTR("NO WITAM WITAM\n"));
Pisać liczby dziesiętne:
'xprintf(PSTR("x=%d\n"),x);'

Opisywać punkty w 3D:
'xprintf(PSTR("x=%d y=%d z=%d\n"),x,y,z);'

Wypisywać w formacie szesnastkowym, lub binarnym:
xprintf(PSTR("x[hex]=%X x[bin]=%b\n"),x);

Wstawiać napisy warunkowo
xprintf(PSTR("x > 10? %s\n"), (x>10)?"YES":"NO");

Jest też jedna ważna zaleta tej biblioteki i w tym miejscu dobra rada, szczególnie dla arduinowców:

Jak chcesz wypisać liczbę z przecinkiem to NIE UŻYWAJ #!$%@? FLOATÓW i DOUBLE jeśli nie musisz


AVRy nie mają wbudowanego FPU i każda operacja na liczbach zmiennoprzecinkowych powoduje dołożenie do programu wieluset bajtów kodu wymaganego do liczenia, nie mówiąc o tym o ile to jest wolniejsze

Chcąc wypisać napięcie powiedzmy 4.060 w programie posługuj się milivoltami:

uint16_t milivolts = 4060;
I co teras?
A no wyciągniemy sobie cześć całkowitą i po przecinku:

xprintf(PSTR("milivolts %d.%d\n\n"), milivolts/1000, milivolts%1000);
Wypisało nam się takie cuś:

milivolts 4.60

4060/1000=4V 4060%1000=60mV A no tak! policzyło dobrze, tylko w wypisywaniu brakuje zera na początku.

Papież Polak - Jan Paweł 2 zapytany czy biblioteką xprintf można dodać zera widące i ustawić ilość znaków na której liczba ma zostać wyświetlona odpowiedział:
https://www.youtube.com/watch?v=Scn4Gzqy0n4

Tak więc elegancko dodajemy %03d oznaczające: liczba będzie wyświetlana na 3 miejscach, jeśli nie ma 3 cyfr, to dopełnij z przodu zerami:

xprintf(PSTR("milivolts %d.%03d\n\n"), milivolts/1000, milivolts%1000);
I to by było tyle na dziś

Zapraszam na github po kod
https://github.com/QB4-dev/AVR-misc/tree/master/avr-xprintf-asm

Powyższe funkcje mają też przenośną implementację w C i można je wykorzystać na praktycznie każdej platformie na której brak domyślnego printf.
Kiedyś napiszę jak to spiąć z wyświetlaczem.

#mikrokontrolery #arduino #avr #stm32 #esp8266 #esp32 #qualitycontent #github #programowanie #qbadev
Pobierz QBA_ - No witam AVRowe świry! Jestem mirkiem, ale nie Kardasiem #pdk i przechodzę od ...
źródło: comment_3jPOvIe8ch1mfzKV9Xwp6eSb8Vaw3Vwc.jpg
  • 17
@QBA__:

uint8t a = 10;
uint8t tab[10];
uint8t str[10];

itoa(a, (char*)(tab), 10);
sprintf(str, "%s.4.4 \n", (char*)(tab) );

Text.Write(str);

Akurat jak ktoś pisze na AVR to tam sprintf działa znakomicie. No chyba, że brakuje mu miejsca i chce się bawić. Za to sprintf jest potężną funkcją i ma mnóstwo opcji które na avr działają.
Ofc zjadło * przy rzutowaniu. Kompilator trochę się o to martwi.
No i jeszcze są funkcje dtostrf, dtostre
@QBA__ dzięki za polecenie :) Swoją drogą super wpis o tym xprintf. Kiedyś mi gdzieś mignął jak bawiłem się FatFSem. Spróbuję go użyć na STM32 i pewnie pojawi się u mnie na blogu ;)
@QBA__: co to za problem sobie samemu zaimplementować printfa. Dociąganie jakiejś zewnętrznej biblioteki do tego to mi się kojarzy z zaciąganiem left-pada z NPM przez dżawaskript dżunior frontend bootcamp nindżów xD
via Wykop Mobilny (Android)
  • 0
@zwei: rozumiem że jesteś taki pro że pod każdy projekt piszesz własną implementację libc? A w javascript piszesz własne frameworki, nie używaasz żadnych jquery czy reactów na kiju?
@QBA__: własny printf na port szeregowy czy na cokolwiek to jest 10, max 20 linijek kodu. Oczywiście, że nie piszę frameworków, tylko co ma piernik do wiatraka.
via Wykop Mobilny (Android)
  • 1
@zwei: to poka nam tu mirkom zgromadzonym ten Twój printf na 20 linijek co wypisuje znaki, liczby, stringi w zadanym formacie, w tym z wiodącymi zerami, binarnie, ponadto czyta fmt string z pamięci programu i na dodatek jest optymalniejszy niż xprintf od ChaNa.
Czekamy z niecierpliwością na link do githuba( ͡°( ͡° ͜ʖ( ͡° ͜ʖ ͡°)ʖ ͡°) ͡°
@QBA__:

#include
#include

void printf_(const char *fmt, ...)
{
  char buf[0x40];
  va_list args;
  va_start(args, fmt);
  vsprintf(buf, fmt, args);
  va_end(args);

  wypchnij_bufor_na_co_tam_sobie_wymarzysz(buf);
}

ponadto czyta fmt string z pamięci programu


zmieniasz se sygnaturkę na

void printf_(const PROGMEM char *fmt, ...)
optymalniejszy niż xprintf od ChaNa

Jak brakuje ci RAM-u, to zmieniasz mikrokontroler, kolego xD
via Wykop Mobilny (Android)
  • 2
@zwei: daję plusa, ale... Nie będzie to optymalniejsze niż w asm, i co jeśli mój tekst ma być dłuższy niż 64 znaki? (czepiam się xD).
Podobnie da się zrobić robiąc sobie własny strumień i przypisując do stdout a potem używać zwykłego printf