Передадим данные по UART с использованием FreeRTOS и созданием задачи.
Для работы с freeRTOS необходимо изменить SDK (в папке с исходниками все добавлено).
В создаваемый проект необходимо дописать следующие пути:
Выбираем Проект->Properties->C/C++ General -> Paths and Symbols -> GNU C
Изменим Makefile (лучше взять из примера в папке с исходниками)
Изменим содержимое файла main.h, дописав
#include "esp_common.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "uart.h"
#include "gpio.h"
Начнем изменять файл main.c
После #include "main.h" напишем тела 2-х задач:
void ICACHE_FLASH_ATTR task1(void *pvParameters)
{
uint32 cnt=0;
char str01[20];
for(;;)
{
snprintf(str01, sizeof(str01), "Task 1: %7lu",cnt);
os_printf("%s\n", str01);
cnt++;
if(cnt>=10000000) cnt=0;
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
void ICACHE_FLASH_ATTR task2(void *pvParameters)
{
uint32 cnt=0;
char str01[20];
for(;;)
{
snprintf(str01, sizeof(str01), "Task 2: %7lu",cnt);
os_printf("%s\n", str01);
cnt++;
if(cnt>=10000000) cnt=0;
vTaskDelay(900 / portTICK_RATE_MS);
}
}
Изменим системную функцию (в дальнейшем в проектах она должна выглядеть так)
uint32 user_rf_cal_sector_set(void)
{
flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 8;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
Изменим «функцию main», добавив задачи
void ICACHE_FLASH_ATTR user_init()
{
UART_SetBaudrate(UART0,BIT_RATE_115200);//изменяем скорость uart
UART_SetBaudrate(UART1,BIT_RATE_115200);//в FreeRTOS это так
os_printf("r\n");
os_printf("SDK version:%s\n", system_get_sdk_version());
os_printf("\r\n");
xTaskCreate(task1, "task1", 256, NULL, 1, NULL);
xTaskCreate(task2, "task2", 256, NULL, 1, NULL);
}
Сигнатура функции для добавления задач:
#define xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask)
Где: pvTaskCode- имя функции, которая вызывается в задаче
pcName — пользовательское имя функции
usStackDepth- глубина стека (в словах-uint32)
pvParameters — параметры, передаваемые в функцию
uxPriority- приоритет
pxCreatedTask -хендл созданной задачи
//———————————————————————-
В примере выше задачи 1 и 2 имеют одинаковый функционал и отличия только в номере задачи и делителе.
Можно использовать функции 1 задачи передавая в качестве параметров различия в 1 и 2 задачах.
Удалим тела 2-х задач и вместо них напишем:
typedef struct
{
unsigned char num_task;
unsigned short del;
} pData;
pData dt1, dt2;
//------------------------------------------------------
void ICACHE_FLASH_ATTR task1(void *pvParameters)
{
uint32 cnt=0;
pData *pdt = (pData*) pvParameters;
char str01[20];
while(1)
{
snprintf(str01, sizeof(str01), "Task%d: %7lu", pdt->num_task, cnt);
os_printf("%s\n", str01);
cnt++;
if(cnt>=10000000) cnt=0;
vTaskDelay(pdt->del / portTICK_RATE_MS);
}
}
В функции main вызовем эту задачу
void ICACHE_FLASH_ATTR user_init()
{
UART_SetBaudrate(UART0,BIT_RATE_115200);
UART_SetBaudrate(UART1,BIT_RATE_115200);
os_printf("r\n");
os_printf("SDK version:%s\n", system_get_sdk_version());
os_printf("\r\n");
dt1.del = 1000; dt1.num_task = 1; dt1.cnt=0;
dt2.del = 900; dt2.num_task = 2; dt2.cnt=0;
xTaskCreate(task1, "task1", 256, (void *) &dt1, 1, NULL);
xTaskCreate(task1, "task2", 256, (void *) &dt2, 1, NULL);
}
Как наглядно видно, физически на стеке выделяется место под 1 задачу и «параметры», что меньше чем 2 задачи и «параметры».
За счет передачи параметров мы избавляемся от дублирования части кода.