Gieneq Wrzesień 16, 2021 Udostępnij Wrzesień 16, 2021 @ethanak faktycznie ciekawe, czyli kod z kursu w C++ by nie przeszedł. Coś rodzaju tego: void mehh(uint8_t *aw, int cnt){ uint8_t k = 0; while(cnt--) k = *aw++; } void meh(void * aa, int cnt){ mehh(aa, cnt); } W C się skompiluje, bez ostrzeżenia. W C++ wyrzucił błąd: argument typu "void *" jest niezgodny z parametrem typu "uint8_t *" Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Wrzesień 16, 2021 Udostępnij Wrzesień 16, 2021 Bo C++ wymaga bezwzględnej zgodności typów - co przy portowaniu kodu z C na C++ może doprowadzić do traumy. Ostatnio przy portowaniu swojego kodu stwierdziłem, że "const " to powinienem mieć pod jakimś łatwym skrótem klawiszowym, a głupi strtol który miał przesunąć wskaźnik na buforze const char * wymagał jawnego rzutowania na char ** z const char ** (przynajmniej ja nie znalazłem lepszego rozwiązania). No ale nic dziwnego - to jednak dwa różne języki. 1 Cytuj Link do komentarza Share on other sites More sharing options...
Popularny post Elvis Wrzesień 16, 2021 Popularny post Udostępnij Wrzesień 16, 2021 Długa dyskusja się wywiązała, więc pozwólcie że napiszę kilka słów. Po pierwsze warto zrozumieć czym różni się wartość od wskaźnika - wartość to np. Bajt (uint8_t), int, albo cała struktura. Typ zmiennej określa ile pamięci jest potrzebne do jej przechowywania oraz jak wykonywać operacje na niej. Różne typy mogą zajmować różną ilość pamięci, więc np. Przypisując wartoś zmiennej 32-bitowej do zmiennej 8-bitowej możemy część danych stracić, bo po prostu się nie zmieszczą. Natomiast wskaźnik jest tylko adresem w pamięci, w stm32l4 to zawsze 32-bitowa liczba, a więc każdy typ wskaźnikowy w pamięci wygląda tak samo. Przypisanie wskaźnika do int na wskaźnik do skomplikowanej struktury nie spowoduje żadnej utraty danych, typy mają nas tylko ustrzec przed używaniem wskaźnika do niepoprawnych danych. To oznacza, że void* jest wskaźnikiem na dowolny typ, po prostu przechowuje jakiś adres w przestrzeni adresowej procesora (nie musi to nawet być RAM). Kompilator bez problemu pozwoli na przypisanie wskaźnika dowolnego typu na void*, bo taka operacja oznacza tylko utratę informacji o typie, nic złego się nie dzieje. Problemem jest natomiast przypisanie void* z powrotem. Takie przypisanie może oznaczać błąd w programie, jeśli przez pomyłkę użyjemy wskaźnika z innym typem. I tutaj dochodzimy do filozofii, albo raczej decyzji projektowych. Język C na początku wcale nie posiadał kontroli typów, przyjęcie więc że programista wie co robi było więc jak najbardziej sensowne. Nawet po wprowadzeniu kontroli typów, pozostała możliwość przypisywania void* do dowolnego wskaźnika. Natomiast C++ od początku większą wagę przywiązywał do statycznej typizacji, więc konieczne jest użycie jawnego rzutowania. Czyli w C można napisać: int x = 5; int *px = &x; void *pv = &x; px = pv; W C++ ostatnia linijka spowoduje błąd i konieczne będzie jawne rzutowanie, czyli nielubiane: px = (int*m)pv; Albo zalecane chociaż dyskusyjnie piękne: px = static_cast<int*>(pv); Przykładowe kody były pisane w C, więc jawne rzutowanie nie było konieczne, ważniejsze jest jednak wyjaśnienie, dlaczego używamy void* zamiast uint8_t*. Użytkownik biblioteki powinien mieć możliwość wysyłania i odbierania dowolnych danych, dlatego void* oraz const void* są tutaj o wiele lepszym wyborem. Taki typ jest również używany w standardzie Posix do odczytu i zapisu (read/write). Wywoływana funkcja działa na bajtach, więc wykona sobie jawną lub niejawną konwersję na uint8_t, ale nie powinno to obchodzić użytkownika. Natomiast dlaczego HAL używa uint8_t* jako parametrów wiedzą pewnie tylko autorzy tej biblioteki. Moja prywatna teoria jest taka, że firmy produkujące świetny hardware, niekoniecznie są ekspertami w tworzeniu oprogramowania (i odwrotnie). Nie można mieć wszystkiego. Ale nie jest to mankament, który uniemożliwiałby korzystanie z zalet dostępnych bibliotek, po prostu taki folklor. PS. Z góry przepraszam za błędy, post był pisany z telefonu, co nie jest aż takie wygodne jak się wydaje. 2 1 Cytuj Link do komentarza Share on other sites More sharing options...
Gieneq Wrzesień 16, 2021 Udostępnij Wrzesień 16, 2021 2 godziny temu, Elvis napisał: Natomiast dlaczego HAL używa uint8_t* jako parametrów wiedzą pewnie tylko autorzy tej biblioteki. Moja prywatna teoria jest taka, że firmy produkujące świetny hardware, niekoniecznie są ekspertami w tworzeniu oprogramowania (i odwrotnie). Pięknie 😅 @Elvis dzięki za obszerne wyjaśnienie 🏅 Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Produkcja i montaż PCB - wybierz sprawdzone PCBWay! • Darmowe płytki dla studentów i projektów non-profit • Tylko 5$ za 10 prototypów PCB w 24 godziny • Usługa projektowania PCB na zlecenie • Montaż PCB od 30$ + bezpłatna dostawa i szablony • Darmowe narzędzie do podglądu plików Gerber Zobacz również » Film z fabryki PCBWay
Hub Listopad 5, 2023 Udostępnij Listopad 5, 2023 Pomimo iż ustawiłem wszystko tak jak w kursie oraz dodałem kod z kursu(powyższy) to dalej mikrokontroler nie łączy się z eprom(w debbugerze test i result obie mają wartość 0 '\0') uint8_t test = 0x5A; HAL_I2C_Mem_Write(&hi2c1, 0xA0, 0x10, 1, &test, sizeof(test), HAL_MAX_DELAY); HAL_Delay(5); uint8_t result = 0; HAL_I2C_Mem_Read(&hi2c1, 0xA0, 0x10, 1, &result, sizeof(result), HAL_MAX_DELAY); Cytuj Link do komentarza Share on other sites More sharing options...
Treker (Damian Szymański) Listopad 6, 2023 Udostępnij Listopad 6, 2023 @Hub witam na forum 🙂 Zacznijmy od początku, czy sprawdziłeś podwójnie poprawność połączeń? Czy na 100% są rezystory podciągające przy I2C? Warto również sprawdzić inne miejsce na płytce stykowej, bo czasami układy scalone nie łączą na nich zbyt dobrze. Do tej pory nikt nie zgłaszał takich problemów, więc na początek doszukiwałbym się problemów w połączeniach sprzętowych. Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
Dołącz do dyskusji, napisz odpowiedź!
Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!