Dzisiejszy świat pulsuje możliwościami, jakie mają do zaoferowania duże modele AI, takie jak ChatGPT. Potencjał sztucznej inteligencji do zrewolucjonizowania sposobu, w jaki ludzie pracują i bawią się, jest zdumiewający, a dla niektórych również nieco przerażający. Aby pokazać pewną perspektywę względem tego zjawiska, wystarczy spojrzeć na akcje firmy NVIDIA — ich kurs w bieżącym roku (dane na czerwiec 2023 r.) zwiększyły swoją wartość trzykrotnie w związku z napływem inwestorów oczekujących niemal nieograniczonego popytu na sprzęt AI. W obliczu nowej: „gorączki złota” programiści systemów wbudowanych mogą zastanawiać się, w jaki sposób wykorzystać sztuczną inteligencję w swojej pracy.
Jeśli chcemy spożytkować AI do szybszego pisania lepszego kodu, trzeba wiedzieć, jak się do tego zabrać. W źródłowym artykule autorzy przyjrzeli się, jak wykorzystać ChatGPT do przyspieszenia pracy. W tym poście omówimy siedem tych samych porad dotyczących pisania oprogramowania wbudowanego, jako przykłady do zastosowania ElektrodaBota. Pokażemy, jak posiłkować się nim, aby zwiększyć naszą wydajność, przy jednoczesnej redukcji podatności na błędy i zmniejszenia ryzyka wystąpienia tych wygenerowanych przez sztuczną inteligencję.
Porada nr 1 — użyj AI do debugowania napisanego kodu
Debugowanie jest jedną z najmniej ulubionych czynności związanych z tworzeniem oprogramowania wbudowanego niemalże każdego programisty. Chociaż niektórzy uwielbiają wyzwania skorelowane z ustaleniem, dlaczego system zawiera błędy, to jednak w większości przypadków prawdziwe jest stwierdzenie Jacka Gansslesa: „Jeśli jest faza debugowania, to musiał być etap błędów”. Programiści systemów wbudowanych nie powinni być świetnymi debugerami; przede wszystkim muszą zapobiegać powstawaniu niedociągnięć w kodzie. Współczesne systemy wbudowane są złożone i pomimo stosowania najnowocześniejszych dostępnych technik i procesów, będą pojawiać się nieprawidłowości i nieoczekiwane zachowania, nad którymi będzie trzeba popracować.
Autor artykułu opisuje swój problem — niedawno integrował rejestrator do śledzenia wykonywania kodu z systemem zbudowanym na zamówienie klienta. Postępował zgodnie z instrukcjami podłączenia, ale odkrył, że pojawiały się błędy kompilacji z powodu wielu definicji. Urządzenie polegało na jakimś: „voodoo linkera”, aby biblioteka śledzenia zastąpiła bibliotekę RTOS wersjami opakowanymi w rejestrator. Voodoo jednak nie działało! Spoglądając szybko na plik make, wszystko wyglądało dobrze. To oznaczało dzień debugowania... Patrząc na wyniki pracy kompilatora, zauważył on, że niektóre rozszerzenia makr nie operowały poprawnie. Zamiast zajmować się normalnym procesem debugowania, zdecydował się skorzystać z AI. Sprawdźmy, jak ElektrodaBot poradzi sobie z takim zadaniem.
Jak widać, ElektrodaBot odpowiedział bardzo szeroko, o wiele obszerniej niż ChatGPT w oryginalnym artykule. Trafił także w sedno problemu, który autor źródłowego materiału miał ze swoim makefilem. Kłopot związany był z automatyczną zmienną. Dodatkowo, przepis budowania kodu wymagał niewielkiej korekty. Po przetestowaniu sugerowanych zmian okazało się, że rozwinięcie makra działa teraz poprawnie! Gdyby nie AI, debugowanie mogłoby zająć kilka godzin. Zamiast tego wystarczy parę minut, aby ElektrodaBot wskazał nam potencjalne obszary, gdzie występować mogą nieprawidłowości. To ogromne przyspieszenie procesu, zwiększenie wydajności programisty i, jednocześnie, dzięki obszernym odpowiedziom Bota, doskonalenie umiejętności.
Porada nr 2 — bądź konkretny i jasno określ swoje intencje
Autor, aby uzyskać odpowiedź, musiał dwukrotnie zapytać ChatGPT o rozwiązanie pewnych kwestii. Wynika to z faktu, że pierwsze pytanie było niedostatecznie konkretne. Oczywiście, jasno określił swoją intencję rozwiązania problemu, ale początkowo autor nie dostarczył pliku makefile. Dopiero gdy zapewnił modelowi wystarczająco dużo informacji i był precyzyjny oraz klarowny względem własnych zamiarów, otrzymał wynik, który pozwolił usunąć nieprawidłowość.
Pracując z modelami AI nad tworzeniem oprogramowania wbudowanego, ważne jest, aby być konkretnym i jasnym w swoich intencjach. W niektórych przypadkach może to być trudne. Jeśli piszemy tajny kod swojej firmy, nie można go po prostu wrzucić na forum, by zapytać ElektrodaBota... Niemniej istnieje szereg ogólnych problemów z oprogramowaniem, które można rozwiązać, pisząc kod przy użyciu AI.
Im więcej informacji dostarczymy modelowi, tym lepsze będą rezultaty. Na przykład, jeśli zapytamy Bota: „Muszę podłączyć się do czujnika”, to nie jest to zbyt konkretne, a model nie będzie wiedział, czego potrzebujemy. Autor dla zabawy wprowadził takie pytanie do ChatGPT. My sprawdziliśmy w tym zakresie ElektrodaBota:
Identycznej odpowiedzi udzielił też chatbot autorowi artykułu... Porównajmy teraz, co stanie się, gdy zadamy mu o wiele konkretniejsze pytanie:
ElektrodaBot dostarczył nam kompletny kod! Podobnie jest w stanie robić ChatGPT. W przykładzie w artykule źródłowym AI dodatkowo objaśniło, po co zastosowano poszczególne elementy w kodzie, czego nie zrobił ElektrodaBot. Jednakże to na nic, ponieważ kod był niepoprawny, mimo wyrażenia prośby, by komunikować się z termometrem za pomocą I²C. Znowu punkt dla ElektrodaBota. Brak szerszego opisu nie jest wszakże problemem, ElektrodaBot dodał w kodzie całkiem sporo komentarzy, a jeśli i to jest dla nas za mało, możemy dodatkowo dopytać, np. co robi jakaś funkcja lub blok kodu:
Porada nr 3 — wprowadź obsługę błędów
Autor artykułu pracuje z systemami wbudowanymi od ponad 20 lat i świadczy usługi doradcze przez ponad połowę tego czasu. Jeśli istnieje obszar, względem którego obserwuje on sytuację, gdzie zespoły i programiści oszczędzają za każdym razem, to kwestia obsługi błędów w programie. Zidentyfikował on wiele kodów, w których wartości zwracane przez funkcje są ignorowane, a błędy mogą niezauważone przenikać całość, ponieważ żaden element w firmware nawet nie wie, że występują. Większość kodu jest pisana, zakładając, że wszystko będzie w porządku. Optymizm to wspaniała rzecz, ale w tym przypadku jest on nieprawidłowo umiejscowiony.
Można poprosić o dodanie obsługi błędów, jeśli generujemy kod za pomocą modelu AI, takiego jak ElektrodaBot. Tak właśnie można zrobić z kodem z poprzedniej porady. Procesowanie błędów to kluczowy element pisania stabilnego oprogramowania. Zamiast to ignorować, należy poprosić model AI o wygenerowanie kodu ich obsługi. Sprawi to, że Twoje oprogramowanie stanie się niezawodne. Nie będzie też trzeba poświęcać na to dużo czasu, poza szybką recenzją kodu. Jak poradził sobie z tym zadaniem ElektrodaBot?
Jak widać w powyższym cytacie — poradził sobie bardzo dobrze, dodając całkiem zaawansowany sposób obsługi szeregu błędów. Przy tym jednak nie uwzględnił jednej rzeczy — czy udało Wam się zauważyć, jaki błąd popełnił ElektrodaBot?
Porada nr 4 — wykorzystuj interakcje iteracyjne
W jednej z wcześniejszych wskazówek wspomnieliśmy, że warto być konkretnym, aby uzyskać pożądany wynik. Czasami jednak możemy nie wiedzieć dokładnie, czego chcemy od Bota, albo mamy pewien pomysł, ale nie jesteśmy pewni, jak dokładnie opisać swoje potrzeby. W takich sytuacjach możesz wykorzystać interakcje iteracyjne, aby np. znaleźć ścieżkę do kodu, który chcesz napisać.
Interakcje iteracyjne z AI mogą zaczynać się od ogólnego pomysłu lub potrzeby, a następnie, poprzez wymianę: „myśli” z modelem, stopniowo skutkować bardziej szczegółowym i dobrze zdefiniowanym wynikiem. Tak właśnie zrobiliśmy w powyższym przypadku — po otrzymaniu kodu programu do obsługi sensora dopytaliśmy Bota o obsługę błędów w kodzie w cytowanej odpowiedzi.
Porada nr 5 — proś o wyjaśnienia kodu
W pewnym momencie kariery każdy programista natrafi na kod, którego po prostu nie rozumie. Być może będzie to przy nauce nowego języka albo zwyczajnie w sytuacji, gdy jakaś osoba postanowi być sprytna i napisze coś, co potrafi przeniknąć tylko ona. W takich przypadkach model AI może pomóc zweryfikować nam, czy nasze zrozumienie kodu jest faktycznie poprawne.
Na przykład, załóżmy, że jesteś początkującym programistą C i po raz pierwszy spotykasz się ze wskaźnikami do funkcji w aplikacji. Prosta aplikacja może wyglądać tak, jak w poniższym pytaniu, które zadaliśmy ElektrodaBotowi:
Odpowiedź jest całkiem szeroka, ale niekoniecznie wyczerpująca. Jeżeli nadal jesteśmy głodni wiedzy, możemy dopytać ElektrodaBota o dowolny z elementów programu, podobnie, jak robiliśmy to wcześniej.
Porada nr 6 — przeprowadzaj recenzje kodu
Przegląd kodu to istotny proces, którego każdy zespół tworzący oprogramowanie wbudowane powinien używać. Jednak nierzadko zdarza się, że nie realizuje się tej operacji z należytą dyscypliną. Naciski biznesowe sprawiają z reguły, że recenzja jest pomijana, a zespoły starają się jak najszybciej dostarczyć kod. Ciekawym zastosowaniem modeli AI jest przeprowadzanie przeglądu. Zrealizujmy recenzję kodu z poprzedniej porady ponownie, prosząc tym razem o podanie zaleceń dotyczących jego udoskonalenia:
ChatGPT w artykule źródłowym również zwrócił uwagę na dodanie typedef-a, jednakże dołączył także inne uwagi — zalecił wpisanie explicite, że funkcje nie przyjmują żadnych parametrów, korzystając z (void) w definicji. Dodał także obsługę błędów — po pierwsze, wykrywanie, czy w funkcji greet nie jest podany pusty wskaźnik, a po drugie zaimplementowana została obsługa kodów błędów poprzez bibliotekę stderr, zamiast wypisywanie ich przez stdout.
Porada nr 7 – nie ufaj wynikowi
Ostatnią wskazówką dotyczącą pisania oprogramowania wbudowanego z wykorzystaniem ElektrodaBota, którą musimy przekazać w tym poście, jest zachowanie nieufności wobec rezultatów. Może to wydawać się sprzeczne z logiką, biorąc pod uwagę, jak właśnie omawialiśmy, jak pomocny może być nasz Bot w pisaniu oprogramowania. Zdecydowanie może on wspierać, ale to nie oznacza, że powinniśmy mu ślepo ufać. Trzeba dokładnie monitorować generowany kod i przeprowadzać własne jego recenzje, aby upewnić się, że całość działa zgodnie z oczekiwaniami. Bez strachu korzystajmy z modeli AI do wszystkich tych celów i metod, o których pisaliśmy, ale każdorazowo musimy upewnić się, że dokładnie sprawdzamy wyniki i testujemy je. Kiedy zaczniemy zbytnio ufać ElektrodaBotowi, możemy napotkać poważne problemy.
Zawsze należy weryfikować, czy rezultat podany przez Bota ma sens. Narzędzia te są tylko statystycznymi modelami, które generują najbardziej prawdopodobną odpowiedź z jakiejś sekwencji. Istnieją duże szanse, że dzisiejsze modele nie są szkolone na kodzie o wysokiej niezawodności. Oczywiście, można wykorzystać te techniki do napisania doskonałego oprogramowania wbudowanego, ale należy mieć na względzie, aby nie zawierzać bezkrytycznie odpowiedziom ElektrodaBota.
Podsumowanie
Najnowsze postępy w dziedzinie dużych modeli językowych umożliwiły AI generowanie kodu, także dla oprogramowania wbudowanego. W tym poście omówiliśmy kilka porad dotyczących współpracy z ElektrodaBotem w celu napisania oprogramowania wbudowanego. Wyniki, jakie można osiągnąć, mogą być bardzo pomocne. Można skrócić czas pisania kodu i, w konsekwencji, koszty jego rozwoju, ale trzeba bardzo uważać, w jaki sposób współpracujemy z modelem. Nie chcemy przekazywać na forum poufnych informacji ani niejawnego kodu. Nie możemy też ślepo ufać wynikom działania Bota.
Nadchodzące postępy w dziedzinie dużych modeli językowych znacząco wpłyną na to, jak będziemy projektować systemy wbudowane w przyszłości. Ta perspektywa jeszcze nie nadeszła, ale może być znacznie bliżej, niż chce się sądzić.
Artykuł źródłowy: https://www.embedded.com/7-expert-tips-for-writing-embedded-software-with-chatgpt/
Jeśli chcemy spożytkować AI do szybszego pisania lepszego kodu, trzeba wiedzieć, jak się do tego zabrać. W źródłowym artykule autorzy przyjrzeli się, jak wykorzystać ChatGPT do przyspieszenia pracy. W tym poście omówimy siedem tych samych porad dotyczących pisania oprogramowania wbudowanego, jako przykłady do zastosowania ElektrodaBota. Pokażemy, jak posiłkować się nim, aby zwiększyć naszą wydajność, przy jednoczesnej redukcji podatności na błędy i zmniejszenia ryzyka wystąpienia tych wygenerowanych przez sztuczną inteligencję.
Porada nr 1 — użyj AI do debugowania napisanego kodu
Debugowanie jest jedną z najmniej ulubionych czynności związanych z tworzeniem oprogramowania wbudowanego niemalże każdego programisty. Chociaż niektórzy uwielbiają wyzwania skorelowane z ustaleniem, dlaczego system zawiera błędy, to jednak w większości przypadków prawdziwe jest stwierdzenie Jacka Gansslesa: „Jeśli jest faza debugowania, to musiał być etap błędów”. Programiści systemów wbudowanych nie powinni być świetnymi debugerami; przede wszystkim muszą zapobiegać powstawaniu niedociągnięć w kodzie. Współczesne systemy wbudowane są złożone i pomimo stosowania najnowocześniejszych dostępnych technik i procesów, będą pojawiać się nieprawidłowości i nieoczekiwane zachowania, nad którymi będzie trzeba popracować.
Autor artykułu opisuje swój problem — niedawno integrował rejestrator do śledzenia wykonywania kodu z systemem zbudowanym na zamówienie klienta. Postępował zgodnie z instrukcjami podłączenia, ale odkrył, że pojawiały się błędy kompilacji z powodu wielu definicji. Urządzenie polegało na jakimś: „voodoo linkera”, aby biblioteka śledzenia zastąpiła bibliotekę RTOS wersjami opakowanymi w rejestrator. Voodoo jednak nie działało! Spoglądając szybko na plik make, wszystko wyglądało dobrze. To oznaczało dzień debugowania... Patrząc na wyniki pracy kompilatora, zauważył on, że niektóre rozszerzenia makr nie operowały poprawnie. Zamiast zajmować się normalnym procesem debugowania, zdecydował się skorzystać z AI. Sprawdźmy, jak ElektrodaBot poradzi sobie z takim zadaniem.
ElektrodaBot napisał:ghost666 napisał:Wydaje się, że problem polega na nieprawidłowym użyciu zmiennej specjalnej: „$(@)” wewnątrz Twojego pliku Makefile. Znak: „$(@)” w kontekście flagi DFLAGS oznacza: „nazwa celu”, co zazwyczaj jest plikiem wyjściowym generowanym przez daną regułę. W Twoim przypadku wygląda na to, że próbujesz utworzyć definicję preprocesora, która zawiera nazwę pliku źródłowego, ale nie masz reguły, która używa konkretnej nazwy pliku jako celu.Pracuję na kompilatorze XC32. W moim makefile ustawioną mam następującą flagę: DFLAGS := -mprocessor=ATSAME54P20A -D__inside_$(basename $(@))) -include ($SRC_DIR)/src/third_party/TraceRecorder/include/trcCTI.h dla kompilacji kodu, kompilator powinien użyć -D do stworzenia definicji z nazwą pliku, jednakże zamiast tego generuje -D__inside_, co można zrobić, aby rozwiązać ten problem?
Jednym z możliwych rozwiązań jest utworzenie zmiennych makefile dla każdego pliku źródłowego, które będą zawierały odpowiednią definicję preprocesora. Na przykład:
Kod: text
Ta metoda definiuje zestaw zmiennych DFLAGS, jedną dla każdego pliku źródłowego, który zawiera odpowiednią definicję preprocesora. Wówczas, podczas kompilacji każdego pliku źródłowego, używana jest odpowiednia zmienna DFLAGS. Pamiętaj jednak, że ta metoda może nie być idealna, jeśli masz wiele plików źródłowych, ponieważ generuje sporo dodatkowych zmiennych.
Alternatywnie, jeżeli korzystasz z GNU Make, możesz zastosować funkcję `eval` i `call`, aby dynamicznie generować część Twojego Makefile. Ta metoda jest bardziej złożona i wymaga pewnej znajomości składni GNU Make, ale jest elastyczniejsza i skalowalna w opozycji do powyższej techniki.
Jak widać, ElektrodaBot odpowiedział bardzo szeroko, o wiele obszerniej niż ChatGPT w oryginalnym artykule. Trafił także w sedno problemu, który autor źródłowego materiału miał ze swoim makefilem. Kłopot związany był z automatyczną zmienną. Dodatkowo, przepis budowania kodu wymagał niewielkiej korekty. Po przetestowaniu sugerowanych zmian okazało się, że rozwinięcie makra działa teraz poprawnie! Gdyby nie AI, debugowanie mogłoby zająć kilka godzin. Zamiast tego wystarczy parę minut, aby ElektrodaBot wskazał nam potencjalne obszary, gdzie występować mogą nieprawidłowości. To ogromne przyspieszenie procesu, zwiększenie wydajności programisty i, jednocześnie, dzięki obszernym odpowiedziom Bota, doskonalenie umiejętności.
Porada nr 2 — bądź konkretny i jasno określ swoje intencje
Autor, aby uzyskać odpowiedź, musiał dwukrotnie zapytać ChatGPT o rozwiązanie pewnych kwestii. Wynika to z faktu, że pierwsze pytanie było niedostatecznie konkretne. Oczywiście, jasno określił swoją intencję rozwiązania problemu, ale początkowo autor nie dostarczył pliku makefile. Dopiero gdy zapewnił modelowi wystarczająco dużo informacji i był precyzyjny oraz klarowny względem własnych zamiarów, otrzymał wynik, który pozwolił usunąć nieprawidłowość.
Pracując z modelami AI nad tworzeniem oprogramowania wbudowanego, ważne jest, aby być konkretnym i jasnym w swoich intencjach. W niektórych przypadkach może to być trudne. Jeśli piszemy tajny kod swojej firmy, nie można go po prostu wrzucić na forum, by zapytać ElektrodaBota... Niemniej istnieje szereg ogólnych problemów z oprogramowaniem, które można rozwiązać, pisząc kod przy użyciu AI.
Im więcej informacji dostarczymy modelowi, tym lepsze będą rezultaty. Na przykład, jeśli zapytamy Bota: „Muszę podłączyć się do czujnika”, to nie jest to zbyt konkretne, a model nie będzie wiedział, czego potrzebujemy. Autor dla zabawy wprowadził takie pytanie do ChatGPT. My sprawdziliśmy w tym zakresie ElektrodaBota:
ElektrodaBot napisał:ghost666 napisał:Cieszę się, że chcesz podłączyć się do sensora, ale potrzebuję więcej szczegółów, aby móc Ci pomóc.Muszę podłączyć się do sensora.
1. Jaki to jest sensor? Czy jest to sensor temperatury, wilgotności, ciśnienia, odległości czy może inny typ?
2. Co chcesz zrobić z tym sensorem? Czy chcesz go wykorzystać do monitorowania, sterowania urządzeniem, czy może do innej aplikacji?
3. Jakie masz doświadczenie w pracy z sensorami? Czy jesteś zaznajomiony z podstawami elektroniki, takimi jak napięcie, prąd, rezystancja?
4. Jaki sprzęt masz do dyspozycji? Czy używasz mikrokontrolera, Raspberry Pi, Arduino, czy może innego urządzenia?
5. Czy masz dostęp do schematu podłączenia tego sensora?
Podając te informacje, będę w stanie udzielić Ci bardziej szczegółowych i konkretnych wskazówek.
Identycznej odpowiedzi udzielił też chatbot autorowi artykułu... Porównajmy teraz, co stanie się, gdy zadamy mu o wiele konkretniejsze pytanie:
ElektrodaBot napisał:ghost666 napisał:Przykładowa funkcja, której szukasz, mogłaby wyglądać tak:Muszę napisać funkcję w języku C dla systemu wbudowanego, która komunikuje się z czujnikiem temperatury TMP36 za pomocą protokołu I2C. Funkcja powinna nawiązać połączenie z czujnikiem, odczytać dane temperaturowe co 5 sekund, przeliczyć surowe na stopnie Celsiusza i zwrócić wartość temperatury. Dodatkowo, funkcja powinna zawierać obsługę błędów w przypadkach, gdy czujnik nie odpowiada.
Kod: C / C++
Proszę pamiętać, że jest to przykładowy kod i może wymagać modyfikacji, aby zadziałał w Twoim konkretnym środowisku. Adres czujnika oraz adres rejestru temperatury mogą być inne w zależności od konfiguracji Twojego systemu. Funkcje sterownika I2C (`I2C_Init`, `I2C_ReadReg`) mogą mieć różne nazwy i parametry w zależności od używanej biblioteki. Proces przeliczania surowych danych na stopnie Celsiusza zależy od specyfikacji czujnika. W tym przypadku założyłem, że surowe dane są 12-bitowymi liczbami zmiennoprzecinkowymi, ale to może się różnić w zależności od czujnika. Wreszcie, `_delay_ms` to funkcja z biblioteki AVR GCC, która opóźnia wykonanie programu o daną liczbę milisekund. Jeśli nie jest dostępna w Twoim środowisku, powinieneś znaleźć odpowiednik.
ElektrodaBot dostarczył nam kompletny kod! Podobnie jest w stanie robić ChatGPT. W przykładzie w artykule źródłowym AI dodatkowo objaśniło, po co zastosowano poszczególne elementy w kodzie, czego nie zrobił ElektrodaBot. Jednakże to na nic, ponieważ kod był niepoprawny, mimo wyrażenia prośby, by komunikować się z termometrem za pomocą I²C. Znowu punkt dla ElektrodaBota. Brak szerszego opisu nie jest wszakże problemem, ElektrodaBot dodał w kodzie całkiem sporo komentarzy, a jeśli i to jest dla nas za mało, możemy dodatkowo dopytać, np. co robi jakaś funkcja lub blok kodu:
ElektrodaBot napisał:ghost666 napisał:Funkcja `I2C_ReadReg(TMP36_ADDR, TMP36_REG_TEMP, buffer, 2)` jest używana do odczytu danych z czujnika TMP36 za pomocą protokołu I2C. Funkcja ta jest częścią biblioteki sterownika I2C i jest zazwyczaj dostarczana przez producenta mikrokontrolera lub innego dostawcę.Co robi ta funkcja:
I2C_ReadReg(TMP36_ADDR, TMP36_REG_TEMP, buffer, 2)
Oto co robią poszczególne argumenty:
1. `TMP36_ADDR`: to jest adres urządzenia I2C na magistrali I2C, w tym przypadku jest to adres czujnika temperatury TMP36. Adresy I2C są używane do identyfikacji konkretnych urządzeń na magistrali I2C.
2. `TMP36_REG_TEMP`: jest to adres rejestru w urządzeniu I2C, z którego chcemy odczytać dane. W tym przypadku jest to rejestr przechowujący odczyt temperatury z czujnika TMP36.
3. `buffer`: jest to wskaźnik na tablicę, w której będziemy przechowywali dane odczytane z urządzenia. W tym przypadku tablica `buffer` ma rozmiar 2 bajty, ponieważ odczyt z czujnika TMP36 zwraca dane o temperaturze w formacie 16-bitowym.
4. `2`: jest to liczba bajtów, które chcemy odczytać z urządzenia. W tym przypadku chcemy odczytać 2 bajty danych z rejestru temperatury.
Pełna funkcja `I2C_ReadReg` odczytuje dane z określonego rejestru urządzenia I2C i zapisuje je do buforu. Jeżeli wystąpi jakikolwiek problem z komunikacją I2C, funkcja zwróci kod błędu. Jeżeli komunikacja przebiegnie pomyślnie, funkcja zwróci wartość `I2C_OK`.
Porada nr 3 — wprowadź obsługę błędów
Autor artykułu pracuje z systemami wbudowanymi od ponad 20 lat i świadczy usługi doradcze przez ponad połowę tego czasu. Jeśli istnieje obszar, względem którego obserwuje on sytuację, gdzie zespoły i programiści oszczędzają za każdym razem, to kwestia obsługi błędów w programie. Zidentyfikował on wiele kodów, w których wartości zwracane przez funkcje są ignorowane, a błędy mogą niezauważone przenikać całość, ponieważ żaden element w firmware nawet nie wie, że występują. Większość kodu jest pisana, zakładając, że wszystko będzie w porządku. Optymizm to wspaniała rzecz, ale w tym przypadku jest on nieprawidłowo umiejscowiony.
Można poprosić o dodanie obsługi błędów, jeśli generujemy kod za pomocą modelu AI, takiego jak ElektrodaBot. Tak właśnie można zrobić z kodem z poprzedniej porady. Procesowanie błędów to kluczowy element pisania stabilnego oprogramowania. Zamiast to ignorować, należy poprosić model AI o wygenerowanie kodu ich obsługi. Sprawi to, że Twoje oprogramowanie stanie się niezawodne. Nie będzie też trzeba poświęcać na to dużo czasu, poza szybką recenzją kodu. Jak poradził sobie z tym zadaniem ElektrodaBot?
ElektrodaBot napisał:ghost666 napisał:Okej, zrozumiałem. Możemy na pewno dodać więcej obsługi błędów do naszej funkcji. Na przykład, moglibyśmy uwzględnić obsługę błędów dla sytuacji, gdy surowe dane z czujnika są nieprawidłowe lub gdy konwersja tych danych na stopnie Celsiusza nie powiedzie się. Poniżej znajduje się zmodyfikowany kod:[...]. Wreszcie, `_delay_ms` to funkcja z biblioteki AVR GCC, która opóźnia wykonanie programu o daną liczbę milisekund. Jeśli nie jest dostępna w Twoim środowisku, powinieneś znaleźć odpowiednik.
Czy możesz dopisać do powyższego kodu do obsługi sensora również obsługę błędów poszczególnych elementów?
Kod: C / C++
Ten kod dodaje opcję sprawdzenia błędów dla surowych danych z czujnika oraz dla przeliczanych danych na stopnie Celsiusza. Jeśli odczytany pomiar jest nieprawidłowy, funkcja `readTmp36()` zwróci -1, co jest następnie weryfikowane w pętli głównej programu. Jeśli wystąpi nieprawidłowość, program wydrukuje komunikat o błędzie i spróbuje ponownie odczytać temperaturę po 5 sekundach.
Jak widać w powyższym cytacie — poradził sobie bardzo dobrze, dodając całkiem zaawansowany sposób obsługi szeregu błędów. Przy tym jednak nie uwzględnił jednej rzeczy — czy udało Wam się zauważyć, jaki błąd popełnił ElektrodaBot?
Porada nr 4 — wykorzystuj interakcje iteracyjne
W jednej z wcześniejszych wskazówek wspomnieliśmy, że warto być konkretnym, aby uzyskać pożądany wynik. Czasami jednak możemy nie wiedzieć dokładnie, czego chcemy od Bota, albo mamy pewien pomysł, ale nie jesteśmy pewni, jak dokładnie opisać swoje potrzeby. W takich sytuacjach możesz wykorzystać interakcje iteracyjne, aby np. znaleźć ścieżkę do kodu, który chcesz napisać.
Interakcje iteracyjne z AI mogą zaczynać się od ogólnego pomysłu lub potrzeby, a następnie, poprzez wymianę: „myśli” z modelem, stopniowo skutkować bardziej szczegółowym i dobrze zdefiniowanym wynikiem. Tak właśnie zrobiliśmy w powyższym przypadku — po otrzymaniu kodu programu do obsługi sensora dopytaliśmy Bota o obsługę błędów w kodzie w cytowanej odpowiedzi.
Porada nr 5 — proś o wyjaśnienia kodu
W pewnym momencie kariery każdy programista natrafi na kod, którego po prostu nie rozumie. Być może będzie to przy nauce nowego języka albo zwyczajnie w sytuacji, gdy jakaś osoba postanowi być sprytna i napisze coś, co potrafi przeniknąć tylko ona. W takich przypadkach model AI może pomóc zweryfikować nam, czy nasze zrozumienie kodu jest faktycznie poprawne.
Na przykład, załóżmy, że jesteś początkującym programistą C i po raz pierwszy spotykasz się ze wskaźnikami do funkcji w aplikacji. Prosta aplikacja może wyglądać tak, jak w poniższym pytaniu, które zadaliśmy ElektrodaBotowi:
ElektrodaBot napisał:ghost666 napisał:Wyjaśnij mi dokładnie, jak działa poniższy kod:
Kod: C / C++
Rozważany tutaj kod demonstruje jedno z zastosowań wskaźników do funkcji w języku C. Wskaźniki do funkcji są potężnym narzędziem, które pozwala na przechowywanie adresów funkcji, a następnie wywoływanie tych funkcji za pomocą wskaźnika. To umożliwia programistom tworzenie kodu bardziej generycznego i wielokrotnego użytku.
Rozważmy kod krok po kroku:
1. `void print_hello();` i `void print_goodbye();`: te linie deklarują dwie funkcje, które nie przyjmują żadnych argumentów i nie zwracają wartości.
2. `void greet(void (*fp)()) { fp(); }`: tutaj mamy funkcję `greet`, która przyjmuje jako argument wskaźnik na funkcję. Wskaźnik na funkcję jest typem `void (*)()`. Co oznacza, że jest to wskaźnik na funkcję, która nie przyjmuje żadnych argumentów i nie zwraca wartości. Funkcja `greet` wywołuje funkcję wskazywaną przez wskaźnik.
3. W funkcji `main`, deklarujemy wskaźnik na funkcję o nazwie `fp`. Następnie przypisujemy `fp` do adresu funkcji `print_hello`, a dalej przekazujemy `fp` jako argument do funkcji `greet`, co powoduje wywołanie funkcji `print_hello` i wydrukowanie napisu: „Hello!”.
4. Następnie zmieniamy `fp` na adres funkcji `print_goodbye`, a dalej wywołujemy `greet(fp)`. Skutkuje to wywołaniem funkcji `print_goodbye` i wydrukowaniem napisu „Goodbye!”.
5. `void print_hello() { printf("Hello!\n"); }` i `void print_goodbye() { printf("Goodbye!\n"); }`: te dwie funkcje są zdefiniowane na końcu i są odpowiedzialne za wydrukowanie „Hello!” i „Goodbye!”.
Tak więc ten kod pokazuje, jak możemy użyć wskaźników, aby stworzyć funkcje wyższego rzędu, które mogą przyjmować inne funkcje jako argumenty i wywoływać je. Jest to przydatne w szeregu sytuacji, takich jak tworzenie funkcji obsługi zdarzeń, operacje na tablicach z funkcjami jako argumentami i w wielu innych.
Odpowiedź jest całkiem szeroka, ale niekoniecznie wyczerpująca. Jeżeli nadal jesteśmy głodni wiedzy, możemy dopytać ElektrodaBota o dowolny z elementów programu, podobnie, jak robiliśmy to wcześniej.
Porada nr 6 — przeprowadzaj recenzje kodu
Przegląd kodu to istotny proces, którego każdy zespół tworzący oprogramowanie wbudowane powinien używać. Jednak nierzadko zdarza się, że nie realizuje się tej operacji z należytą dyscypliną. Naciski biznesowe sprawiają z reguły, że recenzja jest pomijana, a zespoły starają się jak najszybciej dostarczyć kod. Ciekawym zastosowaniem modeli AI jest przeprowadzanie przeglądu. Zrealizujmy recenzję kodu z poprzedniej porady ponownie, prosząc tym razem o podanie zaleceń dotyczących jego udoskonalenia:
ElektrodaBot napisał:ghost666 napisał:Oceń proszę jakość tego kodu i zasugeruj, jakie można wprowadzić poprawki:
[...]
Ogólnie rzecz biorąc, ten kod jest dobrze napisany. Jest prosty i łatwy do zrozumienia, co jest kluczowym aspektem. Jednakże mogę zasugerować kilka drobnych zmian, które mogą posłużyć jako usprawnienie:
1. Zdefiniowanie funkcji z góry: w języku C preferowane jest zdefiniowanie funkcji przed jej użyciem. Oznacza to, że zamiast deklarować funkcje na początku (np. `void print_hello();`), możemy je zdefiniować na wstępie. To pozwoli na usunięcie deklaracji i uczyni kod bardziej zrozumiałym.
2. Wskaźniki do funkcji w typach: wskaźniki do funkcji mogą być trudne do zrozumienia. To mogłoby być trochę łatwiejsze, gdyby użyć typedef do zdefiniowania typu dla wskaźnika do funkcji.
3. Dodanie komentarzy: komentarze są zawsze ważne w kodzie do wyjaśnienia, co robi dany fragment, szczególnie gdy używane są bardziej zaawansowane konstrukcje, takie jak wskaźniki do funkcji.
Oto poprawiona wersja kodu, która uwzględnia te sugestie:
Kod: Text
Należy pamiętać, że opinie na temat jakości kodu mogą się różnić w zależności od osoby, stylu kodowania i preferencji. Powyższy kod jest jedynie sugestią i nie jest jedynym: „poprawnym” sposobem jego pisania.
ChatGPT w artykule źródłowym również zwrócił uwagę na dodanie typedef-a, jednakże dołączył także inne uwagi — zalecił wpisanie explicite, że funkcje nie przyjmują żadnych parametrów, korzystając z (void) w definicji. Dodał także obsługę błędów — po pierwsze, wykrywanie, czy w funkcji greet nie jest podany pusty wskaźnik, a po drugie zaimplementowana została obsługa kodów błędów poprzez bibliotekę stderr, zamiast wypisywanie ich przez stdout.
Porada nr 7 – nie ufaj wynikowi
Ostatnią wskazówką dotyczącą pisania oprogramowania wbudowanego z wykorzystaniem ElektrodaBota, którą musimy przekazać w tym poście, jest zachowanie nieufności wobec rezultatów. Może to wydawać się sprzeczne z logiką, biorąc pod uwagę, jak właśnie omawialiśmy, jak pomocny może być nasz Bot w pisaniu oprogramowania. Zdecydowanie może on wspierać, ale to nie oznacza, że powinniśmy mu ślepo ufać. Trzeba dokładnie monitorować generowany kod i przeprowadzać własne jego recenzje, aby upewnić się, że całość działa zgodnie z oczekiwaniami. Bez strachu korzystajmy z modeli AI do wszystkich tych celów i metod, o których pisaliśmy, ale każdorazowo musimy upewnić się, że dokładnie sprawdzamy wyniki i testujemy je. Kiedy zaczniemy zbytnio ufać ElektrodaBotowi, możemy napotkać poważne problemy.
Zawsze należy weryfikować, czy rezultat podany przez Bota ma sens. Narzędzia te są tylko statystycznymi modelami, które generują najbardziej prawdopodobną odpowiedź z jakiejś sekwencji. Istnieją duże szanse, że dzisiejsze modele nie są szkolone na kodzie o wysokiej niezawodności. Oczywiście, można wykorzystać te techniki do napisania doskonałego oprogramowania wbudowanego, ale należy mieć na względzie, aby nie zawierzać bezkrytycznie odpowiedziom ElektrodaBota.
Podsumowanie
Najnowsze postępy w dziedzinie dużych modeli językowych umożliwiły AI generowanie kodu, także dla oprogramowania wbudowanego. W tym poście omówiliśmy kilka porad dotyczących współpracy z ElektrodaBotem w celu napisania oprogramowania wbudowanego. Wyniki, jakie można osiągnąć, mogą być bardzo pomocne. Można skrócić czas pisania kodu i, w konsekwencji, koszty jego rozwoju, ale trzeba bardzo uważać, w jaki sposób współpracujemy z modelem. Nie chcemy przekazywać na forum poufnych informacji ani niejawnego kodu. Nie możemy też ślepo ufać wynikom działania Bota.
Nadchodzące postępy w dziedzinie dużych modeli językowych znacząco wpłyną na to, jak będziemy projektować systemy wbudowane w przyszłości. Ta perspektywa jeszcze nie nadeszła, ale może być znacznie bliżej, niż chce się sądzić.
Artykuł źródłowy: https://www.embedded.com/7-expert-tips-for-writing-embedded-software-with-chatgpt/
Fajne? Ranking DIY
