05-2_创建任务函数的进一步实验

  • 创建的任务传入handle,之后通过handle引用任务或者删除任务。
  • 空闲任务释放堆和栈
  • 同一个函数可以创建不同的任务,因为他们对应的栈不同,每个任务有自己的栈,互不影响
  • 如何确定任务需要多大的栈空间需要你研究

直播四小时讲解栈

  • 任务--定义
    • 运行起来的函数
    • 不仅仅是一个函数或者代码,
    • 运行的位置
    • 运行的环境
  • arm架构汇编
    • Flash中存取着指令和汇编码
    • cpu读Flash得到指令,然后再执行指令
    • SP就是指的栈
    • LR表示返回地址
    • PC表示当前指令地址
  • CPU虽然强大,但是还是要靠指令取指挥他,指令保存在Flash上,即机器码
    • 由汇编码得到机器码
  • PUSH入栈,入栈的本质就是写内存
  • POP是读内存
  • 硬件中断
    • 硬件保存一部分reg
    • 软件要保存一部分用到的reg
  • 任务切换中是保存全部reg
  • 句柄---结构体指针
  • 每个任务都有自己的栈
    • 栈的大小依赖
      • 局部变量
      • 调用深度
    • 栈的分配
      • FreeRTOS划分出一个巨大的数组给栈分配
  • 高优先级不执行完,低优先级任务永远无法执行
  • 同等优先级任务轮流执行:时间片轮转
  • TICK中断进行任务调度
    • 间隔可以配置,一般为1ms
    • 产生中断就调用tick中断函数
      • 取出下一个任务
      • 切换任务
        • 保存当前任务
        • 回复新Task
  • 同是0优先级,空闲任务会礼让其他任务

06-1_任务状态理论讲解

06-3_vTaskDelay和vTaskDelayUntil

  • vTaskDelay是任务暂停的时间是固定的
  • vTaskDelayUntil让任务周期性执行,总的运行暂停时长是固定的

自杀与他杀

  • 自杀不能清理尸体,需要空闲任务清理并释放栈
  • 他杀,凶手处理尸体,释放栈
  • 空闲任务只能是running或者ready状态

任务调度算法

  • 时间片轮转可以配置
  • 是否支持抢占也可以配置
  • 空闲任务是否yield别人

同步与互斥

  • 同步比较浪费CPU资源
    • 再等待的时候让当前任务进入阻塞状态
  • 全局变量实现互斥的变量切换时间太长了

08-1_队列的理论讲解

  • 队列---传送带
  • 队列要有存放数据的缓冲区
    • 指针就是buffer
  • 等待数据的写入(没有空间)和读取(没有数据)
  • 优先级高的先读取
  • 同优先级等待时间长的先读取

08-2_队列的常规使用

  • 队列实现同步,读取数据,最后一千万计数为1.3s
  • 队列可以理解为一个容器,你放进去东西,别人能取到东西,就代表能使用,取不到东西就代表不能使用
  • 释放这个队列就把东西放到这个容器里,让别人能取到。
  • 创建队列可以指定
    • 多少个元素
    • 每个元素的大小
  • 队列实现互斥
    • 向你创建的互斥队列中写入数据
    • 读取到数据就代表获取了这个东西,不需要考虑写入了啥数据
    • task1是ready,但是task2是running
      • 可以通过vTaskDelay让task2主动放弃
      • 或者通过taskYIELD(),这个更优
      • 或者设置不同的优先级
  • 传输的时候可以选择结构体struct加入ID,然后区分数据源谁传入的。
  • 数据量过大直接传输地址最快。
  • 队列中可以传入数据,数据要么是值要么是地址

08-3_队列集(Queue Set)

  • 队列集中放的是队列,每个队列中放的是其分组的数据。

  • 队列集实际上也是个队列。

  • 每个队列的handle指向队列集。

  • 读一次queue set,就会读一次queue

  • 例子

    static QueueHandle_t xQueueHandle1;
    static QueueHandle_t xQueueHandle2;
    static QueueSetHandle_t QueueSet;
    
    /*-----------------------------------------------------------*/
    void xTask1Function(void * param)
    {
        int i = 0;
    
        while(1)
        {
            xQueueSend(xQueueHandle1, &i, portMAX_DELAY);
            i++;
            vTaskDelay(10);
        }
    }
    /*-----------------------------------------------------------*/
    void xTask2Function(void * param)
    {
        int i = -1;
        while(1)
        {
            xQueueSend(xQueueHandle2, &i, portMAX_DELAY);
            i--;
            vTaskDelay(20);
        }
    }
    /*-----------------------------------------------------------*/
    void xTask3Function(void * param)
    {
        QueueSetMemberHandle_t handle;
        int i;
        while(1)
        {
            /* 1. read queue set: which queue has data */
            handle = xQueueSelectFromSet(xQueueSet1, portMAX_DELAY);
            /* 2. read queue */
            xQueueReceive(handle, &i, 0);
            /* 3. print */
            printf("get data : %d\r\n", i);
        }
    }
    /*-----------------------------------------------------------*/
    
    int main( void )
    {
    
    #ifdef DEBUG
      debug();
    #endif
    
        prvSetupHardware();
        /* 1. 创建2个queue */
        xQueueHandle1 = xQueueCreate(2, sizeof(int));
        if(xQueueHandle1)
        {
            printf("create queue1 fail\r\n");
        }else
        {
        }
        xQueueHandle2 = xQueueCreate(2, sizeof(int));
        if(xQueueHandle2)
        {
            printf("create queue2 fail\r\n");
        }else
        {
        }
        /* 2. 创建queue set */
        xQueueSet1 = xQueueCreateSet(4);
        /* 3. 把2个queue添加进queue set */
        xQueueAddToSet(xQueueHandle1, xQueueSet1);
        xQueueAddToSet(xQueueHandle2, xQueueSet1);
        /* 4. 创建三个任务 */
        xTaskCreate(xTask1Function, "Task 1", 100, NULL, 1, NULL);
        xTaskCreate(xTask2Function, "Task 2", 100, NULL, 1, NULL);
        xTaskCreate(xTask3Function, "Task 3", 100, NULL, 1, NULL);
    
    
        /* 启用任务调度器 */
        vTaskStartScheduler();
    
    	/* Will only get here if there was not enough heap space to create the
    	idle task. */
    	return 0;
    }
    
    
  • 队列集能让你统筹的管理队列,不用一个个的去处理每个队列。让你能随时从每个队列中获取数据,同一件事情的不同处理方式,那个方式输入进来,相应那个方式。

09-1_信号量的理论讲解

  • 信号量不能传输数值,只能表示资源的数量。
  • 信号量为正数,且能限制最大值
  • 步骤
    • 创建一个结构体Semaphpre
    • give/take函数构建
  • 二进制信号量和技术型信号量
posted on 2024-11-25 14:46  明图  阅读(34)  评论(0)    收藏  举报