1、RTOS简介
实时操作系统又称为即时操作系统,会按照排序运行、管理系统资源,并为开发应用程序提供一致的基础。它与一般的操作系统相比,最大的好处就是“实时性”,而实时操作系统中都要包含一个实时任务调度器,这个任务调度器与其他操作系统的最大不同是强调:严格按照优先级来分配CPU,优先级最高的任务也是优先抢占到CPU并执行。
2、Arduino环境配置
2.1 库的安装
在IDE中我们需要安装多个库并且进行一系列的配置,下面是该项目中需要安装的各种类型的库,包括LVGL,TFT,AHT10等;
2.2 参数配置
在库安装完毕后,我们需要对库里面的头文件进行配置,首先在文件管理器中打开->文档->Arduino->libraries->TFT_eSPI->User_Setup.h,打开之后需要把文件改成下列,因为我使用的是Esp32C3与0.96寸LCD屏+AHT10。如果使用其他的开发板,则可以按照下面进行修改;
到这里我们关于IDE的搭建已经完成了!
3、合宙esp32
3.1 合宙esp32管脚定义
因为该项目中esp32管脚占用较多,所以后面会出现无法对接AHT10,0.96寸LCD屏有上、下、左、右、中四个按键。因为左、右用不到,所以这里我把左右两个按键给扣除,作为AHT10的SDA与SCL,大家可以自行进行测试。
2.2 合宙esp32 原理图
具体关于esp32c3的开发板介绍可以在官网进行查阅
合宙Esp32C3https://wiki.luatos.com/chips/esp32c3/board.html
4、AHT10温湿度传感器
4.1 AHT10温湿度传感器外观
4.2 AHT10与Esp32C3连接
AHT10与Esp32C3电路图如下图所示
连接完之后我们需要在Arduino中进行测试,测试之前需要下载相应的库,如下图所示
然后我们在Arduino中,点击上方栏文件->示例->Adafruit AHTX0(我们刚刚安装的库)->adafruit_aht_test,打开之后是下面的文件,注意要加上这句话,代表AHT10传感器SDA与SCL与Esp32C3连接的管脚。
然后我们可以使用数据线进行测试,编译(IDE中左上角的√),编译完成后进行上传,可以看到在我们的串口监视器中检测到了温度。如果串口没有输出,可以在IDE上栏->工具查看相应配置是否正确,波特率等。
5、LCD与ESP32连接
LCD屏与ESP32进行对接即可,但需要注意LCD按钮与ESP32的Type-c口在同一侧,如果插反了然后下载程序,则会导致USB口对应的驱动不能使用,这时候我们需要对板子进行清除flash,具体擦除flash的工具,乐鑫官网都有,可以自行下载
对于擦除flash的方法,可以参考
6、测试与验证
LVGL_Task.ino这是Ardiuno工程文件,里面主要有RTOS的四个任务按优先级来进行执行
#include "aita.h"
/**
全局量定义
*/
// 互斥量定义——保护lvgl线程
SemaphoreHandle_t lvgl_mutex;
SemaphoreHandle_t minute_sem;
AITA_WEATHER_T aita_weather;
AITA_TEMHUM_T aita_temhum;
/**
函数声明
*/
void secPollingTask(void *pvParameters);
void lvglTask(void *pvParameters);
void weatherTask(void *pvParameters); //天气任务函数定义
void temhumTask(void *pvParameters); //温湿度任务函数定义
void initSysModule(void);
void setup() {
// 板级初始化——LED和Serial
initBsp();
Serial.print("ARDUINO_RUNNING_CORE: ");
Serial.println(ARDUINO_RUNNING_CORE);
// 连接Wi-Fi
initNetwork();
// 网络授时
initLocalTime();
delay(1000);
printLocalTime();
// 初始化秒级定时器
initTimer();
// 初始请求一次天气
aita_weather = getWeather();
// 初始化GUI
initLVGL();
// 显示主界面
createMainUI();
// 初始化系统模块
initSysModule();
Serial.println("setup() done");
}
void loop() {
// Empty. Things are done in Tasks.
/**
setup()、loop()实际包含在优先级1的起始任务
当前任务结构中,其优先级最低
可以根据需要放置一些低实时性代码
*/
}
/**
相关函数定义
*/
// 秒级轮询任务函数定义
void secPollingTask(void *pvParameters) {
(void) pvParameters;
// 由sec_timer提供信号量唤醒,以实现本地计时维护
for(;;) {
if(xSemaphoreTake(sec_timersem, 0) == pdTRUE) {
getLocalTime(&now);
if(now.tm_sec == 0) {
printLocalTime();
xSemaphoreGive(minute_sem);
}
if(ui_state == TIMEUI) {
if(xSemaphoreTake(lvgl_mutex, 0) == pdPASS) {
freshTime();
xSemaphoreGive(lvgl_mutex);