Day2--使用ESP32双核、U8G2 OLED任务、任务以绝对频率运行、任务内存优化
创始人
2024-03-10 19:22:59
0

使用ESP32双核

ESP32-C系列为单核,ESP32的core0主要运行WI-FI和蓝牙

  API:

      xPortGetCoreID() 获取当前任务运行的核心

      xTaskCreate() 有系统选择运行核心,优先选择0

      xTaskCreatePinnedToCore() 指派任何给指定核心

Arduino的setup和loop默认运行在core1 

#include void taskA(void *ptParam)
{while (1){Serial.println(xPortGetCoreID()); // 获取当前任务运行的核心}
}void setup()
{// put your setup code here, to run once:Serial.begin(115200);xTaskCreatePinnedToCore(taskA, "Task A", 1024 * 4, NULL, 1, NULL, 0); // 最后一个参数为核心0
}void loop()
{
}

U8G2 OLED任务

 创建任务时使用空指针的原因,加快速度,可以接收任何类型的数据

注意事项,把U8G2相关的配置(初始化)写进任务中,不要写道setup中

#include 
#include void oledTask(void *pvParam)
{U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);u8g2.begin();for (;;){u8g2.clearBuffer();                    // clear the internal memoryu8g2.setFont(u8g2_font_ncenB08_tr);    // choose a suitable fontu8g2.drawStr(15, 10, "LONELY BINARY"); // write something to the internal memoryu8g2.sendBuffer();                     // transfer internal memory to the displayvTaskDelay(1000);}
}void setup()
{ // loopBack , Priority 1, Core 1xTaskCreatePinnedToCore(oledTask, "OLED Task", 1024 * 6, NULL, 1, NULL, 1);vTaskDelete(NULL); // 删除setup任务,节省内存空间
}void loop()
{
}

任务以绝对频率运行

实时操作系统要求必须在指定的时间内处理数据(比如每3秒显示一次数据,不能快,也不能慢)

vTaskDelayUntil函数比vTaskDelay函数定时精准,用处:周期性获取传感器数据(蓝牙发送数据)

vTaskDelayUntil函数比vTaskDelay函数多了一个记录任务本次被唤醒的时刻的变量,因此如果想要实现控制任务能够周期性运行的话,vTaskDelayUntil函数是一种比较简单的方法。

注意:LastWakeTime中保存的是上次唤醒时间,进入vTaskDelayUntil后会判断,如果上次唤醒时间大于当前时间,说明节拍计数器溢出了,就不在延时直接执行了。

  API:

    vTaskDelayUntil(&xLastWakeTime, xFrequency)

      最后一次的唤醒时间是指针类型。

      本函数会自动更新xLastWakeTime为最后一次唤醒的时间

      所以无需手动在while循环内对其手动赋值

    xTaskGetTickCount()

      TickCount和 Arduino Millis一样

      uint32_t类型 49天后overflow(溢出)

void showStockTask(void *ptParam)
{static float stockPrice = 99.57; //股票价格//最后一次唤醒的tick count,第一次使用需要赋值//以后此变量会由vTaskDelayUntil自动更新TickType_t xLastWakeTime = xTaskGetTickCount(); // 相当于millisconst TickType_t xFrequency = 3000; // 间隔 3000 ticks = 3 secondsfor (;;){//恰恰算算,经过思考,既然我们叫做LastWakeTime,那么 vTaskDelayUntil 应该放在循环的第一句话//如果放在循环的最后一句话,应该改为xLastSleepTime 才更加合适vTaskDelayUntil(&xLastWakeTime, xFrequency);//验证当前唤醒的时刻tick countSerial.println(xTaskGetTickCount());//验证xLastWake Time是否被vTaskDelayUntil更新// Serial.println(xLastWakeTime);// ------- 很复杂的交易股票计算,时间不定 ---------stockPrice = stockPrice * (1 + random(1, 20) / 100.0);vTaskDelay(random(500, 2000));Serial.print("Stock Price : $");Serial.println(stockPrice);//使用vTaskDelay试试看会如何// vTaskDelay(xFrequency);   // 测试结果显示,差距很大,时间不精确}
}void setup()
{Serial.begin(115200);xTaskCreate(showStockTask, "Show Stock Price", 1024 * 6, NULL, 1, NULL);
}void loop()
{
}

任务内存优化

变量在stack中

建立任务时会占用额外的内存空间,大概368 bytes 

如果有很多数据需要串口输出,单独创建一个task(例如蓝牙发送所有数据,其他任务通过多任务传参的方式把需要输出的数据发送给,打印输出task)

任务优先级

可以设置0~24之间的任意数字,0最小,24优先级最大

看门狗

防止死机,每一个CPU都有一只看门狗,ESP32有两个核心,所以有两只狗,看门狗是针对任务的,不是针对CPU,默认情况下在核心0有一只看门狗

队列单种数据(重要)

FIFO:first in first out

队列:queue,先进先出

队列是一种数据结构,可以包含一组固定大小的数据,在创建队列的同时,队列的长度和所包含数据类型的大小就确认下来了,一个队列可以有多个写入数据的任务和多个读取数据的任务。当一个任务试图从队列读取 数据的时候,它可以设置一个堵塞时间(block time)。这是当队列数据为空时,任务会进入阻塞状态的时间。当有数据在队列或者到达阻塞时间的时候,任务都会进入就绪状态。如果有多个任务同时在阻塞状态等待队列数据,优先级高的任务会在数据到达时进入就绪状态;在优先级相同的时候,等待时间长的任务会进入就绪状态。同理可以推及多个任务写入数据时候的运行状态。

使用步骤:

  1. 创建队列(设定队列长度,数据大小size)
  2. 往队列里发送数据
  3. 读取数据
  4. 案例:聊天室发信息

API:

    QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,

                             UBaseType_t uxItemSize );

    BaseType_t xQueueSend(

                            QueueHandle_t xQueue,

                            const void * pvItemToQueue,

                            TickType_t xTicksToWait

                         );

    BaseType_t xQueueReceive(

                               QueueHandle_t xQueue,

                               void *pvBuffer,

                               TickType_t xTicksToWait

                            );

队列多种数据(超级重要)

案例:通过队列+结构体的方式,将DHT22的温度和湿度数据在不同的任务间传输

创建队列:长度(可以放几个数据)、大小(每个数据的大小)

编程技巧:可以创建一个结构体类型,然后创建多个对象进行调用。

可以采用这种方法给上位机发送数据(把LCD显示部分的程序改为自己需要的数据)

/*程序:  消息队列公众号:孤独的二进制说明:本实例使用结构体巧妙的通过当个队列传输多个设备多种数据类型在接收方,我们通过deviceID来判断数据来源和value的意义API:QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,UBaseType_t uxItemSize );BaseType_t xQueueSend(QueueHandle_t xQueue,const void * pvItemToQueue,TickType_t xTicksToWait);BaseType_t xQueueReceive(QueueHandle_t xQueue,void *pvBuffer,TickType_t xTicksToWait);*/
#include "DHTesp.h"
#include 
LiquidCrystal_I2C lcd(0x27, 20, 4);
/*设备ID,共有2个设备*/
#define DHT22_ID 0 
#define LDR_ID 1typedef struct
{byte deviceID;float value1;float value2;
} SENSOR;QueueHandle_t queueSensor = xQueueCreate(8, sizeof(SENSOR)); // 长度8,采用sizeof自动计算需要的空间void dht22(void *ptParam)
{const byte dhtPin = 32;DHTesp dhtSensor;dhtSensor.setup(dhtPin, DHTesp::DHT22);SENSOR dht22Sensor;  // 创建一个结构体对象dht22Sensor.deviceID = DHT22_ID;while (1){TempAndHumidity data = dhtSensor.getTempAndHumidity();// Serial.println("Temp: " + String(data.temperature, 2) + "°C");// Serial.println("Humidity: " + String(data.humidity, 1) + "%");dht22Sensor.value1 = data.temperature;dht22Sensor.value2 = data.humidity;/*往队列里发送数据,如果队列数据是满的,等待2s,如果2s之后,队列还是满的,就放弃写操作*/// TickType_t timeOut = portMAX_DELAY;  不要用这个,时间为49天TickType_t timeOut = 2000;if (xQueueSend(queueSensor, &dht22Sensor, timeOut) != pdPASS){Serial.println("DHT22: Queue is full.");}vTaskDelay(1000); // 这个时间如果比较短,则队列很快就满了}
}void ldr(void *ptParam)
{const float GAMMA = 0.7;const float RL10 = 50;const byte ldrPIN = 27;pinMode(ldrPIN, INPUT);SENSOR ldrSensor;ldrSensor.deviceID = LDR_ID;while (1){int analogValue = analogRead(ldrPIN);float voltage = analogValue / 4095. * 5;float resistance = 2000 * voltage / (1 - voltage / 5);float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));// Serial.print("LDR Light Sensor lux : ");// Serial.println(lux);ldrSensor.value1 = lux;// ldrSensor.value2 = 0.0; 这条语句不要也行// TickType_t timeOut = portMAX_DELAY;TickType_t timeOut = 2000;if (xQueueSend(queueSensor, &ldrSensor, timeOut) != pdPASS){Serial.println("LDR: Queue is full.");}vTaskDelay(1000);}
}void lcdTask(void *ptParam)
{ // LCD任务主体lcd.init();lcd.backlight();lcd.setCursor(0, 0);lcd.print("   LONELY  BINARY  ");SENSOR data;  // while (1){// TickType_t timeOut = portMAX_DELAY;TickType_t timeOut = 2000;if (xQueueReceive(queueSensor, &data, timeOut) == pdPASS){switch (data.deviceID){case DHT22_ID:lcd.setCursor(0, 1);lcd.print("Temp: " + String(data.value1, 2) + "c");lcd.setCursor(0, 2);lcd.print("Humidity: " + String(data.value2, 1) + "%");break;case LDR_ID:lcd.setCursor(0, 3);if (data.value1 > 50){lcd.print("Bright ");}else{lcd.print("Dark ");}// lcd.setCursor(0, 3);lcd.print(String(data.value1, 2) + " lux");break;default:Serial.println("LCD: Unkown Device");break;}}else{Serial.println("LCD: Message Queue is Empty");};vTaskDelay(2000);}
}void setup()
{Serial.begin(115200);xTaskCreate(dht22, "DHT22", 1024 * 4, NULL, 1, NULL);xTaskCreate(ldr, "LDR LIGHT", 1024 * 4, NULL, 1, NULL);xTaskCreate(lcdTask, "lcd", 1024 * 8, NULL, 1, NULL);
}void loop() {}

相关内容

热门资讯

婚礼男方家长致辞 婚礼男方家长致辞通用15篇  无论在学习、工作或是生活中,大家都不可避免地会接触到致辞吧,致辞具有“...
学校班级元旦晚会主持稿 学校班级元旦晚会主持稿  导语:在学校召开元旦晚会的时候,通常要用到主持词的。接下来小编整理了学校班...
新郎迎娶新娘主持词 新郎迎娶新娘是一生中最浪漫的事情之一,那么都有什么好的主持词呢?以下是PINCAI小编整理的关于主持...
公司员工大会主持稿 公司员工大会主持稿  在现在的社会生活中,需要使用主持稿的情况越来越多,主持稿一般是由主持人根据场景...
开业的致辞 开业的致辞15篇  在日常的学习、工作、生活中,大家都对致辞很是熟悉吧,致辞是指在举行会议或某种仪式...
毕业聚餐主持词 毕业聚餐主持词  主持词是主持人在节目进行过程中用于串联节目的串联词。在当今中国社会,主持人在活动中...
女娲传说之灵珠经典台词 女娲传说之灵珠经典台词15句  你们根本不懂爱,你们的爱太过自私,不择手段。——仙乐  你放心,我不...
青春演讲比赛主持词 青春演讲比赛主持词  主持:  男——李勇  女——张雨  女:我与祖国共奋进男:我为崛起献青春。 ...
年会赞助商致辞 年会赞助商致辞(精选5篇)  在日常的学习、工作、生活中,要用到致辞的情况还是蛮多的,致辞具有很强的...
培训会主持词 培训会主持词(精选10篇)  在日常中,大家总免不了要培训及会议吧,那么你知道主持词怎么写吗?下面是...
电影《三少爷的剑》经典台词 电影《三少爷的剑》经典台词精选  1. 冷风如刀,大地荒漠,苍天无情。  2. 这世上永远有两种人,...
《十六个夏天》的经典台词 《十六个夏天》的经典台词大全  1.就说我不是他的收藏品,乱说什么啊!  2.说话冲的人,心里都是软...
80岁生日宴会致辞 80岁生日宴会致辞(精选11篇)  在学习、工作或生活中,大家都不可避免地会接触到致辞吧,致辞具有有...
婚宴长辈证婚人致辞 婚宴长辈证婚人致辞  在平日的学习、工作和生活里,大家总少不了要接触或使用致辞吧,致辞受场合、事件的...
元旦舞会主持词 元旦舞会主持词(精选7篇)  主持词要尽量增加文化内涵、寓教于乐,不断提高观众的文化知识和素养。在人...
圣诞联欢会主持词 圣诞联欢会主持词  活动对象的不同,主持词的写作风格也会大不一样。时代不断在进步,主持成为很多活动不...
美好童年—庆“六一”大型活动... 美好童年—庆“六一”大型活动主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。随着...
毕业晚会主持词串词 毕业晚会主持词串词  毕业,是人生的一个转折点,愿你们能展开双翼,飞得更高、看得更远。下面是小编给大...
运动会致辞 运动会致辞(精选5篇)  无论在学习、工作或是生活中,大家或多或少都用到过致辞吧,致辞要求风格的雅、...
六一儿童节的主持稿 六一儿童节的主持稿(精选8篇)  随着社会一步步向前发展,我们都不可避免地要接触到主持稿,主持稿是主...