ESP32的简单使用——Freertso的实验(任务创建、互斥锁)

目录

一、原理和任务的简单介绍

  1.程序(Tasks之间数据传递)

  2.语法

  3.理解方法

二、程序运行

三、实验现象

四、拓展任务—多任务传参


一、原理和任务的简单介绍

  1.程序(Tasks之间数据传递)

  有多任务同时写入,或者数据大小超过cpu内存通道时,或者对共享资源的访问时候,需要有防范机制。资源共享时,多个任务对同一资源进行访问,写入和读出操作可能会发送冲突。
  使用MUTEX对数据对Cirtical Section的内容进行保护,可以想象成MUTEX就是一把锁,在对数据进行写入和读出操作时先进行上锁,再进行解锁,这样各个任务之间可以避免冲突(当然,也可以利用中断进行,后期介绍)

  2.语法

  SemaphoreHandle_t xHandler; 创建Handler
  xHandler = xSemaphoreCreateMutex(); 创建一个MUTEX 返回NULL,或者handler
  xSemaphoreGive(xHandler); 释放
  xSemaphoreTake(xHanlder, timeout); 指定时间内获取信号量 返回pdPASS, 或者pdFAIL

  3.理解方法

  MUTEX的工作原理可以想象成,共享的资源被锁在了一个箱子里,只有一把钥匙,有钥匙的任务才能对改资源进行访问。

二、程序运行

实验平台:ESP32 on Wokwi - Online ESP32, STM32, Arduino Simulator

  这里模拟售货机的操作,销售渠道分为线上和线下,这样在同一时刻会有多个任务对共享资源(存货量)进行访问和修改,这样互斥锁的作用就可见一斑。

直接上代码:

// 养成良好习惯,被多进程和中断调用的变量使用 volatile 修饰符
volatile uint32_t inventory = 100; //总库存
volatile uint32_t retailCount = 0; //线下销售量
volatile uint32_t onlineCount = 0; //线上销售量

SemaphoreHandle_t xMutexInventory = NULL; //创建信号量Handler

TickType_t timeOut = 1000; //用于获取信号量的Timeout 1000 ticks


void retailTask(void *pvParam) {
  while (1) {

    // 在timeout的时间内如果能够获取就继续
    // 通俗一些:获取钥匙
    if (xSemaphoreTake(xMutexInventory, timeOut) == pdPASS) {
      //被MUTEX保护的内容叫做 Critical Section


      //以下实现了带有随机延迟的 inventory减1;
      //等效为 inventory--; retailCount++;
      uint32_t inv = inventory;
      for (int i; i < random(10, 100); i++) vTaskDelay(pdMS_TO_TICKS(i));
      if (inventory > 0) {
        inventory = inv - 1;
        retailCount++;

        //释放钥匙
        xSemaphoreGive(xMutexInventory);
      } else {
        //无法获取钥匙
      }


    };

    vTaskDelay(100); //老板要求慢一些,客户升级后,可以再加快速度
  }
}
void onlineTask(void *pvParam) {
  while (1) {

    // 在timeout的时间内如果能够获取二进制信号量就继续
    // 通俗一些:获取钥匙
    if (xSemaphoreTake(xMutexInventory, timeOut) == pdPASS) {
      //被MUTEX保护的内容叫做 Critical Section
      //以下实现了带有随机延迟的 inventory减1;
      //等效为 inventory--; retailCount++;
      uint32_t inv = inventory;
      for (int i; i < random(10, 100); i++) vTaskDelay(pdMS_TO_TICKS(i));
      if (inventory > 0) {
        inventory = inv - 1;
        onlineCount++;

        //释放钥匙
        xSemaphoreGive(xMutexInventory);
      } else {
        //无法获取钥匙
      }
    };

    vTaskDelay(100); //老板要求慢一些,客户升级后,可以再加快速度
  }
}
void showTask(void *pvParam) {
  while (1) {

    printf("Inventory : %d\n", inventory);
    printf("  Retail : %d, Online : %d\n", retailCount, onlineCount);


    if (inventory == 0 ) {
      uint32_t totalSales = retailCount + onlineCount;
      printf("-----SALES SUMMARY-----\n");
      printf("  Total Sales:  %d\n", totalSales);
      printf("  OverSales:  %d\n", 100 - totalSales);
    }
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  xMutexInventory = xSemaphoreCreateMutex(); //创建MUTEX

  if (xMutexInventory == NULL) {
    printf("No Enough Ram, Unable to Create Semaphore.");
  } else {
    xTaskCreate(onlineTask,//任务
                "Online Channel",//任务名
                1024 * 4,//大小
                NULL,//传入参数
                1,//优先级
                NULL);//句柄
    xTaskCreate(retailTask,
                "Retail Channel",
                1024 * 4,
                NULL,
                1,
                NULL);
    xTaskCreate(showTask,
                "Display Inventory",
                1024 * 4,
                NULL,
                1,
                NULL);
  }

}
void loop() {
}

三、实验现象

四、拓展任务—多任务传参

typedef struct {
  byte pin;
  int delayTime;
} LEDFLASH;

/*
void ledFlash(void *pt) {
  LEDFLASH * ptLedFlash = (LEDFLASH *)pt;
  LEDFLASH led = *ptLedFlash;

  pinMode(led.pin,OUTPUT);
  while (1) {
    digitalWrite(led.pin, !digitalRead(led.pin));
    vTaskDelay(led.delayTime);
  }
}
*/

void ledFlash(void *pt) {
  LEDFLASH * ptLedFlash = (LEDFLASH *)pt;
  byte pin = ptLedFlash->pin;
  int delayTime = ptLedFlash->delayTime;

  pinMode(pin,OUTPUT);
  while (1) {
    digitalWrite(pin, !digitalRead(pin));
    vTaskDelay(delayTime);
  }
}
 
LEDFLASH led1, led2;//如果不是全局变量,setup执行完成后参数会被删除

void setup() {
  Serial.begin(9600);

 
  led1.pin = 23;
  led1.delayTime = 1000;
  led2.pin = 21;
  led2.delayTime = 3000;


if (xTaskCreate(ledFlash,
                  "FLASH LED",
                  1024,
                  (void *)&led1,
                  1,
                  NULL) == pdPASS)
    Serial.println("led1 flash task Created.");

if (xTaskCreate(ledFlash,
                  "FLASH LED",
                  1024,
                  (void *)&led2,
                  1,
                  NULL) == pdPASS)
    Serial.println("led2 flash task Created.");

}

void loop() {
}

欢迎大家交流和指正!!!

特别说明,本系列来源于b站@孤独的二进制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乱码小伙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值