Arduino Polska Forum

Pełna wersja: RTOS - gdzie poczytać?
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Stron: 1 2 3
Cześć

Czy na forum jest wątek o RTOSach dla Arduino? Chyba nie widzę...
Chciałbym się zabrać za ten temat...

PWL
Szukaj na Elektrodzie ale pierwotnie wątek miał być dla początkujących lecz przerodził się w dyskusję kompletnie nie związaną z tematem.

Po swoich doświadczeniach, mogę stwierdzić, że jesteś skazany na siebie ale jak będziesz potrzebował pomocy, to chyba tylko fora zagraniczne i Elektroda. Tu i na Forbocie, moim zdaniem (i doświadczeniem) nie masz na co liczyć.

(28-06-2019, 17:32)PierwszyWolnyLogin napisał(a): [ -> ]Chciałbym się zabrać za ten temat...
Tak z ciekawości, jak chcesz "pożenić" Arduino i RTOS?
Nie twierdzę, że się nie da, pamiętaj jednak, ze bez debugera będziesz długo walczył, a Arduino IDE nie wspiera debugera. Twórcy Arduino,m założyli, że Arduinowcy są nieomylni i debuger jest zbędny.

Kolejna sprawa, wielkość pamięci RAM. Gdy czytam Arduino, bez dodatkowych informacji, zakładam Arduino UNO. 2kB RAM to za mało dzisiejszych czasach na jakiś sensowny projekt zrealizowany zgodnie ze "sztuką" a co dopiero RTOS? RTOS, jak każdy system wielozadaniowy lubi RAM. Nie to, ze się nie da, ale po co się męczyć, jak zamiast Mega328, można użyć ok 100 razy szybszego, tańszego, lepiej wyposażonego (między innymi w pamięć RAM) ARM?

Proponuję STM32, CUbeMX, który wygeneruje kod, także dla RTOS. Napisałem tylko pobieżnie o sensie użycia (zwłaszcza z RTOS) ARM, więcej:
- ARM pzeważnie są tańsze niż AVR o podobnym wyposażeniu oferując zdecydowanie większe możliwości (DMA) i prędkość działania
- ARM, przy tym samym zegarze jest ok 7 razy szybszy od AVR, a maksymalne częstotliwości taktowania zaczynają się od 24MHz a kończą na 650 (w przypadku rodziny STM32.
- W przeważającej większości mają więcej pamięci RAM i można robić duże bufory nadawcze dla UART, I2c, SPI, USB.
- Maja bogatsze wyposażenie (liczba usart, I2C, SPI, timerów) i większe możliwości tychże peryferii.
- Mają DMA (AVR ATmega/tiny nigdy o czymś takim nie słyszały).
- Wiele ARM ma USB, w AVR to rzadkość.
- Wersje z Ethernetem, AVR nie ma z ETH.
- Wszystkie timery 16-bit (można łączyć w 32-bit) a wiele wersji posiada 32-bit.
- AC 12..16-bit, CA 12-bit.
- AC do 80MS/s (LPC), 18MH/s (STM32).
- Mają wielopoziomowy system przerwań.
- Tańsze narzędzia (debuger).
- Podczas debugowania na bieżąco widzę stan zmiennych w AVR po zatrzymaniu uC.
- CubeMX do konfigurowania i generowania kodu (najnowszy także IDE i kompilator).
- Nie muszę się zastanawiać czy dana jest w ram czy flasch aby użyć stosownej funkcji (z sufiksem _P).
- argument liczbowy w sprintf, scanf itp nie jest ograniczony do 16-bit int lecz do 32-bit.
- przesuwane bitu (w lewo) nie jest ograniczone do 16 bitów.
- Zdecydowanie większe pojemności pamięci FLASH (do 2MB) i RAM (do 1MB) o czym nawet AVR Xmega mogą tylko pomarzyć.
Dla początkujących: https://stm32.eu/2019/01/31/nowa-ksiazka...-dostepna/

Czemu "naciskam" na DMA?
To będzie widać w poniższych linkach, ale ważniejsze, że brak DMA często "zabija" zalety RTOS. Nawet ARM nie lubi przerwań 300'000razy na sekundę (AVR się dławi - obciążenie CPU 80..90% przy 20MHz). Zakładam, że wiesz jak się oblicza obciążenie CPU?

ARM vs AVR:
Przykładowo, wysyłanie danych do WS2812 w przypadku Arduino (nie ważne AVR, ARM czy ESP) blokuje CPU na czas tej operacji. Nie wiem jak w przypadku ESP i ARM ale w AVR blokowane są przerwania. To oznacza, że w tym czasie nie będą np odbierane znaki przez UAR, nie działa USB, itp. Transmisja do LED może trwać nawet kilkadziesiąt ms. W ARM, sama transmisja będzie trwać tyle samo ale CPU będzie zajęty tylko przez kilkaset ns bo wysyłaniem danych zajmuje się DMA.
To samo z LCD, w AVR CPU zajęty 100% w czasie wysyłania danych (typowo 20..40ms w przypadku kolorowego wyświetlacza), na ARM us.
Wysyłanie na AVR danych do wyświetlacza w czasie dziesiątek ms jest możliwe, że ma wymaganą ilość pamięci RAM na bufor. Wyświetlacz 96x64 wymaga 12'288bajtów RAM (z Mega w grę wchodzi tylko Mega1284), 128x128 wymaga 32kB RAM, więc Mega odpada. Wymusza to stawianie punktu po punkcie, co zajmuje ok 3 razy więcej czasu.
Namacalne dowody:
https://www.elektroda.pl/rtvforum/topic3588785.html
Zainstalowałem bibliotekę „TFT_ILI9163C-master” ze strony „Nettigo”. Uruchomiłem przykład „Cube”, efekty widać na filmie.
https://es2.000webhostapp.com/Szescian_3...no_UNO.mp4
Zagoniłem do pracy ARM STM32F411CE. Zegar ustawiłem na 60MHz, co pozwoliło taktować SPI częstotliwością 15MHz, maksymalną dopuszczalną dla IL9306. Przeniosłem bibliotekę z Arduino, oto efekt:
https://es2.000webhostapp.com/Szescian_3...ez_DMA.mp4
Słaby coś ten ARM, animacja niewiele szybsza (użyłem HAL, gdyby wykorzystać dostęp rzez rejestry animacja byłaby prawie 2 razy szybsza niż na UNO). Nie, to nie ARM słaby tylko programista, który przeniósł kod nie wykorzystując możliwości sprzętowych ARM. Stworzyłem bufor na dane dla wyświetlacza (128*160*2=40960bajtów) i zagoniłem do pracy DMA. Efekt:
https://es2.000webhostapp.com/Szescian_3D_ARM_z_DMA.mp4
Na koniec porównanie ARM z AVR, gdzie na AVR wyraźnie widać rysowanie tła podczas jego zmiany.
https://es2.000webhostapp.com/Szescian_3...vs_AVR.mp4
https://es2.000webhostapp.com/Szescian_3...ne_tlo.mp4


Wracając do RTOS w ogóle. Wielokrotnie moderatorzy (który wyrośli bardzo szybko z amatorów dalay-owców) uświadamiali mnie , że forum Arduino Polska jest dla amatorów a tu widzę pełen profesjonalizm. Skoro chcesz się zabrać za RTOS, to z pewnością:
- Biegle posługujesz się przerwaniami od każdego możliwego układu peryferyjnego zarówno podczas nadawania jak i odbioru.
- Nie masz delay i pętli oczekującej na zdarzenie np
Kod:
while ( cos_tam ) ;
- Programy realizujesz w oparciu o maszynę stanów.
- Potrafisz synchronizować zdarzenia z różnych pseudowątków pomiędzy sobą (w RTOS będzie trudniej, mutex'y, semafory, kolejki) oraz pomiedzy przerwaniami a programem głównym.
Jeśli powyższe znasz bardzo dobrze, mogę pomóc w sprawie RTOS.
Zainstalowałem z ciekawości i jak na razie "mieszane odczucia"...

Płytka Mega 2560.
Wgrałem przykład z dwoma migającymi LEDami (lekko poprawiłem). Działa, migają jak głupie Wink

Pomyślałem, że sprawdzę jak szybko wykonywane są zadania. W tym celu zdefiniowałem
jedno, które tylko zwiększa zmienną RPM o 1 (RPMengine), oraz drugie, które miało co sekundę
wyświetlać wartość tej zmiennej (RPMlicznik). No i kicha, zadanie "RPMlicznik" nie widzi zmiennej
globalnej "RPM" - wyświetla same zera.

Co ciekawe odkryłem, że gdy wstawić za RPM++ minimalny delay to zmienna już jest widoczna.
Z "delay(1)" zadanie RPMengine wykonywane jest około 1000/s a z "vTaskDelay(1)" około 60x/s.

Chwilę mi to zajęło, żeby ten delay wymyślić, nie powiem żeby mi się to podobało...


Kod:
void RPMengine(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    RPM=RPM+1;
    delay(1);        // bez tego RPM = 0, jakby nie było poprzedniej linii,
    //vTaskDelay(1); // lub tego ;)
  }
}

void RPMlicznik(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    Serial.println(RPM/(millis()/1000));
    vTaskDelay( 1000 / portTICK_PERIOD_MS );
  }
}

Ps. Zmienianie priorytetów zadań nic nie dało...

Pogrzebię trochę więcej, może się nie zniechęcę Wink
PWL
(28-06-2019, 19:59)PierwszyWolnyLogin napisał(a): [ -> ]Płytka Mega 2560.
Wybór rozsądny, bo ma dużo (jak na AVR) RAM, niestety, o DMA zapomniano :-(
Kolejna zaleta to JTAG, więc łatwe, pewne i szybkie debugowanie (jak na AVR). Niestety, Arduino, wyłącza JTAG ale czy programowo w bootloaderze czy w fuses nie wiem i nie chcę wiedzieć.

(28-06-2019, 19:59)PierwszyWolnyLogin napisał(a): [ -> ]No i kicha, zadanie "RPMlicznik" nie widzi zmiennej
globalnej "RPM" - wyświetla same zera.
Pokaż cały kod bo nie widzę deklaracji zmiennej RPM.
Kod:
#include <Arduino_FreeRTOS.h>

// define two tasks for Blink & AnalogRead
void TaskBlinkGreen( void *pvParameters );
void TaskBlinkRed( void *pvParameters );
void TaskRPMlicznik( void *pvParameters );
void TaskRPMengine( void *pvParameters );


//void TaskAnalogRead( void *pvParameters );

float RPM = 0;

// the setup function runs once when you press reset or power the board
void setup() {


etc

Ps. "delay(0);" też działa...
PWL
(28-06-2019, 20:35)PierwszyWolnyLogin napisał(a): [ -> ]float RPM = 0;
Float? Dlaczego?
W Arduino float jest wyjątkowo często nadużywany, zwłaszcza w AVR, jakby były zbyt szybkie i miały za dużo pamięci.
Właśnie portuję bibliotekę z Arduino na STM32 i już wywaliłem kilkanaście float, gdzie wystarczyłby uint16_t czy unit32_t.

Co do problemu, pokaż *lss z i bez delay, może da się coś wywnioskować.
Nie znam się bo też jestem początkujący ale w przykładzie użyłeś dwie nie kończące się pętle to już twój zły tok rozumowania, bo pierwsza pętla nie pozwala uruchomić drugiej, Tu zasada jest taka jak wszędzie w jednym czasie może wykonywać tylko jedno co innego gdybyś miał 2 core i rozdzielił zadania dla procesorów. Dlatego "delay" powoduje działanie przykładu bo wtedy dajesz czas na drugą pętlę. Pierwsza pętla for bez delay obciąża procesor 100% wiec jak ma się wykonać druga??

Zainteresuj sie vTaskDelayUntil a życie stanie sie prostsze.
(28-06-2019, 23:11)Jarewa0606 napisał(a): [ -> ]w przykładzie użyłeś dwie nie kończące się pętle  to już twój zły tok rozumowania, bo pierwsza pętla nie pozwala uruchomić drugiej,
Wiesz co to RTOS?
NIE WIESZ!
Bez RTOS taka konstrukcja wywołałaby ostrzeżenie (chyba, ze się je wyłączy w kompilatorze) a druga pętla nie zostałaby skompilowana. Można to sprawdzić w pliku *lss (wiesz co to?) lub próbując postawić breakpoint (używałeś? 99,9% nie) - nie da się chyba, że zmienisz optymalizację na O0 (wiesz co to optymalizacja, jakie są i jak je zmienić?)

(28-06-2019, 23:11)Jarewa0606 napisał(a): [ -> ] Tu zasada jest taka jak wszędzie w jednym czasie może wykonywać tylko jedno
Zapoznaj się z RTOS!
Można się zgodzić, że jeden rdzeń w danej chwili wykonuje jedno zadanie, ale może być wspomagany przez DMA i np taki STM32 może wykonywać 31 operacji w tym samym czasie. Ponadto, jak wytłumaczyć to, że w czasie gdy odbierane są dane po USART, wyświetlane są informacje na LCD i wysyłane/odbierane informacje po I2C, SPI gromadzone próbki z ADC?

(28-06-2019, 23:11)Jarewa0606 napisał(a): [ -> ]co innego gdybyś miał 2 core i rozdzielił zadania dla procesorów.
Myślisz, że 2 CORE to tylko 2 zadania w (pozornie) jednym czasie? Sprawdź ile zadań realizuje Linux i Window$ na 1, 2 czy 4 CORE.

(28-06-2019, 23:11)Jarewa0606 napisał(a): [ -> ]Dlatego "delay" powoduje działanie przykładu bo wtedy dajesz czas na drugą pętlę.
Tu to walnąłeś, jak łysy grzywą o kant kuli narysowanej przez Pitagorasa przy pomocy ekierki.

(28-06-2019, 23:11)Jarewa0606 napisał(a): [ -> ]Nie znam się bo też jestem początkujący ale
To dlaczego się wypowiadasz i przy okazji PISZESZ BZDURY!


Twierdzisz, że poniższy kod
Kod:
void StartLedG_Task(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    osDelay(200/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_G_GPIO_Port, LED_G_Pin,GPIO_PIN_SET );
    osDelay(800/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_G_GPIO_Port, LED_G_Pin,GPIO_PIN_RESET );
  }
}

void StartLedR_Task(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    osDelay(300/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_R_GPIO_Port, LED_R_Pin,GPIO_PIN_SET );
    osDelay(300/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_R_GPIO_Port, LED_R_Pin,GPIO_PIN_RESET );
  }
}
nie spowoduje migania 2 led z różną częstotliwością? To dlaczego migają?
Jak potrafisz to przeanalizuj większą część kodu:
Kod:
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * Copyright (c) 2018 STMicroelectronics International N.V.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted, provided that the following conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  * 3. Neither the name of STMicroelectronics nor the names of other
  *    contributors to this software may be used to endorse or promote products
  *    derived from this software without specific written permission.
  * 4. This software, including modifications and/or derivative works of this
  *    software, must execute solely and exclusively on microcontroller or
  *    microprocessor devices manufactured by or for STMicroelectronics.
  * 5. Redistribution and use of this software other than as permitted under
  *    this license is void and will automatically terminate your rights under
  *    this license.
  *
  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"
#include "cmsis_os.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
osThreadId defaultTaskHandle;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
void StartDefaultTask(void const * argument);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
void StartLedG_Task(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    osDelay(200/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_G_GPIO_Port, LED_G_Pin,GPIO_PIN_SET );
    osDelay(800/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_G_GPIO_Port, LED_G_Pin,GPIO_PIN_RESET );
  }
}

void StartLedR_Task(void const * argument)
{
  /* Infinite loop */
  for(;;)
  {
    osDelay(300/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_R_GPIO_Port, LED_R_Pin,GPIO_PIN_SET );
    osDelay(300/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_R_GPIO_Port, LED_R_Pin,GPIO_PIN_RESET );
  }
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  *
  * @retval None
  */
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_GPIO_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
    
    
//#define osThreadDef(name, thread, priority, instances, stacksz)  \
//const osThreadDef_t os_thread_def_##name = \
//{ #name, (thread), (priority), (instances), (stacksz)}
//                                                                            nazwaTasku, nazwa_funkcji, priorytet, instances?, rozmiar stosu
const osThreadDef_t os_thread_def_LedG = { "Led G", StartLedG_Task, osPriorityNormal, 0, 128};
osThreadId LedG_TaskHandle;    // potrzebny aby zatrzymac task, zmienic proorytet itp
LedG_TaskHandle = osThreadCreate( &os_thread_def_LedG, NULL);    // wskaznik na wyzej zdefiniowana funkcje
    
const osThreadDef_t os_thread_def_LedR = { "Led R", StartLedR_Task, osPriorityNormal, 0, 128};
osThreadId LedR_TaskHandle;
LedR_TaskHandle = osThreadCreate( &os_thread_def_LedR, NULL);
    
    
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */


  /* Start scheduler */
  osKernelStart();
  
  /* We should never get here as control is now taken by the scheduler */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

  /* 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;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**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_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, LED_G_Pin|LED_R_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : LED_Pin */
  GPIO_InitStruct.Pin = LED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : LED_G_Pin LED_R_Pin */
  GPIO_InitStruct.Pin = LED_G_Pin|LED_R_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB11 */
  GPIO_InitStruct.Pin = GPIO_PIN_11;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{

  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
//    osDelay(1);
    osDelay(500/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_GPIO_Port, LED_Pin,GPIO_PIN_SET );
    osDelay(500/portTICK_PERIOD_MS);
        HAL_GPIO_WritePin( LED_GPIO_Port, LED_Pin,GPIO_PIN_RESET );        
  }
  /* USER CODE END 5 */
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  file: The file name as string.
  * @param  line: The line in file as a number.
  * @retval None
  */
void _Error_Handler(char *file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* 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****/
Jak chcesz dam cały projekt to wgrasz sobie HEX i sprawdzisz czy piszę prawdę.
Przykład jest z "osDelay" czyli korzysta z opóźnień, a osDelay korzysta z vTaskDelay()

W przypadku RTOS "delay" to nie jest blokada że nic nie robi jak to ma miejsce w "Arduino" to też czas na wykonywanie innych zadań.
(28-06-2019, 19:59)PierwszyWolnyLogin napisał(a): [ -> ]
Kod:
    RPM=RPM+1;
    delay(1);        // bez tego RPM = 0, jakby nie było poprzedniej linii,
    //vTaskDelay(1); // lub tego ;)
 
}
W RTOS, do przekazywania informacji pomiędzy taskami powinno używać się np kolejek. W RTOS taski nic o sobie nie wiedzą, tak jak w programie bez RTOS program główny nie wie o zmianach zmiennych w przerwaniu. Pewnie optymalizator zrobił swoje, zadeklaruj RPM z kwalifikatorem volatile i oczywiście zmień ten float na uint czy co tam potrzebujesz.

(28-06-2019, 23:37)Jarewa0606 napisał(a): [ -> ]W przypadku RTOS "delay" to nie jest blokada że nic nie robi jak to ma miejsce w "Arduino" to też czas na wykonywanie innych zadań.
Kulą w płot! W przykładzie jest
Kod:
delay(1);        // bez tego RPM = 0, jakby nie było poprzedniej linii,
a nie "osDelay". Co prawda nawet w czasie "delay" inne taski będą się wykonywać ale z przerwani 10ms, 1ms czy innym (zależnie jak jest skonfigurowany RTOS) bo delay będzie kręcił się w kółko aż scheduler, poz zadanym czasie nie przerwie tasku . W przypadku "osDelay" jest inaczej. Taki task, przez zadeklarowany czas nie jest nigdy wykonywany i pozostałe taski mogą pracować za max prędkością na jaką pozwala CPU.

To, że dostawienie delay pomaga, nie jest związane z tym, że inne taski mogą się wykonać, tylko z tym, ze optymalizator nie optymalizuje już zmiennej RPM. Taki sam efekt może wywołać wywołanie innej funkcji.
Stron: 1 2 3