Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'stm32'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino i ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - roboty
    • Projekty - DIY
    • Projekty - DIY (początkujący)
    • Projekty - w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Zawody/Konkursy/Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie
    • Kosz

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Znaleziono 100 wyników

  1. Witajcie. Ostatnio sobie pomyślałem, że co nieco w arduino się bawiłem, całkiem spoko, nie zrobiłem może jakiś dużych projektów, ale myślałem, że chciałbym coś bardziej zaawansowanego, trochę trudniejszego. Z racji, że rpi odpada ze względu na m.i.n cenę,(rpi wolę kupić dopiero za rok), FPGA zbyt mało związane z programowaniem, to pomyślałem o rodzinie STM32. Zatem, mam pytanie, jaki typ STM32 wybrać. F1, F4, a może jest jakiś inny dobry rodzaj? Chodzi mi o coś poniżej 65zł(może być wyjątek), dobre dla początkującego, ale też lepsze niż arduino. Z góry dziękuję za odpowiedzi. Co do wymagań płytki to minimum jedno i2c(najlepiej więcej), oraz piny z pwm i obsługa najlpopularniejszych magistrali i2c spi i tak dalej.
  2. Czesc, udalo mi sie ostatnio napisac na blue pillu prosty voice recorder, ale przy odtwarzaniu nagrania slyszalem mase stukow (mimo to glos jest calkiem rozpoznawalny). Myslalem ze to moze byc problem z zasilaniem czy cos, ale zrzucilem sobie nagranie na program ala audacity i podejrzenie o stuki padlo na SPI. Jezeli chodzi o kod to uzywam ADC z czestotliwoscia 16kHz i wypelniam bufor o rozmiarze 512. Jak bufor jest pelny robie zapis do karty SD za pomoca biblioteki FATFS( ktorej nie jestem pewien czy uzywam poprawnie), wszystko wygenerowane w CUBEMX i zbudowane na plytce stykowej. x = ~32ms ; y = ~64ms | 512/16kHz = 0.032 s = 32 ms Nagrałem dzwiek fali sinus z glosnikow i zauwazylem ze te zaklocenia troche oddaja to co sie dzieje u mnie w kodzie, tam gdzie jest 1 na SS wyglada na to ze to jest moment gdy robie f_write do SD, a tam gdzie jest 2, dzieje sie znow f_write z kolejnym pelnym buforem + f_sync, ktory jak rozumiem robi flush danych (danych zapisanych wczesniej za pomoca f_write() ) do karty. I teraz pytanko o FATFS. Z tego co probowalem wyczytac z dokumentacji (http://elm-chan.org/fsw/ff/doc/write.html), for i wydebugowac, ta biblioteka tworzy w RAM mcu takie wirtualne odzwierciedlenie tego co jest w pliku na karcie SD w postaci struktury FILE, i teraz jak robie f_write(bufor), to to sie nie przeklada na fizyczny zapis danych do karty za pomoca SPI, tylko na przeniesienie mojego bufora do bufora struktury FILE (czyli kopia z RAM do RAM), a fizyczny zapis do SD nastepuje dopiero po wywolaniu funkcji f_sync(). Wtedy to co jest w FILE.data[] leci po SPI do karty. Dobrze to rozumiem? Czy moze f_sync() uzywac co 10 albo 100 zapis zamiast co 2? Z analizy obrazka z drugiej strony by wynikalo ze jezeli to zeczywiscie SPI tam tak miesza, to f_write() jednak dokonuje zapisu po SPI do karty SD, tylko wtedy nie rozumiem czemu w 2 dzieje sie taki meksyk, f_sync() nie powinno miec nic do wypchniecia i zaklocenia nie powinny tam trwac dwa razy to co sie dzieje w 1. Ostatecznie pytanko, czy da sie te zaklocenia ogolnie jakos wyeliminowac sprzetowo? Piąteczka
  3. Witam. Realizuje kurs: https://forbot.pl/blog/kurs-stm32-f4-5-pomiar-napiecia-adc-dma-stmstudio-id13099 Pomiar temperatury przez ADC bez przerwania działa super. W momencie jak dołożyłem przerwania uC wykonuje raz tą operacje i wchodzi do obsługi przerwania. Inaczej mówiąc dokonuje pomiaru tylko raz, klikając reset dokonuje go znowu nie robi tego cyklicznie sam. Z czego wynika problem? Kod programu /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ ADC_HandleTypeDef hadc1; /* USER CODE BEGIN PV */ uint16_t PomiarADC; float Temperature; float Vsense; const float V25 = 0.76; // [Volts] const float Avg_slope = 0.0025; //[Volts/degree] const float SupplyVoltage = 3.0; // [Volts] const float ADCResolution = 4095.0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_ADC1_Init(void); /* USER CODE BEGIN PFP */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { PomiarADC = HAL_ADC_GetValue(&hadc1); Vsense = (SupplyVoltage * PomiarADC) / ADCResolution; Temperature = ((Vsense - V25) / Avg_slope) + 25; } /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_ADC1_Init(); /* USER CODE BEGIN 2 */ HAL_ADC_Start_IT(&hadc1); //HAL_ADC_Start(&hadc1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { // if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK){ // PomiarADC = HAL_ADC_GetValue(&hadc1); // Vsense = (SupplyVoltage * PomiarADC)/ADCResolution; // Temperature = ((Vsense-V25)/Avg_slope)+25; // // HAL_ADC_Start(&hadc1); // } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } /** * @brief ADC1 Initialization Function * @param None * @retval None */ static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DMAContinuousRequests = DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ Ustawienia z CubeMX
  4. Czesc, Od kilku tygodni probuje napisac na stm32f103 rejestrator glosu z zapisem na karte SD. Chce do tego uzyc ADC z triggerem od TIM3, zeby probkowac z odpowiednia czestotliwoscia, i DMA(potrzebuje sie tego nauczyc pod katem obslugi kamerki CMOS). Brudna robote z generowaniem kodu wykonal za mnie Cube IDE. Poza tym stworzylem dwa bufory na dane, tak zeby nimi zonglowac pomiedzy ADC i DMA uint8_t buf[2][BUFF_SIZE]; uint8_t buf[2][BUFF_SIZE]; Teraz w main odpalam DMA razem z ADC i mowie gdzie maja wszystkie dane ladowac i ile tego ma tam byc ( tam wyzej BUFF_SIZE ma 512 byte) HAL_ADC_Start_DMA(&hadc1, (uint8_t*)buf, 1024); Teraz mam 3 callbacki, ktore sprawdzam debugerem i tutaj dzieje sie cos czego nie rozumiem. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){ void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc){ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ Tutaj jeszcze musze powiedziec, poza pierwszym timerem TIM3, ktory uzywam do odpalanie konwersji ADC, uzywam tez osobnego TIM4 do sprawdzania ile mam zrobionych konwersji dla danego okresu czasu. Ustawilem TIM3 na 8khz i TIM4 na 100hz, co przy przepelnieniu TIM4 powinno dac (albo moze chcialbym zeby dalo) 80 konwersji ADC, czyli 80 wartosci w buf[0], ale tak niestety nie jest. Przy ustawieniu breakpoint na HAL_ADC_ConvCpltCallback i zlapaniu tam programu drugi raz mam juz zapelnione obie tablice buf[0] i buf[1], co mnie dziwi bo myslalem ze DMA bedzie czekac na kazda konwersje ADC i po kazdej z tych konwersji bedzie kopiowac pojedyncza wartosc do wskazanej tablicy. Czy jest cos zle w tym co pokazalem, czy moze seria F1 nie jest zdolna do tego co bym chcial? Widzialem w poradnikach do serii F4 dla ADC pole DMA Continuous Requests, dla F1 tego niestety nie widze i zastanawia mnie czy to nie jest ten moj brakujacy puzzel. Zalaczam screeny z konfiguracja cubemx. Pozdrawiam
  5. W trakcie budowy ostatniego robota zdałem sobie sprawę jak bardzo przydałoby mi się coś, co pozwalałoby wizualizować to co dzieje się w robocie w trakcie jego testowania. Ze względu, że mój robot Micromouse (którego budowę opisałem tutaj: Micromouse Robot - robot typu micromouse) wyposażony był w wyświetlacz LCD oraz moduł Bluetooth to był to idealny powód aby ich użyć. W taki sposób zrodził się pomysł na drugi projekt, który nazwałem "Robot Wizualizer - wizualizacja robota Micromouse". Projekt składa się z 2 części: Wyświetlacz LCD - na wyświetlaczu chciałem ukazać aktualne parametry robota takie jak: ustawiona prędkość na silnikach, pozycja w labiryncie i odczyty z czujników. Dodatkowo chciałem aby wyświetlacz wizualizował labirynt, który poznaje i przeszukuje robot. Wizualizacja komputerowa z środowiskiem ROS i RViZ - na podstawie danych przesyłanych przez robota do komputera miała powstać 3-wymiarowa wizualizacja labiryntu wraz z aktualnym położeniem robota. WYŚWIETLACZ LCD Ze względu, że płytką którą użyłem przy konstrukcji robota było STM32F429I-DISC1 to użytym wyświetlaczem był QVGA TFT LCD wbudowany w płytkę. Schemat elektroniczny projektu wygląda następująco: Jak widać, jeśli chodzi o wyświetlacz LCD to jest on podpięty w płytce wewnętrznie, jedyne co należy zrobić to użyć odpowiednich pinów. Reszta zadania polegała na podpięciu modułu bluetooth (HC-06) oraz w moim przypadku użycia prostego stabilizatora L7805 aby zasilić płytkę 5V. Interfejsy, które wykorzystałem do obsługi wyświetlacza to: DMA2D z Color Mode ustawionym na RGB565 w celu komunikacji pomiędzy mikrokontrolerem a wyświetlaczem, LTDC z rozdzielczością ustawioną na 320x240 do obsługi wyświetlacza i SPI do jego konfiguracji. Wszystkie elementy skonfigurowałem w środowisku STM32CubeIDE. Biblioteką, którą użyłem do sterowania wyświetlaczem jest sterownik STM32F429I_DISCOVERY_LCD dostarczany przez ST, który działa na podstawie sterownika wyświetlacza ILI9341. Użycie powyższej biblioteki sprawia, że praca z wyświetlaczem LCD staje się prosta, gdyż do dyspozycji mamy wiele funkcji, którymi możemy obsługiwać wyświetlacz. Po wykonaniu inicjalizacji oraz włączeniu wyświetlacza: wyświetlacz obsługujemy funkcjami typu: Pierwsze z nich pozwalają na rysowanie prostych kształtów o wybranym kolorze, w tym przypadku białego prostokąta w pozycji 0,0 i wielkości 239x239. Natomiast drugi zestaw odpowiada za wybranie białego koloru czcionki i wyświetleniu napisu w zadanej pozycji (70,260) wyrównanego do lewej. Niestety nie udało mi się znaleźć dokumentacji, która opisywałaby wszystkie funkcje. Osobiście znalazłem przydatne dla siebie funkcje przeszukując plik nagłówkowy biblioteki i testując ich działanie. Ich nazwy są całkiem adekwatne do tego co robią, więc nie było to niemożliwe zadanie. Po przetestowaniu działania wyświetlacza przyszedł czas na zaplanowanie elementów graficznych, które zostaną przedstawione na wyświetlaczu. Ze względu, że nie jestem wyrafinowanym grafikiem to zdecydowałem się na schematyczne ukazanie pożądanych informacji: Kolejne pola labiryntu zostały oznaczone kwadratami a możliwe ścieżki pomiędzy nimi to po prostu linie łączące kolejne pola. Dodatkowo pole, w którym aktualnie znajduje się robot miało być zaznaczane innym kolorem. Po podziale wyświetlacza na równe części i zastosowaniu odrobiny matematyki udało mi się napisać następujące funkcje: Pierwsza z nich rysuje bezbarwne pole dla zadanego położenia robota, natomiast druga pole kolorowe. Położenie robota zdefiniowałem jako 2 współrzędne (x,y) gdzie kolejne wartości całkowite (0, 1, .., n-1; gdzie nxn to rozmiar labiryntu) wskazują na pola labiryntu. Układ współrzędnych umieszczony jest w lewym górnym rogu, więc jeśli z tego punktu robot zacznie swoją trasę i przemieści się dwa razy na wschód, a potem raz na południe to jego współrzędne będą wynosiły (2,1). Zastosowanie współczynnika wielkości (WSP_WIELKOSCI) pozwala wykorzystać moje funkcje rysujące dla labiryntu dowolnej wielkości - podczas zwiększania się wymiarów labiryntu, rysowane pola są mniejsze, jednak nadal mieszczą się na wyświetlaczu. Następnie zaimplementowałem funkcję rysującą istniejące połączenia dla danego pola, dzięki czemu robot wraz z przejeżdżaniem labiryntu może od razu wizualizować, które ścieżki odkrył: W tym przypadku elementy także są skalowane w zależności od wielkości labiryntu. W tym momencie zauważyłem, że kwadratowa plansza labiryntu wykorzystuje tylko część prostokątnego wyświetlacza i nadal pozostaje na nim wolne miejsce - dlatego postanowiłem je wykorzystać. Stworzyłem kolejne funkcje, tym razem działające na tekście, które wypisywały informacje o robocie (prędkość, pozycja, czujniki). Implementacja przykładowej z nich wygląda następująco: Jak widać cały czas posługuje się funkcjami, które przytoczyłem wcześniej i które zapewnia użyta biblioteka do wyświetlacza. Na końcu dodałem jeszcze ramkę aby oddzielić część wizualną labiryntu od reszty danych i o to efekt (zdjęcie 1: labirynt 4x4, zdjęcie 2: labirynt 16x16): WIZUALIZACJA RVIZ Ta sekcja będzie mocno programistyczna i składać się będzie z 3 głównych programów: robota, skryptu w Pythonie oraz programu w C++. Jeśli ktoś jest zainteresowany dokładniejszym zrozumieniem działania każdego z nich, to polecam w trakcie czytania śledzenia poniższego diagramu, na którym przedstawione zostały schematy blokowe właśnie tych programów oraz relacje między nimi: ROBOT - wysyłanie danych Drugą część projektu rozpocząłem od skonfigurowania interfejsu USART w celu komunikacji mikrokontrolera z modułem bluetooth. Na podstawie skonfigurowanego interfejsu napisałem funkcje przesyłające przez niego dane do modułu: Dodatkowo użyłem przerwania wywoływanego przez interfejs w przypadku otrzymania informacji. W ten sposób jeśli otrzymaną informacją była np. komenda stopu to robot mógł zareagować natychmiastowo, bez potrzeby kończenia aktualnie wykonywanej akcji. Kolejnym krokiem była instalacja środowiska ROS oraz RViZ na moim laptopie. Wszystko odbyło się przy pomocy instrukcji ze strony producenta: https://www.ros.org/. W pierwszej kolejności moją uwagę poświęciłem stworzeniu prostego modelu robota. Do tego celu potrzebna okazała się wiedza o budowie plików .urdf wykorzystywanych w środowisku. Po zebraniu wiedzy z kilku poradników powstał pierwszy model: PYTHON - przekonwertowanie i przekazanie danych Następnym krokiem było wyrysowanie wszystkich elementów graficznych na scenie. W tym celu pierwszym krokiem stało się odebranie danych od robota przez komputer. Aby spełnić to zadanie posłużyłem się językiem Python i biblioteką pybluez, która umożliwia komunikację przez bluetooth. Napisany skrypt, w pierwszej kolejności tworzy wydawcę (publishera), który pozwala przesyłać dane do oprogramowania ROS. Następnie pyta użytkownika o tryb pracy: manualny czy zdalny. Tryb manualny polega na ciągłym odczycie komend wpisanych przez użytkownika, natomiast tryb zdalny łączy się z modułem bluetooth i cyklicznie odczytuje otrzymane dane z modułu. Niezależnie od wybranego trybu skrypt przesyła otrzymane dane do środowiska ROS. Wycinki skryptu, które realizują powyższe zadania wyglądają następująco: C++ - odebranie i wykorzystanie danych Kolejnym ogniwem był program napisany w języku C++, który pozwalałby wizualizować otrzymane dane w programie RViZ. W związku z tym tworzy on subskrybenta (subscribera), który łączy się z publisherem wcześniej stworzonym w skrypcie tworząc węzeł komunikacyjny. Następnie program tworzy znaczniki (markery) umożliwiające wizualizację w RViZie. Postanowiłem użyć dwóch rodzajów markerów: linii do rysowania ścian labiryntu oraz sześcianu do reprezentowania robota. Końcowo program w pętli oczekuje na odbiór danych, jeśli to się stanie to następuje przerwanie i w zależności od rodzaju danych wykonywane są odpowiednie funkcje aktualizujące pozycję lub orientację modeli. Wycinek opisanych funkcji wygląda następująco: Końcowy efekt prezentuje się następująco (na zdjęciu widoczne użycie w trybie manualnym): PODSUMOWANIE Myślę, że projekt ten wyszedł całkiem nieźle, w szczególności, że była to moja pierwsza styczność z wyświetlaczem LCD oraz oprogramowaniem ROS. Spora jego część jest czysto programistyczna, jednak mam nadzieję, że i tak kogoś zaciekawił. Jeśli kogoś interesują szczegóły to zapraszam do repozytorium https://github.com/Wirgiliusz/Micromouse-Robot-Wizualizer, w którym można znaleźć wszystkie wspomniane przeze mnie pliki oraz projekt w STM32CubeIDE, który zawiera zarówno konfiguracje samego robota Micromouse jak i wyświetlacza LCD. Na koniec jeszcze filmik pokazujący działanie wszystkich elementów w czasie rzeczywistym:
  6. Od dłuższego czasu chciałem stworzyć działającego robota Micromouse, a jednocześnie chciałem nauczyć się obsługiwać inne mikrokontrolery niż Arduino. Idealna okazja spełnienia obu tych rzeczy nadeszła gdy wszedłem w posiadanie płytki STM32F429I-DISC1. Tak o to rozpocząłem projekt o zaskakującej nazwie "Micromouse Robot". KONSTRUKCJA ROBOTA Komponenty, które postanowiłem wykorzystać w robocie to: Mikrokontroler STM32F429I-DISC1 Czujniki odległości (odbiciowe) skonstruowane z pary: dioda IR SFH4550 i fototranzystor SFH-313FA Silniki DC FIT0450 wraz z enkoderami magnetycznymi SJ01 Sterownik silników L298N Moduł bluetooth HC-06 Koła DFRobot Na samym początku zaplanowałem ogólny schemat robota: Na podstawie schematu ogólnego stworzyłem schemat elektroniczny przy użyciu programu KiCad: Następnie przyszedł czas na zlutowanie potrzebnych układów, w pierwszej kolejności był to moduł z czujnikami - zdecydowałem się na prostopadłe rozstawienie czujników, dwie pary wykrywające przeszkody po bokach oraz dwie pary wykrywające ścianę na wprost dzięki czemu możliwe będzie wykorzystanie ich odczytów do korekcji orientacji robota (oba przednie czujniki powinny odczytywać tą samą odległość od ściany). Dodatkowo zlutowałem pomocniczy układ z przełącznikiem i stabilizatorem step-down (gdyż zasilanie, którego użyłem dochodziło do 8V przy pełnym naładowaniu, a płytka potrzebowała 5V). Dzięki niemu miałem łatwy dostęp do pinów 5V lub 8V w zależności od potrzeby: W celu sprawdzenia działania stworzonego modułu czujników wykonałem testy przy użyciu programu STMStudio, które pozwoliło na łatwą wizualizację odczytów mikrokontrolera. Przeprowadzone testy potwierdziły poprawne działanie każdego z 4 czujników (niższa wartość oznacza przewodzenie fototranzystora w diodzie odbiorczej, tym samym sygnalizując, odbiór światła wysłanego przez diodę IR i odbitego od białej ściany - w skrócie, wykrycie przeszkody przez dany czujnik): Niestety w tym momencie okazało się, że pomieszczenie wszystkich elementów wraz z utrzymaniem sensownych rozmiarów robota będzie niemożliwe, dlatego po wykonaniu wielu pomiarów powstał model 3D przyszłej konstrukcji, na którego podstawie stworzona została rzeczywista konstrukcja stworzona z wyciętej płyty ebonitowej oraz drucianych podpór: Jak widać dzięki wymyślnej konstrukcji udało się pomieścić wszystkie elementy. Nadszedł czas na programowanie. OPROGRAMOWANIE ROBOTA Ze względu, że użyta płytka należała do rodziny STM32 to do pomocy w programowaniu użyłem środowiska STM32CubeIDE. Ponieważ jak już pisałem, była to moja pierwsza styczność z płytką inną niż Arduino, to bardzo pomocny okazał się Kurs STM32 F4 ze strony Forbota. Końcowo wykorzystałem: 4 piny ADC w celu odczytywania wartości z czujników odległości, 2 piny PWM w trybie countera w celu odczytywania wartości z enkoderów silników, 4 piny PWM do sterowania silnikami, oraz 2 piny USART w celu komunikacji z modułem bluetooth. Schemat blokowy przyszłego programu robota wygląda następująco: W tym momencie głównym zadaniem stało się zaimplementowanie najważniejszych funkcji, czyli: przeszukania labiryntu, znalezienia najkrótszej ścieżki i jej przejechania. Również w tym przypadku Forbot nie zawiódł i poratował mnie artykułem Roboty MicroMouse – 5 metod przeszukiwania labiryntu. To właśnie on skłonił mnie do wykorzystania metody propagacji fali. Wzorując się na przykładach z artykułu udało mi się stworzyć własną wersję algorytmu. W międzyczasie stworzyłem funkcje odpowiedzialne za ruch robota w przestrzeni. Odpowiednie przechowywanie aktualnej pozycji (x, y) oraz orientacji robota (północ, południe, zachód, wschód) pozwoliło na proste zaimplementowanie funkcji typu jedz(kierunek), która pozwalała na nawigację po labiryncie jak gdybyśmy patrzyli na niego z góry i zadawali, w którym kierunku ma przemieścić się robot. Dzięki temu możliwe stało się stworzenie symulacji, która pozwalałaby na przetestowanie działania zaimplementowanego algorytmu i funkcji ruchu. Tak też zrobiłem: Jak widać funkcje ruchu pozwalają na przemieszczanie się po poszczególnych polach labiryntu, natomiast algorytm bez problemu znajduje najkrótszą ścieżkę do celu. Przyszedł czas na rzeczywiste testy. W tym celu używając wyciętych kartonów oraz białych kartek A4 złożyłem własny labirynt (na zdjęciu jeszcze bez kartek), niestety ze względu na ograniczoną przestrzeń składał się on tylko z 4x4 pól, jednak nie był to zbyt duży problem, gdyż algorytm zdołał już udowodnić symulacyjnie, że działa także dla pełnowymiarowego labiryntu. Kolejnym wyzwaniem było zaprogramowanie ruchu robota po labiryncie. Z pomocą przyszły enkodery silników oraz czujniki na podstawie których napisałem proste regulatory PD. Pierwszy z nich używając enkoderów gwarantuje, że dystans pokonany przez oba silniki jest stały, natomiast drugi używający czujników zapewnia równy odstęp robota od wszystkich ścian labiryntu. Ich połączenie zapewnia sprawne przemieszczanie się robota po kolejnych polach labiryntu. PODSUMOWANIE Ostatecznemu wynikowi daleko do idealnych. Robot jest dosyć powolny i czasami gubi trasę - myślę, że jest to spowodowane w pewnym stopni jego wagą i wielkością użytych silników, co w połączeniu skutkuje brakiem możliwości wykonywania małych i precyzyjnych ruchów. Dodatkowo brakuje tu wielu usprawnień funkcji ruchu, np. nie zatrzymywanie się na każdym polu jeśli jedziemy prosto kilka razy z rządu. Pomimo to myślę, że robot wcale nie wypada tak źle jak na pierwszy tak duży projekt, przecież jednak jeździ i ma się dobrze. Dodatkowo ilości nowej wiedzy którą zdobyłem podczas jego tworzenia nie da się zastąpić. Ogólnie jestem zadowolony z efektu oraz całego projektu, jednak także świadomy jego niedoskonałości i możliwości poprawy w miarę zdobycia nowej wiedzy. Efekt końcowy (przeszukiwanie labiryntu oraz przejazd najkrótszą ścieżką przyspieszone prawie 5-krotnie) można obejrzeć na filmiku:
  7. Witam. Programowałem trochę avr, ale przesiadałem się na stm32, avr programowałem w VS Code i lubię to środowisko. Moje pytanie to czy ktoś programuje stm32 w ty środowisku, albo umie je skonfigurować tak żeby można było budować i wgrywać program? Wiem że jest wtyczka do tego ale nie potrafię jej używać. Otwieram folder z projektem wygenerowanym z CubeMX i kiedy daje "buduj" to wychodzą błędu ze brakuje jakiegoś Patha, kiedy dodam wszystko i klikam "buduj" to kompletnie nic się nie dzieję. I jeszcze w programie podkreślone są linijki tak jakby nie wykrywało biblioteki. Ktoś potrafi pomoc, bo w internetach nic konkretnego nie znalazłem co by działało i było zrozumiałe.
  8. Płytki nowe, oryginalnie zapakowane, kupione do projektu na który nie miałem ostatecznie czasu. - Nucleo-32 STM32L412 (2sztuki) - 45zł/szt https://allegrolokalnie.pl/oferta/zestaw-rozwojowy-edukacyjny-nucleo-32-stm32l412 - Nucleo-144 STM32F439 (2 sztuki) - 120zl/szt https://allegrolokalnie.pl/oferta/zestaw-rozwojowy-edukacyjny-nucleo-144-stm32f439 - Raspberry Pi 3 model A+ (2 sztuki) - 105zł/szt https://allegrolokalnie.pl/oferta/raspberry-pi-3-model-a - Raspberry Pi 3 model B+ (3 sztuki)- 165zł/szt https://allegrolokalnie.pl/oferta/raspberry-pi-3-model-b-5zj Ceny do małej negocjacji. Wysyłka - paczkomat 12 zł lub kurier 15 zł/za pobraniem 20zł
  9. Jak szybko przygotować STM32F746G-DISCO do pracy. Do zainteresowanych dodam Video.STM32.pdf
  10. Hej, próbuję przerobić kurs STM32 F1 HAL i na samym początku pojawiły się problemy, a mianowicie od kilku dni próbuję zrobić zadanie 4.1, jednak wszystkie próby kończą się niepowodzeniem. Ma może ktoś zrobione to zadanie i chciałby się nim podzielić oraz sposobem jego rozwiązania? Poniżej mój kod. Z góry dziękuję! #include "stm32f1xx.h" int main(void) { SystemCoreClock = 8000000; // taktowanie 8Mhz HAL_Init(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitTypeDef gpio; // obiekt gpio będący konfiguracją portów GPIO gpio.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4| GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9; gpio.Mode = GPIO_MODE_IT_RISING; gpio.Pull = GPIO_PULLUP; // rezystory podciągające są wyłączone gpio.Speed = GPIO_SPEED_FREQ_LOW; // wystarczą nieskie częstotliwości przełączania HAL_GPIO_Init(GPIOC, &gpio); // inicjalizacja modułu GPIOC gpio.Pin = GPIO_PIN_13; // konfigurujemy pin 13 gpio.Mode = GPIO_MODE_INPUT; // jako wejście gpio.Pull = GPIO_PULLUP; // włączamy rezystor podciągający HAL_GPIO_Init(GPIOC, &gpio); // port GPIOC while (1) { if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) { uint32_t led = 0; HAL_GPIO_WritePin(GPIOC, 1 << led, GPIO_PIN_SET); //włącz diode HAL_Delay(150); HAL_GPIO_WritePin(GPIOC, 1 << led, GPIO_PIN_RESET); //wyłącz diode if (++led >= 10) { // przejdz do nastepnej led = 0; } else { uint32_t led = 10; HAL_GPIO_WritePin(GPIOC, 1 << led, GPIO_PIN_SET); //włącz diode HAL_Delay(150); HAL_GPIO_WritePin(GPIOC, 1 << led, GPIO_PIN_RESET); //wyłącz diode if (--led >= 10) { // przejdz do nastepnej led = 10; } } } } }
  11. Cześć, Zacząłem naukę programowania STM32 na podstawie kursu dla STM32F101 tylko używam STM32F303. Niestety pojawił się problem przy konfiguracji UART2. Poniżej załączam kod programu. /** ****************************************************************************** * @file main.c * @author Ac6 * @version V1.0 * @date 01-December-2013 * @brief Default main function. ****************************************************************************** */ #include <string.h> #include "stm32f3xx.h" UART_HandleTypeDef uart; void send_string(char* s) { HAL_UART_Transmit(&uart, (uint8_t*)s, strlen(s), 1000); } int main(void) { SystemCoreClock = 8000000; HAL_Init(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_USART2_CLK_ENABLE(); GPIO_InitTypeDef gpio; gpio.Pin = GPIO_PIN_2 | GPIO_PIN_3; gpio.Mode = GPIO_MODE_AF_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_HIGH; gpio.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &gpio); UART_HandleTypeDef uart; uart.Instance = USART2; uart.Init.BaudRate = 38400; uart.Init.WordLength = UART_WORDLENGTH_8B; uart.Init.Parity = UART_PARITY_NONE; uart.Init.StopBits = UART_STOPBITS_1; uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; uart.Init.OverSampling = UART_OVERSAMPLING_16; uart.Init.Mode = UART_MODE_TX_RX; HAL_UART_Init(&uart); while(1) { send_string("Hello World\r\n"); HAL_Delay(100); } } Czy ktoś mógłby wskazać gdzie zrobiłem błąd? Pozdrawiam.
  12. Cześć, Mam dziwny problem którego nie mogę rozwiązać od dłuższego czasu. Potrzebuje wysłać cyklicznie do raspberry PI 4 pakiet UDP z stm32(mam nucle f207zg oraz f767zi, na obu jest to samo). Używam lwip 2.x. Moja funkcja została przerobiona z przykładu UDPechoserver i jest wywoływana w cyklicznym przerwaniu wygląda tak: void UDPSendString(void) { struct udp_pcb *upcb; struct pbuf *p; upcb=udp_new(); /*assign destination IP address */ ip_addr_t ipDest; IP4_ADDR(&ipDest, 192, 168, 0, 4); char buf[bufSize]; int size; err_t err; if (upcb) { /* Bind the upcb to the UDP_PORT port */ /* Using IP_ADDR_ANY allow the upcb to be used by any local interface */ err = udp_bind(upcb, IP_ADDR_ANY, 0); if(err == ERR_OK) { size = snprintf(buf, bufSize, "B value=500\r\n"); p=pbuf_alloc(PBUF_TRANSPORT,size, PBUF_RAM); pbuf_take(p, buf, size); /* Connect to the remote client */ udp_connect(upcb, &ipDest, 8089); /* Tell the client that we have accepted it */ udp_send(upcb, p); /* free the UDP connection, so we can accept new clients */ udp_disconnect(upcb); } } // /* Free the p buffer */ pbuf_free(p); udp_remove(upcb); } Dziwne jest to, że jeżeli w adresie ip podam adres mojego PC na windows to w wiresharku widzę, że wszystko jest ok i pakiety są cyklicznie wysyłane. Natomiast gdy zmienię adres na raspberry to jakby nic nie było wysyłane. Idąc dalej... Za pomocą konsoli w raspberry jestem w stanie wysłać pakiet do pc a do stm już nie. Dziwne jest to, że wireshark nie widzi żadnych pakietów pomiędzy stm a raspberry. Nawet ping który jest wysyłany z raspberry do stm jest niewidoczny pomimo tego, że stm odpowiada. Dodam, że wszystkie urządzenia są podłączone do jednego switcha. Gdzie mogę szukać problemu? Będę wdzięczny za wszystkie sugestie.
  13. Siema, zbudowałem sobie takiego robota balansującego: i od miesiąca próbuję go zmusić do balansowania, a ten mnie nie słucha. MPU6050 -> filtr kalmana -> pid(na filmiku sam człon PD). Sterowanie wychyleniem wywoływane w w przerwaniu co ok 10 ms. I teraz moje pytanie : Czy kaszanię coś programowo, regulacyjnie, Czy skaszaniłem coś mechanicznie ? Tu podgląd z STMStudio ... robot.zip
  14. Jestem na lekcji 3 z kursu STM32 F1 HAL i próbując pobrać sterowniki z linku podanego w kursie na stronie producenta po kliknięciu w link z maila wyskakuje mi error 403. Miał może ktoś podobny problem? Z Góry dzięki za odpowiedź.
  15. Witam! To mój pierwszy wpis w dziale DIY. Projektem jest (a właściwie dopiero będzie) mini konsolka do gier na STM32F1. Robię ten projekt dla mojego 3-letniego synka. Docelowo będę mu wgrywać na nią różne napisane przeze mnie gry, ale na początek zacznę od klasyki, czyli gra w węża Robiłem już podobny projekt przy okazji kursu SMT32 na Forbocie, więc szybko powinienem napisać niezbędny kod. Tym razem ma to być gotowe urządzenie które bez problemu będzie mógł obsłużyć 3-latek. Założenia projektu: 1. Mikrokontroler STM32F1 2. Ekran TFT kolorowy 240x320 3. Zasilanie bateryjne LiPo z ładowaniem przez gniazdo USB (więcej szczegółów w moim wątku w dziale Zasilanie - szczególnie ostatni mój post) 4. Obudowa w całości drukowana w 3D 5. Żadnych gotowych modułów. Własny projekt PCB i własny montaż. 6. Klawiatura: Krzyżyk, przycisk A, przycisk B oraz przycisk POWER, jak w starych Game - Boy'ach 7. Dzwięk: Nad tym jeszcze nie myślałem, brak I2S oraz DACa na mojej płytce Nucleo trochę utrudnia sprawę. Może będzie coś na Timerach i PWM. Zobaczymy. Teraz po kolei. Pierwsze co musiałem zrobić to ogarnąć wyświetlanie na TFT. Zakupiłem trochę w ciemno kilka wyświetlaczy 2,8" na ILI9341. Mój brak doświadczenia z TFT natychmiast się zemścił. Po odbiorze przesyłki okazało się że obsługa SPI wcale nie jest oczywista i jestem skazany na 16-bitową magistralę. Nie znalazłem nigdzie driverów na STM32 do sterowania tym kontrolerem przy takim połączeniu, ale znalazłem kilka projektów na GitHub'ie gdzie było sterowanie przez magistralę 8-bitową. Postanowiłem więc na podstawie tych projektów napisać własne drivery i procedury wyświetlania podstawowych kształtów. W trakcie prac nad optymalizacją wyświetlania okazało się że jednak 16-bitowa magistrala to doskonały pomysł i jest 4-krotnie szybsza od 8-bitowej. Dlaczego? Już tłumaczę: Gdy używa się 8-bitowej szyny danych to wysłanie piksela wygląda następująco (już po ustawieniu adresu): - Ustawiamy pierwsze 8 bitów koloru - WR strobe - czyli szybka zmiana linii WR na 0 i powrót 1 - Ustawiamy kolejne 8 bitów koloru - WR strobe - czyli szybka zmiana linii WR na 0 i powrót 1 I powtarzamy do czasu wypełnienia zaadresowanego okienka. Czyli na każdy piksel przypadają 4 kroki. Gdy używamy 16-bitowej magistrali - wygląda to następująco: - Ustawiamy 16 bitów koloru - WR strobe - czyli szybka zmiana linii WR na 0 i powrót 1 I powtarzamy do czasu wypełnienia zaadresowanego okienka. Czyli na każdy piksel przypadają 2 kroki. Ale przecież pisałem że jest 4 razy szybciej, a tu wychodzi że 2 razy No więc łatwo można zauważyć, że przy 16 bitach raz ustawiony kolor na linii danych możemy zostawić do czasu aż będziemy musieli użyć innego koloru. Więc jeżeli mamy kilkaset pikseli do wypełnienia jednym kolorem to raz go ustawiamy, a później już tylko WR strobe tak długo jak potrzebujemy Czyli realnie wykonujemy tylko jeden krok. Zaimplementowałem to w moich driverach i rezultaty były doskonałe. Na tyle dobre że odpadła mi konieczność posiadania pamięci pod bufor klatki. Wszystko wyświetla się błyskawicznie: Aktualnie mogę wyświetlać do 8Mpix/s, co teoretycznie pozwala odświeżyć ekran 240x320 ponad 100 razy na sekundę na STM32F1 taktowanym 64MHz. Czyli mogę jeszcze podnieść tą częstotliwość do 72 MHz i jeszcze zwiększyć transfery. Niestety chwilowo mam odcięty programator od płytki Nucleo i muszę kożystać z wewnetrznego oscylatora który pozwala rozkręcić mikroprocesor do 64MHz. Kolejnym problemem z którym musiałem się zmierzyć to mała ilość flash na grafiki do gier. Jak łatwo policzyć jedna pełnoekranowa grafika to 153600 bajty, a mam tylko 128k do dyspozycji. A jeszcze musi się zmieścić program. Rozwiązaniem problemu jest kompresja. Tu znów musiałem od zera napisać program do kompresji grafiki który spełniałby moje wymagania. Kompresor został napisany w Pythonie. A szybki dekoder zaimplementowany w C w driverach na STM32. Pisałem program praktycznie od zera wg mojego pomysłu. Otóż dzieli on grafikę na bloki o jednolitych kolorach, a ich metadane zapisuje w binarnym pliku wyjściowym, albo w pliku C. Bloki są następujące: pozioma linia, pionowa linia, prostokąt. Pojedynczy piksel to pozioma linia o długości 1. Kompresja odbywa się przez rozkład grafiki na takie bloki, a następnie zapisaniu ich parametrów do pliku wyjściowego. Procedurę dekompresji zaimplementowałem w driverach do wyświetlacza, a każdy blok łatwo można wysłać bezpośrednio do pamięci ekranu, gdzie obraz zostaje odtworzony. Kolejną funkcją którą zaimplementowałem w kompresorze jest możliwość kodowania różnicy pomiędzy dwoma grafikami. Tzn jeżeli robię animację to program kompresuje tylko piksele które różnią dwie klatki. Poniżej proces odtwarzania obrazka na wyświetlaczu w zwolnionym tempie: Skoro miałem już ograne wyświetlanie grafiki, przyszedł czas na prototypowanie konsoli i pisanie samego kodu gry Aktualnie moje stanowisko pracy wygląda następująco: Sama gra jest na etapie tworzenia grafiki. Na razie mam animacje na intro: To tyle na dzisiaj. Wraz z postępami będę aktualizował ten wątek. Pozdrawiam, Marek
  16. Cześć, na początek chciałbym się przywitać. Nie pamiętam czy pisałem coś na forum, a jeżeli tak to musiało być bardzo dawno. Zaprojektowałem urządzenie serwera HTTP na bazie stm32f207 i DP83848 (PHY). Oprogramowanie wygenerowałem z użyciem najnowszego CubeMX oraz wersji biblioteki dla procesora stm32f207 v1.9. Wykorzystałem LWIP jako stos TCP/IP oraz FreeRtos-a jako system, komunikacja TCP za pomocą netconn. Wygenerowany szablon zmodyfikowałem na wzór dostarczonego przez ST. Utworzyłem wątek http_server_netconn_thread(), w którym oczekuję na informacje ze strony. Nic odkrywczego. Pierwsza linia to utworzenie nowego wątku a poniżej jest sam wątek. httpTaskHandle = sys_thread_new("HTTP", http_server_netconn_thread, NULL, 4095, osPriorityHigh); void http_server_netconn_thread(void *arg) { static struct netconn *TCPListener, *newconn; static err_t err, conn_check, deleteErr; TCPListener = netconn_new(NETCONN_TCP); if (TCPListener != NULL) { err = netconn_bind(TCPListener, IP_ADDR_ANY, PORT_60662); if (err == ERR_OK) { netconn_listen(TCPListener); while(1) { netconn_set_recvtimeout(TCPListener, TIME_DELAY_500_MS); conn_check = netconn_accept(TCPListener, &newconn); if(osOK == osTimerStart (timeOutHttpServerHandle, TIME_DELAY_60_SECONDS)) { timerHttpStatus = TIMER_RUN; } if(ERR_OK == conn_check) { http_server_serve(newconn); netconn_close(newconn); netconn_delete(newconn); } osTimerStop(timeOutHttpServerHandle); } } else { netconn_close(newconn); netconn_delete(newconn); } } } Funkcja http_server_serve(newconn)() sprawdza czy przyszło zapytanie http i na nie reaguje. Również nic odkrywczego. void http_server_serve(struct netconn *conn) { connCheck = netconn_recv(conn, &inbuf); if(connCheck == ERR_OK) { if (netconn_err(conn) == ERR_OK) { // pobranie danych do bufora netbuf_data(inbuf, (void**)&buf, &buflen); analiza_metody_GET(buf); analiza_metody_POST(buf); } } netconn_close(conn); netbuf_delete(inbuf); } Jeżeli przyszło zapytanie ze strony, program wysyła odpowiedź na to zapytanie. I mógłbym powiedzieć, że wszystko działa. Program działa dobrze do czasu gdy pracuje w sieci lokalnej. Problemy zaczęły się gdy udostępniłem stronę poza sieć lokalną. Szczególnie zauważalne to jest gdy chcę wyświetlić stronę na smartfonie poprzez sieć komórkową. Dane do przeglądarki przesyłam za pomocą funkcji netconn_write_partly(). netconnResult = netconn_write_partly(conn, buffer_send, len, NETCONN_NOCOPY, &written); Niestety po pewnym czasie program blokuje się na tej funkcji i pozostaje już tylko reset. Sytuacje taką zauważyłem przy przesyłaniu do przeglądarki pakietów danych o objętości 6,5 kB. Przy przesyłaniu pakietów o objętości poniżej 1kB takich problemów nie zauważyłem. Przeglądając internet znalazłem parę wątków o problemach z oprogramowaniem od ST. Niestety nie pomogły mi rozwiązać mojego problemu. Pytanie do osób przerabiających temat serwera www na stm32 czy przerabiały podobny problem lub czy istnieje możliwość włączenia dla tej funkcji timeout-u umożliwiającego jej opuszczenie i dalsze działanie urządzenia?
  17. Witam, Właśnie rusza projekt, który ma umożliwiać zdalne nauczanie zagadnień z mechatroniki i przetwarzania sygnałów. Idea jest taka, aby każdy uczeń/student miał w domu swoje własne stanowisko ze szkoły, sam rejestrował dane, a następnie, żeby nauczył się je przetwarzać w chmurze. Na chwilę obecną szukane są pomysły, np.: 1) użytkownik sam zbiera dane drganiowe z kilkudziesięciu cykli prania, a dostarczony generator dodaje sygnały powolnego uszkodzenia łożyska, generując zbiór Big Data. Następnie, użytkownik zgodnie z instrukcją opracowuje w chmurze algorytm Novelty Detection (np.sieć LSTM). 2) w zestawie jest obudowa łożyska, która jest elektromechanicznie wzbudzana z wykorzystaniem Arduino/Raspberry Pi. Drugi układ Arduino/Raspberry Pi rejestruje odpowiedź na wymuszenie. Następnie, estymowana funkcja odpowiedzi częstotliwościowej (FRF) jest wykorzystywana jako część stochastyczna sygnału syntetycznego rozwoju uszkodzenia łożyska tocznego. Na jej podstawie budowany jest zbiór Big Data, który bardzo wiernie odzwierciedla sygnały rzeczywiste. Dane są zbierane od wielu użytkowników i są użyte w procesie uczenia maszynowego w chmurze. 3) oczywiście, takie zestawy WYMUSZENIE/REJESTRACJA same w sobie pozwalają na analizę wpływu rodzaju wymuszenia na estymowaną FRF 4) Dalsze pomysły?! Pozdrawiam, Ajab00
  18. Cześć. Zdarza mi się popełnić jakiś układ, który wykonuję samodzielnie - trawienie, lutowanie, programowanie itp. Hobbystycznie - dla siebie, ewentualnie coś dla znajomych. Zwykle korzystam z uC AVR, ale ostatnio bawię się płytkami Nucleo od STM. Powoli myślę o przesiadce z THT na SMT. I tu pojawia się pytanie - w jaki sposób programować takie mikrokontrolery? Mam w domu jakieś przejściówki z QFP na DIP, ale to wymaga przylutowania, zaprogramowania, odlutowania i przylutowania na gotowej płytce. Trochę mnie taki proces przeraża. Chciałem zakupić taki adapter z klipsem, ale okazuje się, że to uzależnia mnie zarówno od danej wielkości układu (QFP48, QPT64 itd.), jak i rozstawu nóżek (np. 0.8 mm dla AVR i 0.5 mm dla STM32). Znalazłem też takie igły-sondy z wysuwanymi szczypcami do chwytania nóżek, ale czy to mi chwyci 0.5 mm bez zwierania sąsiednich nóżek??? Czy jest jakieś w miarę uniwersalne rozwiązanie, które pozwoli mi na programowanie układów SMD o różnym rastrze, a przynajmniej różnej liczbie nóżek? Takie dedykowane adaptery są dość drogie (ok. 60 zł zwykły i ok. 300 zł z wyprowadzeniami JTAG/SWD i USART) i nie chciałbym kupować kilku, by móc używać różnych uC. Czy pozostaje mi wlutowywanie na docelowej płytce pinów do programowania? Używając SMD chciałbym przede wszystkim uniknąć wiercenia w płytce i zająć jak najmniej miejsca na niej, a takie piny trochę mi się z tym kłócą. Jakie rozwiązanie polecacie dla mnie? I drugie - poboczne pytanie: jak najlepiej/najłatwiej programować gołe scalaki z STM32, jeśli posiadam programatory z płytek Nucleo-64 i Nucleo-144?
  19. Cześć, to już któryś wieczór, kiedy siedzę i próbuję zrozumieć dlaczego nie mogę połączyć się z magnetometrem MMC5983MA po SPI, więc postanowiłem się podzielić problemem. Na własnej płytce mam STM32F4, kilka układów na SPI1, SPI5, które działają i nieszczęsny magnetometr MMC5983MA na SPI2, który korzysta z tych samych funkcji, lecz nie chce rozmawiać. Odbiór danych w kodzie wygląda tak: uint8_t bufferSize = 2U; uint8_t readWriteBit = 0x80; uint8_t timeout = 10U; uint8_t productIdAddress = 0x2F; uint8_t txBuffer[2] = { productIdAddress | readWriteBit, 0x00 }; uint8_t rxBuffer[2] = { 0 }; HAL_GPIO_WritePin(MMC5983MA_SPI2_CS_GPIO_Port, MMC5983MA_SPI2_CS_Pin, GPIO_PIN_RESET); HAL_SPI_TransmitReceive(&hspi2, txBuffer, rxBuffer, bufferSize, timeout); HAL_GPIO_WritePin(MMC5983MA_SPI2_CS_GPIO_Port, MMC5983MA_SPI2_CS_Pin, GPIO_PIN_SET); Na analizatorze wygląda to tak, układ w ogóle nie macha linią MISO: Konfiguracja SPI2 z CubeMX: Schemat: Sekwencja zapisu/odczytu SPI: Przykład połączenia: Rejestr, który próbuję odczytać: Mam polutowane 4 płytki i na żadnej z nich nie udało mi się nawiązać połączenia, nie jest to dowód na to, że z pcb na pewno jest wszystko w porządku, ale chciałbym najpierw potwierdzić, że sposób odczytu danych od strony programowej jest poprawny. W erracie używanego procka nie ma żadnej wzmianki, która mogłaby mieć bezpośredni związek z moim problemem. Czy ktoś ma jakiś pomysł co mogę jeszcze sprawdzić? Edit: Płytki wypiekam w piecu IR, rampa jest bardzo zbliżona do tej z dokumentacji układu magnetometru, do tej pory nie udało mi się upalić pozostałych układów, więc obstawiałbym, że proces lutowania ich nie zabija.
  20. Po udanym projekcie robota "Copernicus" - w szeregowym łańcuchu kinematycznym 4DOF przyszedł czas na robota klasy delta, nazwanego "Astra", ponieważ ramiona układają się właśnie w gwiazdę Prototyp prezentowałem na targach Hobby 2019 na Międzynarodowych Targach Poznańskich, generalnie nie ma nic rewolucyjnego - zasilacz 36V, 3 silniki NEMA17 z przekładniami planetarnymi, przeguby kulkowe firmy Igus® (serdecznie dziękuję), zerowanie - krańcówki, eżektor, ssawka, w pierwszej wersji - Arduino Mega, teraz to już Discovery F429 z wyświetlaczem LCD (wyświetlam na nim koordynaty, chciałbym też obsługiwać dotyk, ale dodanie biblioteki do obsługi dotyku kłóci się ze sterowaniem silnikami krokowymi ). Aktualnie, robot potrafi wykonać proste zadanie pick&place Projekt cały czas ewoluuje (określiłbym postęp na 60%), mam zamontowaną RPi 3B+ z kamerką, chciałbym dodać podajnik obrotowy, rozpoznawać kolor krążków i układać do określonych pojemników, a na koniec pudełeczko z posortowanymi elementami pneumatycznie wysunąć - chyba, że komuś przychodzi na myśl coś lepszego? (ale, żeby z wykorzystaniem pneumatyki, mam do dyspozycji dużo różnych siłowników i kilka chwytaków ), z góry mówię, że znam aplikację taśmociągu i systemu wizyjnego Podziękowania składam również dla Kolegi @Eukaryota za pomoc i inspirację Pozdrawiam
  21. W przypływie wolnego czasu chciałem przećwiczyć sobie obsługę USB w STM32 i przy okazji zrobić coś praktycznego do podłączenia do komputera. Ponieważ mam klawiaturę mechaniczną z przyciskami multimedialnymi ukrytymi pod mało praktyczną kombinacją z klawiszem FN (klawisz po prawej stronie - totalnie niepraktyczne w tym zastosowaniu) postanowiłem zrobić sobie dedykowany pilot do multimediów. Platforma STM32F103 bo mam mały zapas płytek BluePill. Jako sterowanie wybrałem joystick z enkoderem na wzór tych z systemów infotainment w samochodzie. Żeby doprecyzować joysticki ALPS RKJXT1F42001 zamówione jakiś czas temu na aliexpress i czekające na projekt jak ten. Kod na STM32 powstawał na bazie generowanego przez CubeIDE przy middleware USB_DEVICE z wybranym Human Interface Device Class (HID). W moim odczuciu generowany kod jest chyba bardziej demonstracją, ponieważ kod z definicjami deskryptorów jest stworzony dla myszy, i nie ma nigdzie znaczników USER_CODE_BEGIN/END. Próbowałem coś zadziałać z klasą Custom Human Interface Device ale mogłem znaleźć deskryptorów urządzenia, konfiguracji i interfejsu w kodzie, a deskryptor raportu HID był do napisania od zera, co jest raczej trudne przy pierwszym projekcie z USB. Zostałem przy przykładzie z myszką od ST, który sukcesywnie modyfikowałem, tworząc kopie zapasowe na wypadek potrzeby generowania kodu z Cube (przez brak znaczników USER_CODE wszystkie zmiany - głównie zmodyfikowany deskryptor raportu - byłyby nadpisane przez wygenerowany kod). Nie będę opisać tworzenia mojego deskryptora bo robiłem to raczej na czuja metodą prób i błędów. W skrócie chodzi o to, że deskryptor raportu HID informuje host(komputer) o możliwościach urządzenia oraz przypisuje funkcjonalności bajtom w raporcie HID - w moim przypadku każdy bit w drugim bajcie raportu niesie informacje o wciśnięciu przycisku z grupy consumer page (0x0C) (więcej o nich w dokumentacji USB HID - HID Usage Tables 1.12). Utworzenie deskryptora od zera jest raczej trudne dla początkującego ale w internecie jest sporo informacji - wielką pomocą był dla mnie raport z przykładowej implementacji (http://www2.ece.rochester.edu/~parihar/pres/Report_MultiMedia-KB.pdf) w którym o wiele lepiej wytłumaczono działanie USB, klas i deskryptorów, niż ja to jestem w stanie zrobić. Oprócz tego mój deskryptor raportu jest lekko zmodyfikowaną wersją tego spod linku. Deskryptory urządzenia, konfiguracji i interfejsu wykorzystałem w wersji wygenerowanej przez cube dla myszy - zmieniłem jedynie typ urządzenia na klawiaturę (0x01) w deskryptorze konfiguracji (Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c). Deskryptor raportu powstał na podstawie tego podlinkowanego. Mapowanie przycisków do bitów w raporcie jest tam zobrazowane na stronie 11. Dobry tutorial o deskryptorach raportów HID tutaj. Gotowy deskryptor raportu przedstawia się tak: 0x05, 0x0c, // USAGE_PAGE (Consumer Devices) 0x09, 0x01, // USAGE (Consumer Control) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x10, // REPORT_COUNT (16) 0x09, 0xe2, // USAGE (Mute) 0x01 0x09, 0xe9, // USAGE (Volume Up) 0x02 0x09, 0xea, // USAGE (Volume Down) 0x03 0x09, 0xcd, // USAGE (Play/Pause) 0x04 0x09, 0xb7, // USAGE (Stop) 0x05 0x09, 0xb6, // USAGE (Scan Previous Track) 0x06 0x09, 0xb5, // USAGE (Scan Next Track) 0x07 0x0a, 0x8a, 0x01, // USAGE (Mail) 0x08 0x0a, 0x92, 0x01, // USAGE (Calculator) 0x09 0x0a, 0x21, 0x02, // USAGE (www search) 0x0a 0x0a, 0x23, 0x02, // USAGE (www home) 0x0b 0x0a, 0x2a, 0x02, // USAGE (www favorites) 0x0c 0x0a, 0x27, 0x02, // USAGE (www refresh) 0x0d 0x0a, 0x26, 0x02, // USAGE (www stop) 0x0e 0x0a, 0x25, 0x02, // USAGE (www forward) 0x0f 0x0a, 0x24, 0x02, // USAGE (www back) 0x10 0x81, 0x62, // INPUT (Data,Var,Abs,NPrf,Null) 0xc0 I definicje bitów dla przycisków oraz zmiennej przechowującej raport HID do wysłania #define HID_REPORT_SIZE 3 #define MEDIA_MUTE 0 #define MEDIA_VOLUP 1 #define MEDIA_VOLDOWN 2 #define MEDIA_PLAY_PAUSE 3 #define MEDIA_STOP 4 #define MEDIA_PREV 5 #define MEDIA_NEXT 6 /* USER CODE END PD */ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim1; /* USER CODE BEGIN PV */ extern USBD_HandleTypeDef hUsbDeviceFS; uint8_t HID_report[HID_REPORT_SIZE] = {0x01,0,0}; //empty hid report W celu zakomunikowania hostowi wciśnięcia przycisku wysyłamy raport HID z ustawionym bitem odpowiadającym wciśniętemu przyciskowi. Przykładowo dla przycisku VOL_UP ustawić należy drugi bit w drugim bajcie raportu. Ponieważ należy zasymulować wciśniecie i zwolnienie przycisku należy wysłać po chwili drugi raport z samymi zerami. Ważne jest też zachowanie co najmniej 10 ms odstępu między wysyłaniem raportów, by dać czas na przetworzenie informacji bibliotece USB na STMie oraz hostowi (komputerowi). Poniżej kod w funkcji main() obsługujący wysyłanie raportów o wciśnięciu przycisków HID_report[1]=0; //0 means none of the buttons pressed ////THIS CODE CAN SUPPORT ONLY 1 KEY AT A TIME, AND VERY SLOW REPEAT WITH LONG PRESS//// CheckButtonsState(); //check if any button is pressed and set appropriate bits in HID_report[1] if(HID_report[1]!=0){ USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); //send key-press and after 15 ms key-release reports HAL_Delay(400); HID_report[1]=0; USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); HAL_Delay(15); } Funkcja CheckButtonsState() ustawia na podstawie stanów logicznych na wejściach uC, bity w 2 bajcie tablicy uint8_t przechowującej raport HID. void CheckButtonsState(){ if(!HAL_GPIO_ReadPin(PUSH_GPIO_Port, PUSH_Pin)) { //push input is low when whichever button is pressed uint8_t isPushPressed=1; if(!HAL_GPIO_ReadPin(RIGHT_GPIO_Port, RIGHT_Pin)) {SetKeyPress(MEDIA_NEXT); isPushPressed=0; } if(!HAL_GPIO_ReadPin(LEFT_GPIO_Port, LEFT_Pin)) {SetKeyPress(MEDIA_PREV); isPushPressed=0; } if(!HAL_GPIO_ReadPin(UP_GPIO_Port, UP_Pin)) {SetKeyPress(MEDIA_MUTE); isPushPressed=0; } if(!HAL_GPIO_ReadPin(DOWN_GPIO_Port, DOWN_Pin)) {SetKeyPress(MEDIA_STOP); isPushPressed=0; } if(isPushPressed==1){SetKeyPress(MEDIA_PLAY_PAUSE);} } } void SetKeyPress(uint8_t key){ HID_report[1] |= 1<<key; } Zastosowany joystick ALPS jest tak skonstruowany, że wciśnięcie jakiegokolwiek przycisku zwiera także wyprowadzenie PUSH odpowiadające wciśnięciu joysticka. Z tego powodu funkcja jest napisana tak, że jeżeli na wejściu PUSH jest 1 to na każdym innym musi być 1 (styki otwarte). Jeżeli wciśnięty jest PUSH (logiczne 0) ale też 0 jest na pinie od innego przycisku, oznacza to że wciśnięto inny przycisk, a stan na wejściu PUSH jest ignorowany. Jeżeli 0 jest tylko na wejściu PUSH, oznacza to że joystick rzeczywiście został wciśnięty. Takie rozwiązanie prosi się aż o generowanie przerwania z wejścia PUSH i wykonywania kodu wtedy. Ponieważ jestem leniwy i miałem już gotowy kod do wysyłania raportów HID kiedy to odkryłem, zostałem przy pollingu stanu na wejściach. Delay po wysłaniu raportu rozwiązuje mi także problem z debouncingiem przycisków (obserwowałem wejścia na oscyloskopie i stwierdzam że styki w tym joysticku drżą jak złe ). Regulację głośności obsługuję przez timer 1 w trybie enkodera (przydał się kurs zaawansowanych timerów na STM32 z waszego bloga ). Przy zmianie wartości licznika timera wartość jest porównywana z zapisaną w poprzednim przejściu głównej pętli while(1). Jeżeli się zmieniła na mniejszą lub większą wysyłany jest raport HID z ustawionym bitem odpowiadającym klawiszowi VOLUP/VOLDOWN a zmienna lastEncoderCount jest in/dekrementowana. Dopóki obie wartości nie są równe raporty są wysyłane co przejście głównej pętli while. Wartość licznika jest dzielona przez 2 gdyż przy poprawnej pracy enkodera o tyle zmienia się po przeskoczeniu "o jeden ząbek". Czasem miałem sytuację że wartość licznika była nieparzysta (może błąd połączeń/drżenie styków) i algorytm w kółko podnosił/obniżał głośność o 1 bo wartości encoderCount i lastEncoderCount nigdy nie były równe. Dzielenie przez 2 gwarantuje parzystość wartości zmiennej ///TE ZMIENNE SA GLOBALNE/// uint16_t encoderCount=32766; //half of timers resolution (16bit) uint16_t lastEncoderCount=16383; //////////////////////////// //TEN KOD WYKONUJE SIE W PETLI WHILE FUNKCJI MAIN()// encoderCount=__HAL_TIM_GET_COUNTER(&htim1)/2; //get encoder absolute position if(encoderCount!=lastEncoderCount){ if(encoderCount<lastEncoderCount){SetKeyPress(MEDIA_VOLDOWN);lastEncoderCount-=1;} //set key press depending on encoder movement direction else{SetKeyPress(MEDIA_VOLUP);lastEncoderCount+=1;} USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); HAL_Delay(15); HID_report[1]=0; USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); HAL_Delay(15); } Kompletne oprogramowanie STMa dostępne na github.com/wiciu15/STM32-USBHID-MultimediaPilot. Po zweryfikowaniu działania prototypu zaprojektowałem i wytrawiłem prostą płytkę w KiCADzie żeby się pozbyć luźnych kabelków. Urządzenie zasilane jest z USB na BluePillu, programuje je z wyprowadzeń SWD po drugiej stronie płytki za pomocą ST-Linka V2. Żeby urządzenie jakoś wyglądało zaprojektowałem i wydrukowałem obudowę oraz gałkę do joysticka. Od razu ostrzegam że na drukarce FDM ciężko jest osiągnąć taką precyzję żeby gniazdo w gałce ciasno siedziało na wałku joysticka - ja zaprojektowałem 0,1mm ciaśniej i przy montażu rozgrzałem plastik tak by się uplastycznił i dopasował do kształtu na końcu drążka joysticka. Nie jest to ciasne pasowanie ale wystarcza żeby sterować bez urywania gałki co drugie dotknięcie . I wydrukowane: Wszystkie pliki z kodem, płytka i obudowa dostępne na github.com/wiciu15/STM32-USBHID-MultimediaPilot. Z racji że chciałbym dalej to rozwijać to zakupiłem moduł NRF51822 i będę próbował zrobić coś podobnego, ale na Bluetooth HID, i z zastosowaniem w aucie do sterowania tanim tabletem z emulatorem headunitu AndroidAuto (używam apki HeadUnit Reloaded która wspiera obsługę z klawiatury do sterowania API Androida Auto np. sterowanie jasny/ciemny tryb, multimedia, poruszanie się po interfejsie za pomocą enkodera - AA jest tak zaprojektowany bo piloty do systemów infotainment z reguły mają też enkodery). Jedyna moja obawa jest taka że pilocik będzie musiał działać cały czas ze stałej instalacji 12V, bo tablet z niewiadomych powodów po rozłączeniu z sparowanym urządzeniem BT wymaga ręcznego ponownego połączenia, więc po wyłączeniu i włączeniu pilocika czeka mnie wycieczka do ustawień tabletu by go z powrotem połączyć. Nie mam doświadczenia z programowaniem nRF więc zobaczymy jak mi pójdzie na raz z BT HID, przerwaniami, enkoderem i jeszcze minimalizacją poboru energii Łatwiej by było dorobić drugie USB w tablecie i podłączyć taki pilot jak opisałem powyżej. Tu jest problem tej natury, że tablet który mam już zmodyfikowany i założony na bardzo mocną taśmę dwustronną () nie chce działać na OTG z więcej niż jednym urządzeniem. Podłączałem do niego kilka HUBów USB, kupiłem nawet specjalną przejściówkę do OTG z paroma portami USB ale nic nie chce ruszyć. Póki co moduł z NRF81 dopiero przyszedł, będę teraz się oswajał z SDK do niego, może jakiś hello world . Nie jestem jeszcze pewny czy będę w stanie go programować i debugować bo mam tylko ST-Linka na stanie w tej chwili Podobno korzystając z OpenOCD można ST-Linka z tym połączyć ale to musiałbym przy wolnej chwili zrobić próby. Jak nie ruszy to będę szukać jakiegoś JTAGa ale ceny mnie trochę odstraszają. Wszelkie sugestie, pochwały, krytyka i komentarze mile widziane
  22. Witam Tak jak w temacie chciałbym skonfigurować dwa moduły nRF24L01 do najprostszej komunikacji między sobą. Mam na myśli podstawowe wysyłanie danych np. jednego bajtu, bez żadnych bajerów typu zmiana adresu, automatyczna odpowiedź, potwierdzenie dostarczenia itp. Do obsługi tych modułów korzystam z mikrokontrolerów STM32. Konfiguruję wszystko zgodnie z notą od producenta, krok po kroku ustawiam wszystkie rejestry konfiguracyjne tj: - CONFIG - tu ustawiam maskę przerwań, włączam moduł i ustalam tryb pracy (Rx lub Tx) - EN_AA Enhanced ShockBurst™ - tutaj zeruję cały rejestr - nie korzystam z Auto Acknowledgment - RX_PW_P0 - korzystam z pipe 0 i dla niej ustawiam długość ładunku na 1 bajt - SETUP_RETR - tutaj wyłączam retransmisję - RF_SETUP - ustawiam prędkość transmisji na 1 Mbps ...i w zasadzie to wszystko. Doczytałem że tyle jest wymagane do prostej komunikacji. Dodam jeszcze że korzystam z domyślnych adresów zarówno w nadajniku jak i odbiorniku (0xE7E7E7E7E7) więc rejestrów z adresami w ogóle nie ruszam. Nadawanie realizuję w ten sposób: po konfiguracji (przy niskim CE) wysyłam do modułu komendę "Chcę wysłać dane" oraz dane do wysłania (1 bajt) przez SPI. Po zakończeniu transmisji wystawiam impuls wysoki na pinie CE. Odbieranie: po konfiguracji (również przy niskim CE) wystawiam stan wysoki na pinie CE - nasłuchiwanie, po czym moduł po otrzymaniu poprawnie odebranych danych wystawia stan niski na pinie przerwania IRQ co oznacza że są gotowe dane do odczytania. Problem w tym że..... nie wystawia sygnału na IRQ... czyli nie odbiera danych a przynajmniej nie poprawnie. Dlatego też zwracam się z prośbą o pomoc i pytaniem co w powyższych czynnościach jest błędne lub czego brakuje ??? Liczę na to że ktoś z mądrych ludzi, których na tym forum nie brakuje zadał sobie kiedyś taki trud jak ja i zechciał samodzielnie obsłużyć moduły radiowe nRF24L01 nie korzystając z bibliotek. Bardzo proszę o nawet drobne wskazówki.
  23. Witam! Czy ktoś jest w stanie polecić jakieś materiały na temat współpracy ESP32-CAM i STM32 udało mi się nawiązać komunikację poprzez FTDI lecz nie wiem co dalej.
  24. Na podstawie kursu STM32 chcę uruchomić płytkę STM32F103C8T6, zdjęcie płytki poniżej. Oczywiście nie mogę podczas tworzenia projektu wybrać NUCLEO-F103RB więc poniżej przesyłam zdjęcia z konfiguracji, czy jest ona prawidłowa ? Czy może powinienem wejść w zakładkę MCU a nie Board i tam wybrać procesor ? Przechodząc do biblioteki, zgodnie z opisaną aktualizacją: https://forbot.pl/forum/topic/8387-kurs-stm32-3-plytka-nucleo-konfiguracja-srodowiska/page/10/#comments Dla NUCLEO-F103RB: https://www.st.com/en/embedded-software/stsw-stm32143.html#overview Dla STM32F103C8T6: https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f1-series/stm32f103/stm32f103c8.html#tools-software Następnie wybrałem zakładkę Tools & Software, następnie MCU & MPU Embedded Software, następnie najbardziej podobny plik do "based on Standard Peripheral Library" to (proszę kliknąć ctrl+f i wkleić STM32-CLASSB-SPL). Czy to jest odpowiedni plik ?
  25. Cześć. Robię projekt rozpoznawania jednego z kilku ruchów za pomocą akcelerometru, żyroskopu, STM32F467ZG i pakietu X-CUBE-AI. Opieram się na artykule @Elvis Sztuczna inteligencja na STM32, czyli przykład użycia X-CUBE-AI, ale mam kłopot z jego rozszerzeniem. Próbowałem różnych sposobów, ale nie mogę zrobić sieci, która zamiast wartości binarnej (ruch - brak ruchu) zwróci mi prawdopodobieństwa każdego z 6 wyjść (na razie chciałbym tyle różnych ruchów rozpoznawać). Mam książkę, którą poleca Elvis ("Deep Learning" autorstwa Chollet'a), ale brak doświadczenia z SSN, czy nawet językiem Python mocno mnie ogranicza. Chciałbym też, żeby zamiast jednego wejścia będącego prostą funkcją odczytów z czujników (suma kwadratów odczytów z akcelerometru), f = open('data1.csv','r') values = [] results = [] for line in f: fields = line.strip().split(',') if len(fields) == 4: x = float(fields[0]) y = float(fields[1]) z = float(fields[2]) values.append([math.sqrt(x**2 + y**2 + z**2)]) results.append(float(fields[3])) f.close() układ bezpośrednio korzystał ze wszystkich 6 (3ACC i 3 GYRO). Tutaj fragment kodu Elvisa z STM'a: void MX_X_CUBE_AI_Process(void) { /* USER CODE BEGIN 1 */ float nn_input[AI_FORBOT_AI_IN_1_SIZE]; float nn_output[AI_FORBOT_AI_OUT_1_SIZE]; aiRun(nn_input, nn_output); /* USER CODE END 1 */ } static uint32_t next_ms = 1000; static float nn_input[AI_FORBOT_AI_IN_1_SIZE]; float nn_output[AI_FORBOT_AI_OUT_1_SIZE]; while (HAL_GetTick() < next_ms) {} next_ms += READ_DELAY_MS; lsm6_value_t acc; acc = lsm6_read_acc(); for (int i = 0; i < AI_FORBOT_AI_IN_1_SIZE - 1; i++) nn_input[i] = nn_input[i + 1]; nn_input[AI_FORBOT_AI_IN_1_SIZE - 1] = sqrt(acc.x * acc.x + acc.y * acc.y + acc.z * acc.z); aiRun(nn_input, nn_output); if (nn_output[0] >= 0.5f) HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); else HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); Pomożecie mi zmienić kod Python'a i STM'a, bym mógł go użyć do swoich potrzeb? Naprawdę długo szukałem sposobu i próbowałem wielu rozwiązań, ale albo nie działa mi sieć neuronowa, albo nie kompiluje się projekt w SW4STM32.
×
×
  • Utwórz nowe...