3【ESP32_freeRTOS学习笔记】

常用API

esp_get_free_heap_size()//获取空闲堆内存

任务状态
运行:当任务实际执行时,它被称为处于运行状态。任务当前正在使用处理器;
就绪:能够执行但目前未执行的任务,因为同等或更高优先级的不同任务正在执行;
阻塞:正在等待时间或外部事件。例如一个任务调用vTaskDelay(),它将被阻塞;
挂起:与“阻塞”状态下的任务一样, “挂起”状态下的任务不能 被选择进入运行状态,但处于挂起状态的任务 没有超时。 相反,任务只有在分别通过 vTaskSuspend() 和 xTaskResume() API 调用明确命令时 才会进入或退出挂起状态
在这里插入图片描述
低优先级数字表示低优先级任务。 空闲任务的优先级为零 (tskIDLE_PRIORITY)。被置于运行状态的任务 始终是可运行的最高优先级任务。
FreeRTOS 默认使用固定优先级的抢占式 调度策略,对同等优先级的任务执行时间片轮询调度:

1.Task相关

1.系统启动流程

  • 各函数调用关系

freeRTOS相关
app_main -> main_task -> esp_startup_start_app_common -> esp_startup_start_app ->
(esp_system文件中)
start_cpu0_default -> start_cpu0(硬件相关的初始化) -> g_startup_fn(可调用不同CPU初始化程序) -> SYS_STARTUP_FN()(宏定义) -> call_start_cpu0(或者其他内核) -> /* Default entry point: */ENTRY(call_start_cpu0);(esp32设计的入口,对硬件初始化,创建主task,进行任务调度)

2.创建 删除任务

创建任务

task. h

 BaseType_t xTaskCreate(    TaskFunction_t pvTaskCode, //指向该任务函数的指针
                            const char * const pcName, //函数名,字符串格式
                            configSTACK_DEPTH_TYPE usStackDepth, //堆栈可以容纳的字数
                            void *pvParameters, //传入该任务函数的形参,没有则为NULL
                            UBaseType_t uxPriority, //该任务优先级,数字越大优先级越高,0为空闲任务,最高( 25 )
                            TaskHandle_t *pxCreatedTask //该任务函数的句柄,可用以后续删除任务等操作
                          );
//example
//********创建任务
void myTask(void *pvParam) 
{
    while (1){
        printf("hello");
        vTaskDelay(10000 / portTICK_RATE_MS);
    }
}
void app_main(void *param){
	xTaskCreate(myTask, "myTask", 1024, NULL, 1, NULL);  //创建任务
}
//*******删除任务法1:利用句柄
void app_main(void *param){
	TaskHandle_t myTaskHandle=NULL;
	xTaskCreate(myTask, "myTask", 1024, NULL, 1, &myTaskHandle); //创建任务
	vTaskDelay(10000 / portTICK_RATE_MS); //延时一秒再删除,否则刚创建就被删除,无现象。
	if(myTaskHandle != NULL){
	vTaskDelete(myTaskHandle);
}
//********创建任务
//*******删除任务法2:在任务函数里自己删除自己
void myTask(void *pvParam) 
{
    while (1){
        printf("hello");
        vTaskDelay(10000 / portTICK_RATE_MS);
        vTaskDelete(NULL); //创建任务时句柄形参为NULL
}
void app_main(void *param){
	xTaskCreate(myTask, "myTask", 1024, NULL, 1, NULL);  //创建任务
}

3.Task参数

//将结构体类型的变量传递给Task
typydef struct A_STRUCT
{
int i=1;
int j=1;
}xStruct;
xStruct xStrTest={6,9};

void myTask(void *pvParam) 
{
	xStruct *pStrTest;
	pStrTest=(xStruct *)pvParam;
	printf("i=%d\n",pStrTest->i);
	printf("j=%d\n",pStrTest->j);
	vTaskDelay(10000 / portTICK_RATE_MS);
    vTaskDelete(NULL); //创建任务时句柄形参为NULL
}
void app_main(void *param){
	xTaskCreate(myTask, "myTask", 1024,(void *)&xStrTest, 1, NULL);  //创建任务
}

4.Task优先级别

优先级别:0-25,数字越大级别越高;

  • 取得优先级别的接口:UBaseType_t uxTaskPriorityGet( TaskHandle_t pxTask );
void myTask(void *pvParam) 
{
	xStruct *pStrTest;
	pStrTest=(xStruct *)pvParam;
	printf("i=%d\n",pStrTest->i);
	printf("j=%d\n",pStrTest->j);
	vTaskDelay(10000 / portTICK_RATE_MS);
    vTaskDelete(NULL); //创建任务时句柄形参为NULL
}
void app_main(void *param){
	UBaseType_t iPriority=0;
	TaskHandle_t pxTask = NULL;
	xTaskCreate(myTask, "myTask", 1024,(void *)&xStrTest, 24, NULL);  //创建任务
	iPriority = uxTaskPriorityGet(pxTask);
}
  • Same Priority
    创建任务后,顺序运行,切换相同的时间片

  • 设置优先级别的接口:void vTaskPrioritySet( TaskHandle_t pxTask, UBaseType_t uxNewPriority );

5.Task挂起和恢复

可任务内部挂起(任务句柄为NULL)或外部挂起;
void vTaskSuspend( TaskHandle_t pxTaskToSuspend );
void vTaskResume( TaskHandle_t pxTaskToResume );
void vTaskSuspendAll( void ); //只运行当前任务,调度器被挂起,freeRTOS API都不可被调用
BaseType_t xTaskResumeAll( void );
void vTaskList( char *pcWriteBuffer ); // 打印所有任务的情况(状态 堆栈 优先级……)//可能已经被弃用了。。

6.Task堆栈

//用以确定某任务剩余的堆栈,返回值越接近0则任务越接近溢出,以确定创建任务时合适的堆栈
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
  • 单位换算:
    1B(字节)=8b(位)
    1 KB = 1024 B
    1 MB = 1024 KB
    1 GB = 1024 MB
    1TB = 1024GB

7.Task看门狗

  • 以下task一卡直在while(1)的死循环里,导致无法执行空闲任务idle1,会触发Task看门狗
void myTask(void *pvParam) 
{
	while(1)
	{
		;
		//printf("task1");
		//vTaskDelay(10000 / portTICK_RATE_MS);
	}
}
void app_main(void *param){
	xTaskCreate(myTask, "myTask", 1024,NULL,1, NULL);  //创建任务
}
  • 解决措施:
  1. 加阻塞函数例如延时,可阻塞当前任务的运行,使得调度器可以调度低优先级的任务,可以去喂狗;
  2. 将优先级改为0 ,该任务和空闲任务有相同的时间片,空闲任务得以运行。

2.Queue相关

//头文件
#include "FreeRTOS.h"
#include “queue.h”
QueueHandle_t xQueueCreate( 
UBaseType_t uxQueueLength,  //队列长度
UBaseType_t uxItemSize );
//发数据到队列
BaseType_t xQueueSend( QueueHandle_t xQueue, 
const void * pvItemToQueue, 
TickType_t xTicksToWait );
  • 多入单出:
    在这里插入图片描述

Queue Set

问题:Queue Set里各队列数据类型不一致如何处理?
在这里插入图片描述

Queue Mailbox

  • 单入多出
    在这里插入图片描述

Software Timer

  • Software Timer与硬件、平台无关,均使用相同的命定调用软件定时器
  • Software Timer和硬件定时器数量有限制不同,可以通过配置很多个~
#include “FreeRTOS.h”
#include “timers.h”
//创建定时器
TimerHandle_t xTimerCreate( const char *pcTimerName,  //定时器名称
 const TickType_t xTimerPeriod,  //周期
 const UBaseType_t uxAutoReload, //是否多次执行
 void * const pvTimerID, //ID
 TimerCallbackFunction_t pxCallbackFunction ) //回调函数
//启动定时器
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
//停止定时器
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );
//获取定时器name
const char * pcTimerGetName( TimerHandle_t xTimer );
//获取定时器ID
void *pvTimerGetTimerID( TimerHandle_t xTimer );

信号量

就像信号灯控制汽车一样,信号量可以控制任务。当没有信号量时,两个优先级相同的任务有相同的时间片,轮番执行;而加入信号量控制,可以使得第一个任务执行完之后再执行第二个任务。

#include “FreeRTOS.h”
#include “semphr.h”

二进制信号量

//1.创建信号量
SemaphoreHandle_t xSemaphoreCreateBinary( void );
//2.释放信号量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
//以下在任务函数中
//3.获取信号量
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait )
//4.释放信号量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

计数型信号量

//1.创建信号量
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount );
//2.释放信号量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
//以下在任务函数中
//3.返回信号量的计数
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
//4.获取信号量
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait )(信号量--)
//5.释放信号量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );(信号量++)
//example——main.c
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "freertos/semphr.h"

SemaphoreHandle_t xSemaphoreCountHandle;
void taskCarin(void *pvParam)
{
    int emptyCou=0;
    BaseType_t result;
    while(1)
    {
        emptyCou = uxSemaphoreGetCount(xSemaphoreCountHandle);
        printf("emptyCou:%d\n",emptyCou);
        result = xSemaphoreTake(xSemaphoreCountHandle, 0);
        if (result == pdPASS)
        {
            printf("one car in\n");
        }
        else
        {
            printf("no space\n");
        } 
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void taskCarout(void *pvParam)
{
    while (1)
    {
        vTaskDelay(pdMS_TO_TICKS(6000));
    xSemaphoreGive( xSemaphoreCountHandle);
    printf("one car out\n");
    }
}

void app_main(void )
{
    xSemaphoreCountHandle = xSemaphoreCreateCounting(5, 5);
    // xSemaphoreGive( xSemaphoreCountHandle);

    xTaskCreate(taskCarin,"taskCarin",5*1024,NULL,1,NULL);
    xTaskCreate(taskCarout,"taskCarout",5*1024,NULL,1,NULL);
}

在这里插入图片描述

Mutex 互斥量

从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放锁。 一个线程占有一个互斥量以后,不允许其他线程继续占有这个互斥量。 其他试图访问这个互斥量的线程会被阻塞住。 直到占有互斥量的线程主动解锁。

递归互斥量在这里插入图片描述

事件组

#include “FreeRTOS.h”
#include “event_groups.h”
//main 中创建group
EventGroupHandle_t xEventGroupCreate( void );
//设置对应位的值
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet )
//task1等待对应位的设置后再解除阻塞
EventBits_t xEventGroupWaitBits( const EventGroupHandle_t xEventGroup,
 const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAll)
//task2中设置对应位后task1就解除阻塞
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
 const EventBits_t uxBitsToSet );

xEventGroupWaitBits事件组等待 和xEventGroupSync时间组同步的区别

  • 事件组等待
    task2 3在设置后能继续运行
    在这里插入图片描述
  • 事件组同步
    会等待需要同步的任务设置后再一起运行
    在这里插入图片描述

EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
 const EventBits_t uxBitsToSet,
 const EventBits_t uxBitsToWaitFor,
 TickType_t xTicksToWait );

消息通知

可以控制任务阻塞与解除阻塞。

/* Prototypes of the two tasks created by main(). */
static void prvTask1( void *pvParameters );
static void prvTask2( void *pvParameters );
/* Handles for the tasks create by main(). */
static TaskHandle_t xTask1 = NULL, xTask2 = NULL;
/* Create two tasks that send notifications back and forth to each other, then
start the RTOS scheduler. */
void main( void )
{
 xTaskCreate( prvTask1, "Task1", 200, NULL, tskIDLE_PRIORITY, &xTask1 );
 xTaskCreate( prvTask2, "Task2", 200, NULL, tskIDLE_PRIORITY, &xTask2 );
 vTaskStartScheduler();
}
/*-----------------------------------------------------------*/
static void prvTask1( void *pvParameters )
{
 for( ;; )
 {
 /* Send a notification to prvTask2(), bringing it out of the Blocked
 state. */
 xTaskNotifyGive( xTask2 ); //通知task2可以解除阻塞了
 }
}
/*-----------------------------------------------------------*/
static void prvTask2( void *pvParameters )
{
 for( ;; )
 {
 /* Block to wait for prvTask1() to notify this task. */
 ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); //阻塞,等待通知后再接触阻塞
 }
}
//根据每一位的设定值处理不同的工作
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
 uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
//例如
void vAnEventProcessingTask( void *pvParameters )
{
uint32_t ulNotifiedValue;
 for( ;; )
 {
 xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
 ULONG_MAX, /* Reset the notification value to 0 on exit. */
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
 portMAX_DELAY ); /* Block indefinitely. */
 /* Process any events that have been latched in the notified value. */
 if( ( ulNotifiedValue & 0x01 ) != 0 )
 {
 /* Bit 0 was set - process whichever event is represented by bit 0. */
 prvProcessBit0Event();
 }
 if( ( ulNotifiedValue & 0x02 ) != 0 )
 {
 /* Bit 1 was set - process whichever event is represented by bit 1. */
 prvProcessBit1Event();
 }
 if( ( ulNotifiedValue & 0x04 ) != 0 )
 {
 /* Bit 2 was set - process whichever event is represented by bit 2. */
 prvProcessBit2Event();
 }
 /* Etc. */
 }
}

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
/* Set the notification value of the task referenced by xTask3Handle to 0x50,
even if the task had not read its previous notification value. */
//参数eAction 一般取 - eSetBits –,例如:
/* Set bit 8 in the notification value of the task referenced by xTask1Handle. */
xTaskNotify( xTask1Handle, ( 1UL << 8UL ), eSetBits );

流数据StreamBuffer

在这里插入图片描述

#include “FreeRTOS.h”
#include “stream_buffer.h”
\\创建数据流
\\xTriggerLevelBytes表示在达到这么多个数据前一直会阻塞
StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes,size_t xTriggerLevelBytes )
 \\task1里发送数据
 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
 const void *pvTxData,
size_t xDataLengthBytes,
TickType_t xTicksToWait )
\\task2里接收数据
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
 void *pvRxData,
size_t xBufferLengthBytes,
TickType_t xTicksToWait );

确定流数据缓冲区的大小

xStreamBufferSpacesAvailable() //获取某个流数据剩余可用空间的大小,以便合理设置流数据的大小

Message Buffer消息缓冲区

与流缓冲区的区别:

  1. 区别1
    消息缓冲区:可以从缓冲区取出一条完整的数据;
    流数据缓冲区:只要流缓冲区中有足够的数据,接收缓冲区足够大,会把缓冲区中的所有数据取出来
  2. 区别2
    当接收buffer的大小小于一条meaasge的大小时,
    流数据缓冲区:能接收设定大小的数据,直至接收完成。
    在这里插入图片描述
    消息缓冲区:不能接收数据,接收的内容为空,返回为0。
    在这里插入图片描述

JTAG

在这里插入图片描述
或者把Adapter集成到芯片
在这里插入图片描述

open ocd最初源于05年的毕业论文,设计思想如下:
在这里插入图片描述

WIFI

在这里插入图片描述

  • 三层架构及函数关系
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值