Доброе время суток продолжаем серию уроков по программированию микроконтроллеров ARM, сегодня продолжаем говорить про ОСРВ, то есть про FreeRTOS и ChibiOS. Снова для узания у нас STM32F429zi-DISCO. Речь сегодня пойдет об динамической изменении приоритетов задачи. Приоритет задачи – это важность задачи для планировщика, чем выше приоритет, тем планировщик быстрее ее начнет выполнять и тем меньше система потратить процессорного времени на выполнении задачи. Минимальный приоритет для задачи – 0, данный приоритет имеет задача бездействия. Дефолтная задача в наше программе будет иметь приоритет равный 1, а задача для обработки реакции от нажатия кнопки будет иметь приоритет равный 2. Соответственно при условии, что у нас вытесняющая многозадачность задачи с приоритетом равным 1 никогда не получат процессорного времени и не начнет своего выполнения. Для того что бы задача не висели в бездействии, мы с вами уровняем силы, и переопределим приоритеты задачи с приоритетами равными 1 на приоритеты равными 2. Что ж, приступим)
FreeRTOS + STM32F4
UART_HandleTypeDef huart5; void SystemClock_Config(void); static void StartThread(void const * argument); static void MX_GPIO_Init(void); static void MX_UART5_Init(void); xTaskHandle xTask1Handle; xTaskHandle xTask2Handle; xTaskHandle xButtonHandle; volatile unsigned long global_temp = 0; typedef struct TaskParam_t{ signed long int period; } Task; Task p1, p2; void vTask1(void *pvParameters){ unsigned portBASE_TYPE uxPriority2; uxPriority2 = uxTaskPriorityGet(xTask2Handle); unsigned portBASE_TYPE uxPriority3; uxPriority2 = uxTaskPriorityGet(xButtonHandle); Task *task_period; task_period = (Task *)pvParameters; HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_SET); for(;;){ HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13); HAL_Delay(task_period->period); HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13); HAL_Delay(task_period->period); } vTaskDelete(NULL); } void vTask2(void *pvParameters){ Task *period; period = (Task *) pvParameters; HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); for(;;){ HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14); HAL_Delay(period->period); HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14); HAL_Delay(period->period); } vTaskDelete(NULL); } void vButton(void *pvParameters){ unsigned portBASE_TYPE uxPriority1; uxPriority1 = uxTaskPriorityGet(xTask1Handle); unsigned portBASE_TYPE uxPriority2; uxPriority2 = uxTaskPriorityGet(xTask2Handle); for(;;){ if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET){ vTaskPrioritySet(xTask1Handle, uxPriority1 + 1); vTaskPrioritySet(xTask2Handle, uxPriority2 + 1); } } vTaskDelete(NULL); } void ApplicationIdleHook(void){ } int main(void) { HAL_Init(); SystemClock_Config(); HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); MX_GPIO_Init(); MX_UART5_Init(); p1.period = 1000; p2.period = 1000; xTaskCreate(vTask1, (signed char *) "LED_GREEN", configMINIMAL_STACK_SIZE, (void *) &p1, 1, &xTask1Handle); xTaskCreate(vTask2, (signed char *) "LED_RED", configMINIMAL_STACK_SIZE, (void *) &p2, 1, &xTask2Handle); xTaskCreate(vButton, (signed char *) "BUTTON", configMINIMAL_STACK_SIZE, NULL, 2, NULL); vTaskStartScheduler(); while (1){ }
У нас есть 3 хэндела xTask1Handle, xTask2Handle и хэндел для кнопки. С помощью функции uxTaskPriorityGet мы берем значение дефолтных приоритетов от Task 1 и Task2 и пере присваиваем их с помощью функции vTaskPrioritySet на 2.
Динамическое изменение приоритетов для задач ChibiOS, имеет небольшую особенность так там нет дескриптора на задачу, а приоритет можно изменять только той задачи в которой вы в данный момент находитесь, которая имеет процессорное время выполнение.
#include "ch.h" #include "hal.h" static WORKING_AREA(waThread1, 128); static WORKING_AREA(waThread2, 128); static WORKING_AREA(waButton, 128); static msg_t Thread1(void *arg); static msg_t Thread2(void *arg); static msg_t Thread3(void *arg); typedef struct TaskParam_t{ signed long int period; } Task; Task p1, p2; int main(void){ p1.period = 1000; p2.period = 500; halInit(); chSysInit(); chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, (void *)&p1); chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, (void *)&p2); chThdCreateStatic(waButton, sizeof(waButton), HIGHPRIO, Thread3, NULL); while(TRUE){ } } static msg_t Thread1(void *arg){ Task *period; period = (Task *) arg; palSetPad(GPIOG, GPIOG_LED4_RED ); while(TRUE){ palTogglePad(GPIOG, GPIOG_LED4_RED); chThdSleepMilliseconds(period->period); } } static msg_t Thread2(void *arg){ Task *period; period = (Task *) arg; palSetPad(GPIOG, GPIOG_LED3_GREEN); while(TRUE){ palTogglePad(GPIOG, GPIOG_LED3_GREEN); chThdSleepMilliseconds(period->period); } } static msg_t Thread3(void *arg){ volatile int inc = 0; while(TRUE){ if(palReadPad(GPIOA, GPIOA_BUTTON) == PAL_HIGH){ inc++; if(inc % 2){ chThdSetPriority(HIGHPRIO); } else{ chThdSetPriority(NORMALPRIO); inc = 0; } } } }
В данном примере мы понижая и повышая приоритет задачи для обработки события нажатия кнопки, позволяем получить процессорное время задаче с более низким приоритетом.
На сегодня все!, всем пока!) увидимся на просторах mcu.by, как всегда вопросы оставляйте в коментах.