2024年寒假练-用搭配带屏12指神探的传感器扩展板做PID控制温度练习
该项目使用了搭配带屏12指神探的传感器扩展板,实现了用PID方式控制温度的设计,它的主要功能为:通过PWM方式控制mos管通断,使得电阻加热。使用PID自动控制加热温度。。
标签
嵌入式系统
测试
显示
2024年“寒假在家一起练”
happy
更新2024-03-29
148

硬件介绍:

硬件分为两个部分:第一部分为一个带屏版的12指神探,它是一款基于树莓派基金会推出的微控制器RP2040制作的多功能硬件调试助手,它有12根引脚,提供了5V和3.3V的电压,其中有9根GPIO,功能灵活,通过搭配不同程序可以做成各种调试器。第二部分:是一块扩展板。搭载了几款常见传感器和功能模块,包括麦克风、蜂鸣器、、红外收发、霍尔效应开关、加热电阻,温湿度传感器、六轴传感器、接近/环境光/IR传感器、颜色传感器。

任务选择:

我选择的是任务1:恒温或恒湿控制系统。任务要求:至少使用一种自控算法控制,如PID等,可用按键或拨轮控制目标温度可在LCD屏上显示目标温度及实时温度。

编程语言我使用Arduino。开发工具使用 Vscode+platformio

任务实现:

查看电路图可以得知,扩展板上有4颗电阻加一个MOS管构成了一个可控加热装置。rp2040可以通过管脚控制MOS管的开关。加热装置上还有一颗NSHT30传感器,用来测量温湿度,通过IIC与rp2040通讯。

第一步,先搞定温湿度传感器。这里传感器使用了sht30,在platformio的库里搜索,找到一个“SHTSensor”库,能够很方便很方便地驱动起这颗温湿度传感器。

#include <Wire.h>
#include "SHTSensor.h"

SHTSensor sht;
void setup()
{
  Wire.begin();
  Serial.begin(115200);

  if (sht.init())
  {
    Serial.print("init(): success\n");
  }
  else
  {
    Serial.print("init(): failed\n");
  }
  sht.setAccuracy(SHTSensor::SHT_ACCURACY_MEDIUM); // only supported by SHT3x

}

void loop()
{
  // put your main code here, to run repeatedly:

  if (sht.readSample())
  {
    Serial.print("SHT:  ");
    Serial.print("  RH: ");
    Serial.print(sht.getHumidity(), 2);
    Serial.print("  T:  ");
    Serial.print(sht.getTemperature(), 2);
    Serial.print("\n");
  }
  else
  {
    Serial.print("Error in readSample()\n");
  }

  delay(1000);
}

这里需要留意一下,这个板子的IIC接的管脚为SDA(20),SCL(21),和默认管脚不同,需要在配置文件中做修改。

第二步,驱动屏幕。这里的屏幕使用的是ST7789驱动,使用TFT_eSPI库就轻易地将屏幕驱动起来了。有尝试过LVGL,但是移植失败。TFT_eSPI显示中文比较麻烦,就增加了个U8g2_for_TFT_eSPI库,用来显示中文。

#include "SPI.h"
#include "TFT_eSPI.h"
#include "U8g2_for_TFT_eSPI.h"

TFT_eSPI tft = TFT_eSPI(); // tft instance
U8g2_for_TFT_eSPI u8f;     // U8g2 font instance
void setup()
{
    tft.begin();
    tft.setRotation(0);
    tft.fillScreen(TFT_BLACK);
    u8f.begin(tft); // connect u8g2 procedures to TFT_eSPI
}

unsigned long x = 0;

void loop()
{
    u8f.setFontMode(0);                // use u8g2 none transparent mode
    u8f.setFontDirection(0);           // left to right (this is default)
    u8f.setForegroundColor(TFT_WHITE); // apply color

    u8f.setFont(u8g2_font_wqy15_t_gb2312);
    // u8g2.drawStr(10,20,"你好");
    u8f.setCursor(0, 20);
    u8f.print("你好");
    u8f.setCursor(0, 40);    // start writing at this position
    u8f.print("Umlaut ÄÖÜ"); // UTF-8 string with german umlaut chars

    u8f.setFont(u8g2_font_inb63_mn); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
    u8f.setFontMode(0);              // use u8g2 none transparent mode

    while (1)
    {
        u8f.setCursor(0, 110); // start writing at this position
        u8f.print(x);          // numerical value
        x++;
        delay(250);
    }
}

第三步,驱动按键。需要使用按键与系统交互,用来控制系统运行状态和修改设定温度。这里使用了AceButton库,定义了三个按键。分别对应旋钮的 左、中、右。中间键控制运行状态,运行状态分为两类:运行态和设置态。运行态时通过PWM控制mos管进行加热。设置态分为两档,慢速调节,左右两个按键每次上下调节1度,快速调节,左右两个按键每次上下调节2度。设置态时禁止mos管加热。

// The event handler for both buttons.
void handleEvent(AceButton *button, uint8_t eventType, uint8_t buttonState)
{
    if (eventType == AceButton::kEventReleased)
    {
        switch (button->getPin())
        {
        case BUTTONL_PIN:
            settemperature -= setstat;
            break;
        case BUTTONR_PIN:
            settemperature += setstat;
            break;
        case BUTTONO_PIN:
            setstat = (setstat + 1) % 3;
            break;
        }
        if (settemperature > TEMPMAXVAL)
            settemperature = TEMPMAXVAL;
        if (settemperature < TEMPMINVAL)
            settemperature = TEMPMINVAL;
        diapSetTemp();
    }
}

第四步,添加PID控制。PID算法在自动化控制里边真的是很厉害的一个算法,鲁棒性超强。本质上就是面多了加水、水多了加面的一个操作。这里使用PWM控制mosmos管的开关,需要加热时,就打开模式管,让电流通过电阻,进行加热。当温度达到或超过设定温度时,就关闭mos管,通过环境给电阻降温。所以设定温度不能低于环境温度,否则无法降温。

#include "tempturepid.h"
PID pid;
void PID_Init()
{
    pid.Kp = 210;
    pid.ki=0.125;
    pid.kd=0.08;
}

void PID_Calc() // pid计算
{
    float DelEk;
    float ti, ki;
    float td;
    float kd;
    float out;
    pid.Ek = pid.Sv - pid.Pv;   //得到当前的偏差值
    pid.Pout = pid.Kp * pid.Ek; //比例输出
    pid.SEk += pid.Ek;          //历史偏差总和
    DelEk = pid.Ek - pid.Ek_1;  //最近两次偏差之差
    pid.Iout = pid.ki * pid.SEk;    //积分输出
    pid.Dout = pid.kd * DelEk; //微分输出

    out = pid.Pout + pid.Iout + pid.Dout;

    if (out > MAXOUTVAL)
    {
        pid.OUT = MAXOUTVAL;
    }
    else if (out <= 0)
    {
        pid.OUT = 0;
    }
    else
    {
        pid.OUT = out;
    }
    pid.Ek_1 = pid.Ek; //更新偏差
}

第五步,调整PID的参数,让温度震荡在可接受的范围内。设计个简单的UI。最上方使用小字体显示当前运行状态和湿度。中间一行用较大字体显示设定值。最下方用大字体显示实时温度。当处于设置模式时,慢速设定时使用棕色字体显示设定值,以1度为步进值;当为快速设定时,使用红色字体显示设定值,以2度为步进值。当切换到运行状态时,用绿色字体显示设定值,当mos管导通时,红色LED灯会亮起,并且通过串口将pwm输出值显示出来。

心得体会

非常开心参加寒假一起练活动,边玩边学,即获得了开心,又打开了单片机的世界。开发过程中得到了交流群里很多老师的帮助,在此表示非常感谢!期待学习各位老师的作品!

附件下载
pico2024_homework.zip.001
pico2024_homework.zip.002
pico2024_homework.zip.003
团队介绍
单片机爱好者
团队成员
happy
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号