2023寒假一起练平台(5)—— 基于ESP32-S2模块实现加热和温度采集系统
在该项目中,我实现了一个加热和温度采集系统。该系统使用PWM控制电阻发热功率,并用温度传感器采集温度信息,并显示在TFT屏上。此外,我还用到了ESP32-S2中的wifi功能,可以将TFT屏的图像上传到自己的笔记本电脑中。
标签
嵌入式系统
显示
接口
2023寒假在家练
aezakmi
更新2023-03-27
北京理工大学
508

一、项目介绍

   在该项目中,我基于ESP32-S2模块,设计了一个可实现加热和温度采集系统:

   (1). IO扩展板上有一处加温电阻,通过电流给电阻加热,并通过温度传感器电阻温度的变化,将测量到的温度信息显示在LCD屏幕上,绘制一个1分钟的温升曲线。并且每隔1分钟改变加热电阻两端电压的占空比,重复温度测量和绘制的过程。

   (2). 扩展版上还有一个按键,按下按键时,可以将显示屏截屏并将图像发送至上位机。

   (3). 板上有一处RGB彩灯,当温度超过50°C时转为红色,低于20°C时转为蓝色,在20°C和50°C之间时为绿色。

   除此之外,我还基于ESP32-S2的一些特点,对部分功能进行了拓展:

   (1). 对于利用PWM调节加热电阻的发热功率,PWM的数值除了每分钟变更一次以外,我还加入了特定代码,允许通过按下开发板上的另一按键,直接手动变更PWM的数值。

   (2). 对于截屏,当ESP32-S2完成截屏,生成图像数据后,通过WIFI功能,利用udp协议将数据发送至上位机,而在上位机上也有一特定的程序,可以接收图像数据,并生成png格式的图像文件保存下来。

二、设计思路

1、硬件简介及设计思路

   该项目提供了一个ESP32-S2 WIFI开发板,一个IO拓展板,一个Type-C数据线,和两根杜邦线。其中,ESP32-S2 WIFI开发板有多个GPIO引脚,且支持包括micropython,arduino在内的多种开发方式。IO拓展板上有TFT显示屏,温度传感器,按钮等多个元件,将ESP32开发板插在IO拓展板上,即可通过ESP32开发板控制拓展板上的元件工作。Type-C数据线可用于ESP32开发板与上位机之间的交互。

   硬件部分的设计思路相对来说比较简单。直接将ESP32-S2 WIFI开发板插在IO拓展板上,并用杜邦线将控制拓展板电阻的V_HEAT引脚和与ESP32开发板相连的任一空闲的引脚连接即可。我这里选择的是CA-PWD引脚。即将拓展板上部一排引脚中的第2个引脚(CA-PWD),与拓展板左部的第4排,第2列的引脚(V_HEAT)连接即可。

 

bw2Tjj632msfgWifo90pT057x6oz79P6526qH7RUxMXFITk5GV6vFxQcDFXtzD639c6SyGgrOR0nAiIgAiIgAiLQLAGJDE0QERABERABERABRwhIZDiCVY2KgAiIgAiIgAhIZGgOiIAIiIAIiIAIOEJAIsMRrGpUBERABERABERAIkNzQAREQAREQAREwBECEhmOYFWjIiACIiACIiACEhmaAyIgAiIgAiIgAo4QkMhwBKsaFQEREAEREAERkMjQHBABERABERABEXCEgESGI1jVqAiIgAiIgAiIgESG5oAIiIAIiIAIiIAjBCQyHMGqRkVABERABERABCQyNAdEQAREQAREQAQcISCR4QhWNSoCIiACIiACIiCRoTkgAiIgAiIgAiLgCAGJDEewqlEREAEREAEREAGJDM0BERABERABERABRwhIZDiCVY2KgAiIgAiIgAhIZGgOiIAIiIAIiIAIOEJAIsMRrGpUBERABERABERAIkNzQAREQAREQAREwBECEhmOYFWjIiACIiACIiACEhmaAyIgAiIgAiIgAo4QkMhwBKsaFQEREAEREAERkMjQHBABERABERABEXCEgESGI1jVqAiIgAiIgAiIgESG5oAIiIAIiIAIiIAjBCQyHMGqRkVABERABERABCQyNAdEQAREQAREQAQcISCR4QhWNSoCIiACIiACIiCRoTkgAiIgAiIgAiLgCAGJDEewqlEREAEREAEREAGJDM0BERABERABERABRwhIZDiCVY2KgAiIgAiIgAhIZGgOiIAIiIAIiIAIOEJAIsMRrGpUBERABERABERAIkNzQAREQAREQAREwBECEhmOYFWjIiACIiACIiACEhmaAyIgAiIgAiIgAo4QkMhwBKsaFQEREAEREAERkMjQHBABERABERABEXCEgESGI1jVqAiIgAiIgAiIgESG5oAIiIAIiIAIiIAjBCQyHMGqRkVABERABERABCQyNAdEQAREQAREQAQcISCR4QhWNSoCIiACIiACIiCRoTkgAiIgAiIgAiLgCAGJDEewqlEREAEREAEREAGJDM0BERABERABERABRwhIZDiCVY2KgAiIgAiIgAhIZGgOiIAIiIAIiIAIOEJAIsMRrGpUBERABERABERAIkNzQAREQAREQAREwBECEhmOYFWjIiACIiACIiACEhmaAyIgAiIgAiIgAo4QkMhwBKsaFQEREAEREAERkMjQHBABERABERABEXCEgESGI1jVqAiIgAiIgAiIgESG5oAIiIAIiIAIiIAjBCQyHMGqRkVABERABERABCQyNAdEQAREQAREQAQcISCR4QhWNSoCIiACIiACIiCRoTkgAiIgAiIgAiLgCAGJDEewqlEREAEREAEREAGJDM0BERABERABERABRwhIZDiCVY2KgAiIgAiIgAj8P9DA3KV62r4KAAAAAElFTkSuQmCC     IMG_20230201_171242 

图1:硬件连线方式

2、软件简介及设计思路

该系统可以用micropython开发,也可以用arduino开发。micropython开发的优点在于方便调试,缺点在于板子上运行程序的速度会较慢。arduino开发的优点在于板子上运行程序时速度较快,且相关的生态(例如教程,第三方库)比micropython会好一些,缺点在于调试较于micropython会更加困难。在实际开发中发现,如果使用micropython开发,显示屏的刷新会很迟钝,影响观感。所以我最后决定采用arduino开发。

软件的简要设计思路如下,具体设计代码的解析,详见:“四、代码解析”

(1). 在arduino的“开发板管理器”中,安装好esp32相关的包。我安装的是“esp32 by EspressifSystems 版本2.0.2”这个包。

(2). 利用PWM控制电阻发热功率。利用arduino的Wire第三方库,通过温度传感器读取温度,并利用串口输出。

(3). 利用数组储存历史温度,安装TFT_eSPI第三方库,利用该库将温度曲线显示在拓展板的屏幕上。

(4). 利用WiFi第三方库,将拓展板的屏幕的图像发送到上位机。并在上位机上开发相应的软件程序,接收图像信息并保存。

(5). 完善其它的一些小细节。

三、系统框图和软件流程图

1、系统框图

该系统的简单框图如下。

FrZ5rL9U5kIlKqCZ3TBCjlRoP60I

图2:系统框图

 

在该系统中,ESP32-S2 MCU通过PWM控制电阻发热功率,从而间接控制温度变化。温度传感器将温度信息传回MCU,MCU再操纵TFT屏驱动模块,在屏幕上显示出温度曲线等信息,并生成图像数据,通过WIFI模块传至上位机,在上位机也有一专门的程序,接收图像信息并保存为png文件。

2、软件流程图

控制该系统工作的软件的流程图如下:

Fk8cae-ruJlgocpFTWqNABMzOueZ

图3:流程图

对于流程图,有几点需要额外说明一下:

(1). 对于系统初始化中的“sprite对象初始化”,指的是利用TFT_eSPI库中的TFT_eSprite类,新建并初始化一个对象spr。在开发截屏功能时发现,无法正常地直接从TFT屏中读取像素信息。所以我另外维护了一个spr对象,每当需要在刷新屏幕图像时,先在spr对象中画好图像,再传至屏幕,这样在spr类中也保存了一份图像信息。而当需要读取图像信息时,则直接从spr中读取,这样即可解决问题

(2). 对于系统初始化中的“储存温度的数组初始化”,我在程序中维护一个长度为60的数组,用于储存一分钟内每秒的温度信息。程序启动时,数组内的所有元素设置为一个负数-200,然后在每秒1次的循环中,每次循环都利用温度传感器读取当前秒的温度,记录在数组中,并根据数组画出温度曲线。当1分钟结束后,数组内的所有元素都已记录有温度了。将数组所有元素重新变为-200,开始新一分钟的记录。

(3). 在循环中,我设置当按下按键时,LED会熄灭或者亮白灯,这主要是为了能给用户一个反馈,告诉用户MCU已经得知了用户的操作。

具体设计代码的分析,详见“四、代码解析”

四、代码解析

在这一部分中,我会选择程序中几部分关键代码,讲述代码的含义。

1、温度数组

首先是储存温度的数组的初始化,一开始,我先初始化两个数组,数组x作为画图的横坐标,数组tlist储存温度,是画图的纵坐标。一开始把所有的元素设为-200,主要是为了便于画图时只显示记录到的温度信息(画图时不会把-200画出来)。

for (int i=0; i<60; i++){
  x[i] = i;
  tlist[i] = -200;
}

接下来,在每轮循环中,都需要更新一次图像。代码如下。首先需要将当前温度t放入tlist数组,我这里维护了一个变量current_idx,每个计时周期的一开始将其赋值为0,然后每次循环加一,在计时周期的最后,也就是current_idx为59时,清零。接下来清屏,然后在屏幕的右上角和右下角分别显示温度,PWM数值。遍历x和tlist数组,将x中的元素作为横坐标,tlist中的作为纵坐标,画出曲线。

void plotOnScreen(int t){
  tlist[current_idx] = t;
  current_idx++;
  spr.fillSprite(TFT_BLACK);  //清屏
  char str_tpr[7]; sprintf(str_tpr, "  t:%d\0", t);
  char str_pwm[7]; sprintf(str_pwm, "pwm:%d\0", pwm);
  spr.drawString(str_tpr, (int32_t)75, (int32_t)10, 4);  //右上角显示当前温度
  spr.drawString(str_pwm, (int32_t)85, (int32_t)105, 2);  //右下角显示当前pwm数值

  for (int i=0; i<60; i++){  //显示曲线
    spr.fillCircle(x[i],110-tlist[i],1,TFT_GREEN);  
  }
  spr.pushSprite(0,0);

}
  }
  spr.pushSprite(0,0);
}

最后,在每轮循环的末尾,都要检查一次current_idx是否为59,如果是,需要重置数组,并变更PWM数值。

if (tlist[59]!=-200) {  //当最后一格也被用完时,清空温度记录
  reset_record();
  change_PWM();
  current_idx = 0;
}

2、按键控制

在更新完屏幕后,需要检查是否有按键被按下,如果有,需要做出相应操作。开发板上有两个按键,一个是旋转编码器,一个是右侧的黑色小按钮。按下后,会使1号引脚A_Out的电压发生变化。之前在群里和群友聊天,以及查阅相关资料发现,按下按键后,A_Out的电压输出并不是一个恒定值,会呈一定规律变化。但是实际中发现,如果用analogRead读取该引脚电压,当按下旋转编码器时,返回值在6080左右;当按下黑色小按钮时,返回值在2200左右;而什么都不按时,返回值在7400左右。按照这样的规律即可判定按下的是哪个按键。虽然这样的做法不是很标准严谨,但是在我的设计中已经够用了。

此外,由于这里涉及到了按键操作,所以还应当引入防抖动的代码。但是实际发现即使不加防抖动,按下一次按键后对应功能也只是触发一次,程序运行正常。所以我也没有加上防抖动的功能。

int key = analogRead(KEY);
if (key<4000){
  digitalWrite(LED_R, 0);
  digitalWrite(LED_G, 0);
  digitalWrite(LED_B, 0);
  sendPic();
}
else if (key<6500){
  digitalWrite(LED_R, 1);
  digitalWrite(LED_G, 1);
  digitalWrite(LED_B, 1);
  change_PWM();
}

3、截屏

实现截屏的方法是这样:首先,利用sprite对象的readPixel方法,读取图像的所有像素点。然后,每读取一行,就打包,并通过WIFI向上位机传输。由于我这里用的是udp协议,不保证可靠交付,所以我这里刻意加上了延时,让相邻的两个数据包之间有一定的延时,方便上位机完整接收数据。

void sendPic(){
  for (int y=0; y<128; y++){
    udp.beginPacket(udpAddress,udpPort);
    for (int x=0; x<128; x++){
      uint16_t pixel = spr.readPixel(x,y);
      udp.printf("%d,", pixel);
    }        
    udp.endPacket();
    delay(10);
  }
}

3、变更PWM的值

这部分代码较简单;当需要变更PWM的值时,就检测一下当前PWM的值是多少,然后再选择合适的下一个值就行了(有点类似Verilog中的状态机的写法)。在我的程序中。我会在每个计时周期结束后,或者按下旋转编码器时,调用此函数。

void change_PWM(){
  switch (pwm) {
    case 16: pwm=64; break;
    case 64: pwm=96; break;
    case 96: pwm=16; break;
    default: pwm=16; break;      
  }
  analogWrite(PWM_OUT, pwm);
}

这里只展示了一部分代码,关于其它代码,详见我上传的源代码文件。

此外,我的代码还有一定的优化空间,不过当前版本的代码已经能很好地实现所需功能。

五、功能展示

如图,在开发板的屏幕上可以显示温度曲线等信息。当pwm值较小时,由于发热比不上散热,所以温度会下降,而当pwm较大时,温度会逐渐升高。

FoiGsW03o3lpYE3hLYUA97264SMX

图4:屏幕显示温度曲线

另外,按下黑色按键后,开发板会截屏并将图像发送至上位机,这是我收到的一个图像:

FosG4Qpv49UD4ThETXMPY3V6OPFS图5:截屏

 

更详尽的功能展示,详见我上传的视频。

六、其它

1、遇到的困难

在完成这个项目时,我遇到了各种各样的困难,比如开发环境配置,传感器的使用等等,不过许多困难都被我缺失解决了。而令我印象最深刻的困难其实是截屏功能的实现。由于屏幕本身的不足,无法直接从屏幕中获取图像信息,所以需要另外维护一个sprite对象,在sprite上也保存一份图像信息,需要截屏时就直接从sprite上读取,以此可以很好的实现获得图像信息的功能。

2、可以改进的地方

这个项目中可以改进的地方有很多。比如,画图,截屏算法可以可以优化(不过个人感觉,就此任务而言,当前的版本的算法性能已足够优秀,再进行优化也不会带来更多使用上的便利)。画图时的界面设计可以更加美观;pwm数值的选择可以更多,如0~128的整数;可以加入恒温功能等。

3、总结与收获

在本项目中,我基于硬禾学堂提供的ESP32-S2 WIFI MCU以及拓展板,使用温度传感器,TFT屏等多个元件,实现了一个加热和温度采集系统。通过完成本次项目,我学习到了许多有关驱动程序,通信协议的知识,对嵌入式开发有了更加深入的了解。并且,我的实践能力得到了很大的提升与进步。

附件下载
附件.rar
附件中包含我的项目的源代码
团队介绍
北京理工大学电子信息大三本科生 陆品成
团队成员
aezakmi
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号