programowanie w C - bardzo ogólne pytanie o filozofi
Oct 23, 2017 78 Replies
P
Piotr Gałka
W dniu 2017-10-30 o 17:32, slawek pisze:
Takiego typu warunku się nie spodziewałem. Myślałem raczej, że jakieś opcje debuggowania, czy pracy w grupie, czy jakieś biblioteki są wycięte. Ale kiedyś sprawdzę. Jeśli faktycznie to się nie załapię. Sam mam 3 komputery - jeden w sieci, drugi nie podłączony i stary z XP dla tego co nie działa pod Win7. Brat tak samo, a nie jesteśmy sami. A może liczą się tylko te podłączone - to wtedy mam jeden :) P.G.
Didn't find your answer? Ask the community — no account required.
T
ToMasz
Tatuś już od dawna nie żył, a mamusia tyrała.
no więc prosiłem o napisanie jak w c obejść goto (gosub)
ale to nie jest wskazówka. pisanie że goto jest do zastąpienia w inny sposób już od lat 70 to też nie wskazówka. a analiza mojej rodziny to już granica dobrego wychowania.
i co się wtedy stanie? ruszy a ja z premedytacją wsadzę tam rękę? Po co to piszesz? Masz w tym jakiś cel? skąd wiesz ile pralek naprawiłem? Nie wpadłeś na to, że właśnie ta ilość niedziałającej elektroniki skłania mnie do realizacji pomysłu z arduino?
ToMasz
M
Mateusz Viste
Kopiesz się z koniem - nie wygrasz :) Koń (lub troll) - ma to do siebie że w kopaniu się ma dużą wprawę, tyle że na tym kończą się jego umiejętności. Nie trać czasu - użyj killfile.
Mowa tutaj o pralce, a nie o kontrolerze lotów kosmicznych, więc nie ma sensu wiele kombinować. Jeśli goto pasuje do tego co chcesz osiągnąć i działa - nie ma powodu by go nie użyć. Zawsze najsłuszniej korzystać z narzędzi które się zna i nad którymi ma się kontrolę.
Nie jestem co prawda jednym z tych zagorzałych przeciwników goto, ale sam raczej w tym kontekście zrobiłbym to inaczej: "program" pralki to nic innego jak ciąg różnych akcji o pewnej długości. Być może coś takiego miałoby sens:
void wirowanie(int czas, int szybkosc) { ... }
void plukanie(int czas, int szybkosc) { ... }
void grzanie(int temperatura) { for (;;) { int t = zmierz_temp_wody(); if (t >= temperatura) break; wlacz_grzalke();/* grzałka jest "włączana" w kółko, gdyż z */ /* powodów bezpieczeństwa wyłącza się sama */ /* po kilkunastu sekundach bez sygnału */ sleep(5); } wylacz_grzalke(); }
void pranie(int czas, int szybkosc) { ... }
Czyli definiujesz zestaw funkcji które odpowiadają za "podstawowe" czynności które pralka potrafi wykonać. Następnie programujesz cykle wywołując powyższe funkcje w odpowiedniej kolejności i ze stosownymi parametrami:
Naszło mnie aby to przeczytać jeszcze raz i jeszcze raz itd... Czytając:
"pranie? nie nie pierz, ale sprawdz jak się pierze. płukanie? Nie nie płukaj, ale już wiesz jak to należało zrbić? przeczytałeś procesorku?"
mam wrażenie, że Ty uważasz, że jak jest if(warunek) { zrób jedno coś; zrób inne coś; zrób coś na zakończenie; }
i warunek jest false to procesor będzie studiował znak po znaku to co jest napisane w {} szukając } zamykającego blok wykonywany warunkowo.
Otóż nic z tych rzeczy - on od razu skoczy za } Zapominasz, że kod źródłowy został dawno przeanalizowany przez kompilator i w programie, który widzi procesor jest po prostu skok w odpowiednie miejsce gdy warunek jest false.
W programie, który widzi procesor, jest cała masa goto. Różnica jest taka, że o to aby te skoki były w dobre miejsca dba kompilator a nie programista.
Jeszcze słówko o pomijaniu kawałków programu w przypadku błędów - bo mam wrażenie, że to też miejsce gdzie chciałbyś mieć goto.
W prostym przypadku, gdy mamy wykonać serię czynności, ale jak któraś się nie uda to mamy pominąć pozostałe i na końcu wiedzieć, że był błąd to zakładając, że mamy serię funkcji z których każda zwraca true jak się jej udało i false jak się nie udało to można to zapisać np. tak:
lub krócej: bool ok = fun1() && fun2() && fun3() && fun4();
gdyż operator && (logiczne and) nie sprawdza wartości tego czego nie musi - jak np. fun2() da false to on już wie, że wynik całego wyrażenia będzie false i nie ustala wartości fun3() i fun4() czyli ich nie wykonuje.
I w obu przypadkach jak fun2() zwróci false to procesor nie będzie czytał dalszego kawałka programu tylko ma w programie skok na koniec tej sekwencji. P.G.
S
slawek
Nie wsadzisz. Bo ona już tam będzie. W środku. I nie wyciągniesz. Bo czas reakcji człowieka jest dłuższy niż czas pełnego obrotu bębna przy wirowaniu. Jeżeli ładowana od góry to amputacja, złamanie np. obu kości przedramienia lub coś w ten deseń. Jeżeli ładowana od przodu to np. rozerwanie wiązadeł, uszkodzenia stawów, cokolwiek.
A nie da się wyjąć upranych rzeczy nie wkładając łap. No chyba że będziesz używał szczypiec czy czegoś.
Trochę naoglądałem się ludzi po podobnych wypadkach, np. rekonstrukcja dłoni bo śmigło w dronie "samo" ruszyło.
S
slawek
Że aby ładnie takie rzeczy oprogramować to potrzebne są wątki i/lub kolejka priorytetowa.
Przydałoby się także kopać psa.
A zacząć od przeczytania dobrego podręcznika do C, polecam Sexton "Język C to proste" i Francuz "C dla AVR" (czy jakoś tak).
I obejrzeć sobie jakiś open source - taki który dobrze działa - pełno tego wszędzie - to lepsze niż nadęte akademickie przykłady.
S
slawek
Sprawdź sam, ale jeżeli czegoś nie pomyliłem to...
Liczy się, IMO, ile kopi jest używanych w firmie. Czyli jeżeli firma ma komputer z MSVS Community to ok. Jeżeli dwa takie, to ok. Jeżeli używasz jako hobbysta i masz to na trzech... to ok. Ale jak jest sześciu ludzi w firmie i jakieś np. osiem razy zainstalowane VS Community... to już nie jest ok. Jeżeli to firma, a nie szkoła. Szkoły nie mają ograniczenia, studenci (do uczenia się) też nie. Chyba jeszcze research się też łapie na Community. Z drugiej strony student jako osoba fizyczna się łapie.
Ale np. firma zatrudniająca 100 programistów... No sorry, koszt licencji 100 sztuk kompilatora to dla niej mały pryszcz. I na Community się nie załapie.
Zresztą poczytaj sam: wyszukaj Visual Studio Community w Google.
Swego czasu były darmowe wersje Express - każdy mógł używać do czego chciał - komercjalnie też. Od normalnych różniły się że nie miały tego i owego. Ale w praktyce i tak miały wszystko co potrzebne. (Z rzeczy ciekawych a wyciętych to OpenMP). Microsoft chyba przestał te expressy wypuszczać.
P
Piotr Gałka
W dniu 2017-10-31 o 18:40, slawek pisze:
Znalazłem jakąś licencję z której wynika że jak firma:
- ma mniej niż 250 komputerów i jednocześnie
- przychód mniejszy niż 1 mln USD to nie jest firmą.
A jak nie jest firmą to może gratis używać to na 5 wskazanych komputerach. Dla open source czy dla edukacji to można nawet jak się jest firmą.
Natomiast tego co piszą o zasadach udostępniania tego co się napisało to ni w ząb nie rozumiem. Tam coś piszą o zapewnieniu w licencji co najmniej takiej samej ochrony jak ta licencja, ale nie wiem kiedy. Ciekawe, czy jak coś napiszę i będę chciał komuś exe udostępnić to też muszę jakieś licencje wypisywać. Czy jak przetestuję kod źródłowy i będę chciał udostępnić źródła to już jest praca nad projektem open-source.
Oczywiście gdzieś sobie zapisuję to hasło i ... może kiedyś, bo teraz brak czasu.
Zastanawia mnie co to znaczy "wskazany komputer". Czy to się nie sprowadzi do tego, że nie uda mi się tego zainstalować i używać na komputerze na którym pracuję - czyli nie połączonym do sieci.
To nie są pytania do grupy tylko takie sobie moje wątpliwości. P.G.
T
ToMasz
DZIĘKI
ToMasz
J
Jacek Radzikowski
Ja bym zaczął od porządnego zdefiniowania problemu: Każde z zadań składa się z serii kroków, a każdy krok ma określony zestaw wyjść, warunek jaki musi być spełniony żeby przejść do kolejnego kroku, oraz numer następnego kroku. Te wszystkie informacje da się opisać jako w miarę prostą strukturę:
typedef WarunekWyjścia bool (*f)(); struct { int nastepnyKrok; int wyjscia[liczbaWyjsc]; int czasTrwania; WarunekWyjscia funkcjaTestujaca; } KrokOperacji;
Co oznaczają pola w strukturze:
nastepnyKrok - to jest indeks w tabeli opisującej zestaw kroków dla danej operacji, do którego kroku przejeść po spełnieniu warunku wyjścia dla danego kroku.
wyjścia - Tabela opisująca stan wyjść dla danego kroku. W najprostszym przypadku to mogą być wartości jakie należy wysłać na piny mikrokontrolera: np. pierwszej pozycji w tabeli odpowiada pin sterujący wolnymi obrotami w lewo. Druga pozycja ro wolne obroty w prawo. Trzecia to włączenie grzałki, itd. "Wyjścia" mogą też uruchamiać funkcje wykonujące bardziej skomplikowane operacje. Wszystko zależy od implementacji.
czasTrwania - Jeśli ustawione jest na wartość większą od zera, to mówi przez jak długo ma trwać dany krok. Jeśli ostawione jest na zero, to wywoływana jest funkcja testująca warunek stopu.
funkcjaTestująca - funkcja zwracająca true jeśli pralka osiągnęła stan kiedy można przejść do kolejnego kroku, albo false, jeśli trzeba czekać dalej (np. sprawdzanie czy temperatura wody osiągnęła wymaganą temperaturę, albo czy pralka jest napełniona wodą.)
Opis każdej operacji będzie zawarty w tabeli takich struktur, składającej się w tylu wierszy, ile jest kroków:
struct KrokOperacji operacjaWirowanie[] = { ..... }; itd.
Na pierwszy rzut oka to może wyglądać jak niepotrzebne komplikowanie sobie życia, ale w rzeczywistości to przekłada się na olbrzymie uproszczenie programu sterującego, który nie zależy od tego jak są zdefiniowane operacje. Zmiana w opisie operacji pociągnie za sobą jedynie zmianę tabeli ja opisującej, bez potrzeby modyfikowania kodu.
Główna pętla programu sterującego będzie wyglądać mniej-więcej w taki sposób:
void loop() { switch(operacja) { case 0: // czekaj na wybranie programu operacja = wybórOperacji(); krok = 0; break;
case 1: // pranie //Funkcja zwróci numer kroku do którego należy przejść. Jeśli krok = nastepnyKrok(operacjaPranie, krok)
// krok < 0 oznacza koniec operacji i wracamy do wyboru programu if(krok < 0) operacja = 0 break; case 2: // pranie krok = nastepnyKrok(operacjaWirowanie, krok) if(krok < 0) operacja = 0 break; ... // pozostałe operacje default: operacja = 0; // kiedy operacja nie jest zdefiniowana, powróć do wyboru programu } }
//Funkcja sprawdzająca czy użytkownik che uruchomić jakąś operację, i zwracająca jej indeks. int wybórOperacji() { if(wybranePranie) operacja = 1; else if (wybraneWirowanie) operacja = 2; else .... ....
else operacja = 0; //w pozostałych przypadkach zawsze wróć do wyboru operacji return operacja }
Tak implementacja głównej pętli jest bardzo rozwlekła, ale zależało mi na pokazaniu jak ręcznie obsłużyć każdy z programów. Kosztem niewielkiego zwiększenia skomplikowania tabeli opisującej programy, i (pozornego) zmniejszenia czytelności głównej pętli, można ją mocno skrócić.
I teraz chyba najważniejsza funkcja programu, wyliczająca następny krok programu. Jeśli nie nadszedł czas na przejście do następnego, to zwraca numer obecnego kroku
int nastepnyKrok(struct KrokOperacji *opis, int krok) { // jeśli przerywamy program, to wróć do wyboru operacji if(przerwanieProgramu) { zatrzymajPralkę(); return -1; }
opisKroku = opis[krok]; //opis wykonywanego kroku
//Ustaw wyjścia dla aktualnego kroku. //Ustawianie wyjść tutaj ma tę zaletę, ze pożądany stan wyjśc będzie ustawiany przy każdym obiegu pętli. Wadą jest to że ustawianie wyjść jest wywoływane przy każdym obiegu pętli, co w wyjątkowych sytuacjach może mieć niepożądane następstwa. ustawWyjścia(opisKroku.wyjścia);
//jeśli obecna operacja ma trwać określony czas, to sprawdź czy jeszcze odlicza timer. if(timerAktywny) { if(timer > 0) // czas nie upłynął. Zwróć numer aktualnego kroku return krok
//Czas upłynął. Zatrzymaj timer i zwróć indeks kolejnego kroku zatrzymajTimer(); return opisKroku.nastepnyKrok; }
//Jeśli timer nie jest aktywny, to albo trzeba zbadać warunek wyjście, albo ustawić timer dla kolejnego kroku. if(opisKroku.czasTrwania > 0) // krok trwa określony czas) { uruchomTimer(opisKroku.czasTrwania); return krok; }
//sprawdź warunek wyjścia if(opisKroku.funkcjaTestujaca()) //funkcja zwróciła true, przechodzimy do kolejnego kroku return opisKroku.nastepnyKrok
//nic się nie dzieje, pozostajemy dalej w tym samym kroku return krok }
Z doprowadzeniem kodu do postaci kompilowalnej i działającej, zaimplementowaniem obsługi timera odmierzającego czas i funkcji pomocniczych testujących warunki i ustawiających wyjścia powinieneś poradzić sobie sam :)
Jacek.
S
slawek
Tak.
Nie.
Pralka ma: być bezpieczna dla użytkownika; wykonywać polecenia użytkownika; nie zniszczyć tego co pierze; skutecznie wyprać; dbać o swój stan techniczny; oszczędzać prąd, wodę, detergenty i środowisko (w tym nie hałasować); zachowywać się w zrozumiały i przewidywalny sposób; mieć innowacje, np. dać się programować ze smartfona i przez internet, przesyłać fotki do Facebooka itp. itd. W tej kolejności.
Teraz masa pracy aby to wszystko przełożyć jeszcze nie na program, ale na jakąś ogólną architekturę. Sprawy nie upraszcza że jest nieustalone jeszcze hardware. Ważne: oszacować ilu ludzi, jacy ludzie, gdzie, jaki czas, jakie narzędzia i czy to wszystko będzie możliwe. Kto to sfinansuje i czy będzie to opłacalne? (Np. w ty i syn, dobry elektronik, początkujący programista, w garażu, dwa lata, język C++, ty i żona, tak jeżeli junior przez to będzie miał lepszy start życiowy i ogólnie zyskiem ma być radość z hobby.) WAŻNE: CZY SĄ JAKIEŚ OGRANICZENIA PRAWNE? Uprawnienia do projektowania, wykonania, ograniczenia ze strony wspólnoty mieszkaniowej itp. Licencje. Patenty.
A to dopiero początek.
S
slawek
Fuj.
A nie prościej kolejka priorytetowa poleceń?
J
jacek
W dniu 2017-11-01 o 08:00, slawek pisze:
Każda pralka ma podstawową funkcjonalność w postaci zabezpieczenia drzwiczek zamkiem, które w momencie załączenia zasilania zamyka zamek oraz styków potwierdzających zamknięcie. W najprostszym układzie podłączenie sterownika silnika poprzez ten styk zapewnia zabezpieczenie przed wsadzeniem ręki czy głowy podczas pracy pralki. Odłączenie zasilania pralki nie powoduje zwolnienie blokady od razu tylko po ok 2 minutach co zapewnia bezpieczne zatrzymanie. W ten sposób zabezpiecza się "użyszkodnika" przed urazami od pralki. Zabezpieczenie przed zalaniem także jest prosto zrealizowane przez styki hydrostatu, który rozwiera się gdy poziom wody osiągnie maksymalny poziom. W przypadku zastosowania tych dwóch zabezpieczeń szkody wyrządzone przez pralkę będą minimalne. Sterownik dodatkowo może pilnować czasu napełniania, długości czasu grzania itp i na ich podstawie wystawiać statusy na facebooku czy innym portalu :)
Takie problemy to można mieć w korporacji ale w domu czy garażu osoby prywatnej to można wziąć czteropaka czy dwa i razem z synem posiedzieć i popróbować. Gdy nie zadziała to znów rano do sklepu itd...
J
Jacek Radzikowski
Masz coś przeciwko maszynom stanowym? :)
Jacek.
S
slawek
Niekoniecznie. Wystarczy że będzie np. zdjęta obudowa.
S
slawek
To najprostsza droga do alkoholizmu.
S
slawek
A może to przetwarzać polecenia z kolejki? ;)
J
Jacek Radzikowski
Może, ale po co? W pralce masz stałą listę kroków do wykonania, która po dopracowaniu najprawdopodobniej nie zmieni się do czasu aż blacha przerdzewieje i trzeba będzie sprzęt zutylizować. Kolejka miała by sens kiedy lista kroków była by dynamiczna. Jeśli ktoś chce sobie potrenować to można zrobić, ale to jest trochę taka armata na muchy.
Jacek.
S
slawek
No coś ty! Pralka Światowid nie ma jakichś tam kroków, tylko wyłącznik czasowy napędzany sprężyną. A Frania nie wiem czy nawet to.
Automatyka wagowa, czujnik piany, czujnik drgań, poziomu wody, położenie i prędkość bębna, termometry, może i ciśnienie wody, ciśnienie powietrza, być może absorbcja światła (test czy woda jest czysta?) i pomiar napięcia zasilania. To tak na szybko, bo coś jeszcze da się wymyślić.
Do tego interfejs graficzny, sterowanie przez smartfon, WiFi, diagnostyka i serwisowanie.
Join the Discussion
Have something to add? Share your thoughts — no account required.
Didn't find your answer?
Ask the community — no account required
Report Content
You are reporting this content to the moderators. They will look at it
ASAP.