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() {}

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...