Skocz do zawartości

Elvis

Użytkownicy
  • Zawartość

    2435
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    171

Wszystko napisane przez Elvis

  1. Z tego co na szybko można o module hc05 wyczytać, napięcie zasilania powinno być w zakresie 3.6-5V. Natomiast linie sterujące max. 3.3V. Nie wiem do czego był ten dzielnik używany, na pewno nie powinno być go przy zasilaniu modułu, nie powinno się również bezpośrednio łączyć 5V do linii sterujących. Edit: chyba dałem się podejść opisowi na stronie Botlandu. W sumie już sam nie wiem czy ten moduł toleruje 5V czy nie.
  2. Poczytaj https://pl.wikipedia.org/wiki/Kod_uzupełnień_do_dwóch W dokumentacji układu masz wyraźnie powiedziane, że w tym formacie są wyniki - więc np. 65339 to po prostu -197.
  3. Więc zostawiając własne opinie, a wracając do tematu wątku. @jare72 nie wiem jak dokładnie masz wszystko podłączone, ale zgaduję. Więc wiersze (ROWS) używasz do sterowania, natomiast stan klawiatury odczytujesz w kolumnach (COLS) - co jest dokładnie odwrotne od tego jak jestem przyzwyczajony, ale to bez znaczenia Na wejściach, czyli kolumnach masz włączone rezystory podciągające (PULL_UP), więc jeśli nic nie jest przyciśnięte, będzie tam stan wysoki. Wciśnięcie przycisku może zwierać do masy, co spowoduje pojawienie się stanu niskiego. Jak wcześniej @Gieneq zauważył, odczyt działał więc niepoprawnie: if(ekspander.digitalRead(COLS[y]) == HIGH) return KEYS[x][y]; Pierwsz zmiana to testowanie LOW, zamiast HIGH. Teraz trzeba zająć się wierszami. Ponieważ na wejściu masz pull-upy więc przyciskając klawisze użytkownik powinien zwierać odpowiednią linię do masy. Aktualna kolumna powinna być więc wybierana stanem niskim, a nie wysokim. Więc kod powinien być mniej więcej taki: char readKey() { for(int x = 0; x < NUM_ROWS; x++) { ekspander.digitalWrite(ROWS[x], LOW); for(int y = 0; y < NUM_COLS; y++) { if(ekspander.digitalRead(COLS[y]) == LOW) return KEYS[x][y]; } ekspander.digitalWrite(ROWS[x], HIGH); Na początku programu powinieneś też wystawić stany wysokie na wszystkich wyjściach. Nie wiem jak wygląda schemat elektryczny, ale powinieneś uważać na możliwe zwarcia na pinach. Podczas skanowania, na jednej kolumnie jest wymuszany stan niski, a na pozostałych wysoki. Więc naciśnięcie dwóch przycisków jednocześnie może spowodować zwracie... Możesz to obejść sprzęowo dodając diody lub rezystory, albo programowo. W skrócie - zamiast zapisywać stanu wysokiego do kolumn lepiej przełączać piny w stan wysokiej impedancji (czyli wejście, najlepiej z pullup-em). Wtedy ewentualne przyciśnięcie dwóch klawiszy nic złego nie zrobi. Ale to moim zdaniem zadanie na kolejny etap - zacznij od uruchomienia tego co masz, tylko nie wciskaj dwóch klawiszy jednocześnie Edit: pomyliłem kolumny z wierszami na końcu komentarza. przyzwyczajenie to jednak druga natura
  4. Przepraszam, że się wtrącam - ale moim zdaniem używanie ekspandera to nic złego. Oczywiście ma swoje wady: po pierwsze jest drogie, po drugie powolne. Wydaje mi się jednak, że w przypadku konstrukcji amatorskiej, to nie przekreśla stosowania ekspandera. Pierwszy argument, czyli cena nie ma znaczenia jeśli budujemy jeden egzemplarz. Nawet jeśli jeden układ kosztuje 1zł, a drugi 5, to i tak koszty przesyłki będą wyższe. A gdyby nadal była różnica, to czas spędzony przy zabawie tymi układami ma i tak większą wartość niż wszystkie elementy razem wzięte (doliczając złocenie wyprowadzeń). Natomiast jak chodzi o czasy działania, to wszystko zależy jak często potrzebujemy wykonywać skanowanie klawiatury. Tak teoretycznie licząc: zapis do ekspandera to 3-4 bajty (adres urządzenia, numer rejestru, 1-2 danych). Niektóre wymagają mniej, ale liczmy dla 4 bajtów. Dla każdej kolumny musimy wykonać zapis - załóżmy że klawiatura ma 4 kolmny - mnożąc przez 4 mamy 16 bajtów. Po każdym zapisie dajemy odczyt wartości - i i wychodzi wszystkiego razem 32 bajty, czyli 256bitów. Dojdą jeszcze bity startów, stopów, potwierdzeń - żeby w pamięci łatwiej liczyć, niech będzie 500 bitów. I2C powinno poradzić sobie co najmniej z 100kHz, więc skanowajmie zajmie jakieś 5ms. To z jednej strony wieki - ale jeśli takie skanowanie wykonamy co 100ms to będziemy mieli działającą klawiaturę oraz zużycie CPU na poziomie 5%. Tak jak napisałem wcześniej - w pełni się zgodzę, że inne rozwiązania są szybsze, tańsze, lepiej dopasowane do produkcji seryjnej. Ale moim zdaniem w tym konkretnym przypadku można spokojnie dodać ekspander, albo dwa i mieć prosty projekt, który pozwoli jego autorowi uczyć się dalej programowania. Edit: w pierwszej wersji pomyliłem się o rząd wielkości, wyszło mi 0.5%, poprawiłem na 5%.
  5. Moim zdaniem warto przetestować jak zachowa się program i czujnik przy maksymalnych wartościach - ale nie musisz się nimi szczególnie przejmować. Jak będziesz znał zakres, który Cię interesuje wystarczy wpisać go do funkcji map(), ale przed jej użyciem wywołać funkcję constrain() https://www.arduino.cc/reference/en/language/functions/math/constrain/ Wtedy wszystko powinno działać jak należy
  6. Nie musisz testować wszystkich możliwych kolorów - potrzebujesz tak naprawdę 6 liczb, czyli minimalnej i maksymalnej wartości, która jest zwracana przez pulseIn() dla trzech kolorów w używanym przez Ciebie otoczeniu. Później możesz te wartości wstawić do map(). Musisz tylko doczytać jak działa ta funkcja: https://www.arduino.cc/reference/en/language/functions/math/map/ Wykonuje ona proste skalowanie, czyli: long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } Więc jeśli wartość x, czyli wejście jest poza zakresem in_min - in_max, to i wynik jest poza zakresem out_min i out_max. Będziesz musiał więc odczytany wynik ograniczyć jeśli wyszedł poza zakres, albo jeszcze lepiej - ograniczyć wartość danej wejściowej, czyli x.
  7. @startrek1p2p Ja też nie wiem jakie wartości będziesz odczytywał - dlatego napisałem żebyś na razie zrezygnował z funkcji map() i przetestował jaki jest zakres wartości. Bo map() przelicza zakresy, czyli jak miałeś: frequency = map(frequency, 25,72,255,0); to zakres 25-72 był przeliczany na 255-0. Jeśli dostałeś wartość spoza zakresu 25-72, to i wyniki wyszły poza 0-255. Stąd takie dziwne wartości. Moim zdaniem powinieneś zacząć od ustalenia jakie wartości dostajesz dla R, G i B - zaczynając od całkiem zasłoniętego czujnika, a kończąc na oświetlonym białym światłem. Co więcej warto sprawdzić, czy czujnik odpowiednio reaguje na kolory - tak żeby się upewnić że wszystko działa. Nie musisz mieć do tego oscyloskopu, wystarczy trochę się pobawić i poobserwować wyniki. Jeśli umieścisz czerwony obiekt - wartości dla czerwonego powinny maleć itd. Dopiero wiedząc jakie otrzymujesz "gołe" wyniki możesz dodać funkcję map() i przeskalować odczytane wartości na oczekiwany zakres. Musisz jednak pamiętać, że map może zwracać też wartości spoza oczekiwanego przedziału. I jeszcze jedno - zmień typ zmiennych R,G,B z powrotem na int. Teraz jest dużo gorzej niż było.
  8. @startrek1p2p wyłącz na chwilę wywołania funkcji map(), będzie można wtedy zobaczyć jak wyglądają same odczyty z czujnika. Wygląda na to że, twój czujnik zwraca wartości z innego przedziału niż zakładasz - zacznij więc od sprawdzenia, jakie są to wartości i czy zmieniają się zgodnie z oczekiwaniami.
  9. Dla mikrokontrolerów są biblioteki np. od ST: https://www.st.com/en/embedded-software/x-cube-ai.html Cały trening sieci wykonuje się "jak zwykle" za pomocą narzędzi opartych o Pythona, ale nauczoną sieć można skonwertować na zminimalizowaną postać dopasowaną do mikorokontrolera, którą obsługują biblioteki napisane w C.
  10. Powiedziałbym bardziej że widziałem przykłady użycia sieci neuronowych na STM32 podczas szkolenia. Były to faktycznie małe sieci, ale stm całkiem sprawnie sobie radził. Moim zdaniem w przypadku mikrokontrolerów mogłoby być ciekawe użycie sieci neuronowych do wstępnego przetwarzania mniejszych zbiorów danych niż w przypadku obrazu - np. analizować dane z akcelerometru, czy żyroskopu. Z ciekawostek - w sieci są przykłady używania ML do nauki "chodzenia" przez roboty. Planowałem więcej się tym pobawić, ale jak zwykle - brakuje czasu
  11. Można mieć komercyjne produkty w pełni amatorskie - jako przykład weźmy chociażby zestawy AVT. Nie wszystko za co ktoś płaci jest profesjonalne - i odwrotnie, wiele produktów typu open-source, open-hardware itd jest darmowych, a często w wiele lepszej jakości niż niejeden płatny projekt. Na AVR można opracować w pełni profesjonalny projekt, a na ARM mieć zupełnie skopaną amatorszczyznę - więc nie ma sensu porównywać architektur i rozwiązań, podbudowywać własne ego dopiero co poznanym mikrokontrolerem. To co zaproponował p. Kardaś o ile wiem jest rozwiązaniem skierownym do amatorów, osób które chcą się nauczyć programowania, poznać podstawy elektroniki. I chyba jest to dobry wyrób skoro wiele osób go kupuje i sobie to chwali - jak to się mówi, zagłosowali portfelami
  12. Panie Skrzyński, to bardzo nieładnie czepiać się tego co robi ktoś inny, szczególnie jeśli wymienia się go z nazwiska. Rozumiem że ma pan ogromny żal i przemawia przez pana ogromna zawiść, że prace p. Kardasia, które nie tylko są przez wiele osób lubiane, ale jeszcze wspierane znacznymi kwotami. Jednak to forum nie jest miejscem na terapię i leczenie kompleksów - prosiłbym o unikanie takiej krytyki. Oczywiście można napisać że nie powinno się używać układów poza zakresami wskazanymi przez producenta, ale pamiętajmy, że zarówno konstrukcje pojawiające się na tym forum, kursy p. Kardasia, jak i artykuły w EP, czy EdW to wszystko amatorskie i hobbistyczne zastosowania.
  13. wszystko zależy do czego i gdzie te tranzystory były dodawane. Używanie wyjścia w trybie open-collector (albo raczej open-drain) nie zawsze jest idalnym rozwiązaniem. Dodatkowe tranzystory czasem bardzo się przydają, np. kiedy potrzebne są nieco większe prądy, albo odporność na zakłócenia. Co więcej czasy przełączania dla OC są znacznie niższe niż w trybie push-pull, a zewnętrzny tranzystor dużo lepiej zadziała z małym rezystorem podciągającym - więc moim zdaniem trzeba dobierać rozwiązanie do problemu, a nie teoretyzować. Tym bardziej że w większości przypadków sterowanie napięciem 3.3V w zupełności wystarczy nawet dla wejść w logice 5V.
  14. Jak najbardziej może być tam 5V. Bazując na standardowej technice wytwarzania układów półprzewodnikowych można umieścić więcej niż jedno złącze pn i wtedy 5V nie stanowi problemu. Co więcej można odpowiednio domieszkując można uzyskać złącze zenera, co chyba nawet lepiej pasuje w takim przypadku - w każdym razie schemat z diodą to tylko model i ogromne uproszczenie.
  15. @atMegaTona stm32 i wiele innych mikrokontrolerów jest wyposażone w wyprowadzenia "tolerujące" napięcie wyższe niż zasilania samego układu - czyli powiedzmy tolerujące 5V, gdy układ jest zasilany z 3.3V. Rysunki z diodami zabezpieczającymi są oczywiście uproszczeniem, a jak faktycznie dane zabezpieczenie jest rozwiązanie to już zupełnie inna sprawa. W każdym razie w przypadku wielu wyprowadzeń stm32 podawanie 5V nie stanowi problemu - a ustawienie pinu w tryb wejścia, albo wyjścia open-colector z rezystorem podciągającym to żadna tajemnica ani czarna magia.
  16. Darmowe statystyki popularności języków są dostępne w sieci i co więcej są za darmo. Język C++ jest używany w wielu projektach opartych o uC. Zarówno kilku poprzenich projektach, jak i w mojej aktualnej pracy C++ jest wykorzystywany do pisania aplikacji działającej bez systemu operacyjnego (albo raczej używającej jedynie RTOS-a) i jakoś nikomu to nie przeszkadza. Co ciekawe akurat po linuxem pracuję więcej w czystym C, sam system też w tym języku jest napisany - więc argumenty o C++ dla linuxa, a czystym C dla uC to absolutna bzdura - chociaż nie pierwsza wygłaszana przez tego użytkownika. Jak chodzi o naukę, to zarówno C, jak i C++ są dobrymi kandydatami - chociaż ostatnio modne są zupełnie inne języki, więc można również pomyśleć o micropythonie, albo Rust. @Wloczykij555 Skoro kupiłeś zestaw z STM32, to może zacznij od kursu stm32? Jak czegoś nie będziesz wiedzał, czy rozumiał zawsze możesz zapytać na forum, na pewno pomożemy. Arduino to fajna opcja, ale skoro masz już sprzęt to bez sensu kupować kolejny - zacznij, zobacz jak Ci się będzie tym bawiło, zawsze można, a nawet należy później kupić coś kolejnego. A czy to będzie Arduino, Raspberry Pi, czy zupełnie coś innego - to się okaże
  17. C++ jest jak najbardziej używany w świecie mikrokontrolerów. Więc argument o 90% softu w C można spokojnie między bajki włożyć - no chyba że @RFM przytoczy jakieś sprawdzone statystyki, a nie tylko własne opinie. Zarówno w "świecie" Linuxa, jak i programowania mikrokontrolerów bez systemu operacyjnego jest miejsce zarówno dla języka C, jak i C++.
  18. Trochę się zastanawiałem nad tym błędem i wartością rejestru SP - bo przeglądając plik startup_stm32f103c8tx.s wszystko wygląda poprawnie (nie licząc złej wartości _estack). Wydaje mi się, że przyczyną problemów była nieco nietypowa konfiguracja. Ja najczęściej w przypadku bluepill używam bootloadera oraz programowania przez usb. Tym razem, żeby uzyskać ten sam efekt co opisywany w wątku podłączyłem st-link z interfejsem SWD (właściwie to podłączyłem stlink z płytki nucleo). W każdym razie sam bluepill nadal uruchamiał bootloader, a dopiero później przez SWD wgrywany i uruchamiany był "właściwy" program. Normalnie po włączeniu zasilania pierwsze słowo z kodu programu jest ładowane do rejestru SP. Tam znajduje się wartość _estack i wszystko powinno działać. Ale jeśli zamiast programu uruchamiany jest bootloader to oczywiście rejestr SP jest kontrolerowany przez kod bootloadera. W kolejnym kroku debugger przejmuje kontrolę i uruchamia główny program. Jednak procedura jego uruchomienia nie jest identyczna z "prawdziwym" resetem. Rejestr SP powinien być więc ustawiony przez debugger, ale ktoś tego nie przewidział w skryptach dołączonych do CubeIDE... i w efekcie program startuje z wartością SP z bootloadera. To by również tłymaczyło wpływ grzebania przy liniach BOOTx na działanie programu. Jako ciekawostkę można spróbować skompilować oryginalny program, wgrać do flasha i wystartować bez bootloadera i debuggera. Jeśli to zadziała, to będzie potwierdzenie mojej teorii...
  19. Faktycznie, kod źródłowy sporo pomaga. Problem okazał się dużo ciekawszy niż w pierwszej chwili wyglądało, więc w końcu odnalazłem zakurzone blue pill, podłączyłem programator i postanowiłem sprawdzić o co w tym chodzi. Najpierw wersja skrócona - lepiej na razie nie używać CubeIDE... to nowe środowisko, powiedziałbym że wersja beta. Więc jest w nim dużo więcej błędów niż w starych i sprawdzonych. A teraz pełna wersja: Na początek faktycznie - błąd się pojawia, występuje w dość przypadkowych momentach, nie ma najmniejszego sensu... Chociażby podczas inicjalizacji DMA, HardFault jest wynikiem dereferencji wskaźnika NULL, który pojawia się magicznie. Więc typowe debugowanie niewiele daje oraz wskazuje na problemy ze stosem. I tutaj niestety musimy zejść do poziomu samego procesora. Po uruchomieniu mamy: Jak widzimy po prawej stronie wskaźnik stosu, czyli rejestr sp ma wartość 0x200001fc, czyli od początku pamięci SRAM dzieli go 0x1fc = 508 bajtów. To za mało na skomplikowany program działający na liczbach zmiennopozycyjnych. Teoretycznie wielkość stosu ustawiamy w pliku linkera, czyli STM32F103C8TX_FLASH.ld: Tutaj znajdziemy dwie ważne wartości. _estack to adres "końca" stosu, czyli najwyższego adresu zajmowanego przez stos. Widzimy tutaj pierwszy błąd, bo adresy powinny być podzielne przez 4, a często i przez 8. W każdym razie powinniśmy zmienić deklarację na: /* Highest address of the user mode stack */ _estack = 0x20005000; /* end of "RAM" Ram type memory */ Teraz to czego szukamy, czyli wielkość stosu: _Min_Stack_Size = 0x400 ; /* required amount of stack */ Domyślna wartość 0x400 oznacza 1024 bajty. Mikrokontroler STM32F103C8 ma 20 KiB pamięci SRAM, więc nie musimy być aż tak oszczędni - można ustawić stos na nieco większy. Okazuje się jednak, że zmiana _Min_Stack_Size nie wpływa na wartość rejestru SP, czyli faktyczny wskaźnik stosu... Mamy 508 bajtów bo coś się komuś pozajączkowało. Nie jestem pewien, czy to najlepsze rozwiązanie, ale można poprawić problem zmieniając plik startup_stm32f103c8tx.s, który znajdziemy w katalogu Startup. Teoretycznie rdzeń Cortex-M3 ustawia wartość rejestru SP podczas uruchamiania programu - ale to jak widać nie działa poprawnie. Możliwe że wynika to ze sposobu działania debuggera i po wgraniu do pamięci flash byłoby poprawnie, ale możemy zastosować "obejście" i sami ten rejestr ustawić. Do wspomnianego pliku wystarczy dodać jedną instrukcję: ldr sp, =_estack Program wygląda wówczas tak: I u mnie działa...
  20. @astex a potrafisz wysyłać i odbierać komunikaty tekstowe? Bo jeśli tak, to skonwertuj wynik z czujnika na napis i wyślij. Po pierwsze łatwiej to testować, bo na początek możesz po prostu wyświetlać co dostajesz, bez przetwarzania. Możesz też testować serwer niezależnie wysyłając mu napisy z dowolnego terminala. A jak już opanujesz wysyłanie gołych tekstów to poczytaj o formacie JSON, będziesz miał wtedy piękną możliwość przesyłania nawet całkiem skomplikowanych danych, czy wyników.
  21. Nie sądzę żeby zmiana BOOT1 na 1 była choćby odrobinę dobrym rozwiązaniem. To nawet ciekawe na czym polega problem, jeśli umieścisz gdzieś kompletny projekt może będzie łatwiej poszukać przyczyny problemu. Bo zarówno DMA, jak i BOOT1 to raczej leczenie objawowe.
  22. A sprawdziłeś czy nie masz przepełnienia stosu?
  23. CPU i DMA konkurują o dostęp do pamięci - dokładniej DMA co jakiś czasu zapisuje do pamięci wyniki z przetwornika A/C. Ale skoro w programie masz: sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; to ten zapis nie następuje zbyt często. Mawet nie wnikając czy ADC jest taktowane wolniej niż CPU, na jeden zapis przez DMA masz setki cykli CPU. Wiec teoretycznie program działa wolniej, ale pewnie nikt tego nie zauważy. Natomiast w programie masz pewnie inny błąd, który daje podobne efekty. Ciężko jest tak "zdalnie" zdiagnozować przyczynę problemów, ale z tego co przychodzi mi do głowy: 1) jesli wyłączysz ADC to funkcje arytmetyczne działają na stałych danych, może coś się psuje jak pojawią się określone wartości - coś gdzieś dzieli przez zero, liczy tangens z pi-pół itd. 2) może po wyłączeniu DMA optymalizator usuwa jakieś fragmenty kodu i całość działa względnie poprawnie 3) na zrzucie ekranu, który wstawiałeś wcześniej program zatrzymywał się w procedurze obsługi przerwania. Może problem nie wynika z samego DMA, ale złego sposobu obsługi przerwania od DMA? np. nie jest zerowana jakaś flaga i przerwanie wywoływane jest "w pętli", co faktycznie może uniemożliwiać działanie programu? To tylko pomysły, bo jak napisałem ciężko jest diagnozować przyczynę problemu na odległość. W każdym razie DMA nie ma prawa zatrzymać programu, może go spowolnić, ale nie zatrzymać całkiem.
  24. DMA nie zawiesza wykonywania obliczeń, ale w pewnych warunkach może mieć wpływ na czas działania procesora oraz wykonywanie programu. O ile sam mechanizm działa niezależnie od CPU, to w przypadku dostępu do tego samego modułu jak np. pamięci RAM możliwe jest spowolnienie działania procesora. Oba moduły master, czyli w tym wypadku CPU oraz DMA konkurują o dostęp do jednego układu podrzędnego (slave). Oznacza to, że gdy np. DMA zapisuje wyniki, CPU musi poczekać. Jednak to oczekiwanie to raptem jeden, a maksymalnie kilka cykli magistrali AHB. Co więcej spowalniane są tylko dostępy do pamięci, a procesor większość operacji np. arytmetycznych i tak wykonuje na rejestrach. W przypadku ADC problem jest jeszcze mniejszy - DMA zapisuje wyniki dopiero po zakończeniu konwersji A/C. Więc "zatrzymanie" CPU następuje bardzo, bardzo rzadko. Moim zdaniem problem wynika z zupełnie innej przyczyny, natomiast wpływ DMA jest raczej pomijalny. Nie ma natomiast możliwości, że DMA zupełnie zablokuje działanie CPU. Program nawet w najgorszym przypadku będzie wykonywany, chociaż z nieco mniejszą prędkością - niestety nie ma nic za darmo.
  25. @RFM czyli uważasz że nie można spalić wyjścia mikroprocesora / tranzystora MOS zwierając wyjście do masy i wystawiając stan wysoki?
×
×
  • Utwórz nowe...