任务:
恒温或恒湿控制系统
需求分析:
- 至少使用一种自控算法控制,如PID等
- 可用按键或拨轮控制目标温度
- 可在LCD屏上显示目标温度及实时温度
硬件资源介绍:
主控:
采用树莓派Pico核心芯片RP2040
- 双Arm Cortex M0+内核,可以运行到133MHz
- 264KBSRAM,板卡上外扩2MBFlash
- 性能强大、高度灵活的可编程IO(PIO)可用于高速数字接口
- 拥有2个UART、2个SPI、2个I2C、16个PWM通道以及4路12位精度ADC
- 支持MicroPython、C、C++编程
- 拖拽UF2固件至U盘的方式烧录固件,方便快捷
扩展板搭载了几款常见传感器和功能模块:
麦克风、蜂鸣器、红外收发、霍尔效应开关、加热电阻,温湿度传感器、六轴传感器、接近/环境光/IR传感器、颜色传感器。其中温湿度传感器、六轴传感器、接近传感器、颜色传感器.
硬件原理图:
主控:
传感器:
项目方案设计的介绍和说明:
这个方案采用arduino C++开发,通过I2C读取温湿度传感器的数值可以实时的显示温度和湿度。
通过拨码开关可以设定目标温度数值,并且可以打开或者关闭自动控制。
通过设定的目标值可以把温度稳定,并实时的通过串口输出曲线。(在视频上有详情展示)
主板引脚情况:
屏幕接口:
LCD_RST IO0
LCD_DC IO1
LCD_SCL IO2
LCD_SDA IO3
LCD_CS IO4
两个按键:
KEY_M IO5
KEY_S IO6
拨轮开关:
KEY_L IO7
KEY_OK IO8
KEY_R IO9
侧面有12个插针,分别对应:
GND 3V3
IO20 5V
IO21 IO25
IO22 IO26
IO23 IO27
IO24 IO28
其中I2C接口:用来驱动温湿度传感器
I2C_SDA IO20
I2C_SCL IO21
实现流程:
开发过程和具体步骤:
(1)驱动st7789屏幕
通过TFT-espi库驱动,需要修改userSetup.h中的参数,分辨率为240*240。具体可以参考很多网上例程。
(2)调试通过NSHT30温湿度传感器
NSHT30实际上就是国产厂商用来替换SHT30用的,接口驱动代码和SHT30是一样的,所以驱动NSHT30可以
直接用SHT30的驱动代码。
(3) Pid控温,参数调节,按键交互
PID控制可以直接使用arduino的pid库,使用起来很简单。
PID的参数调节最好使用串口输出,这样比较容易调节(详情件视频中的串口实时输出)。
按键交互比较简单,只需要按键消抖就可以了。
当自动控制没有打开时候,on数值是0,此时显示的是室温的温湿度。
当打开自动控制时候,on数值从0变成1,红色led代表了pwm的输出大小。温度会不断升值去逼近目标设定数值。
遇到的主要难题及解决方法:
最开始打算用micropython做刷屏,PID处理,但是实际上感觉python对字节数据,位数据操作还是不如C方便,速度也比较慢。后来使用cmake做,但是cmake做太费时间了,没有丰富的library可以使用,要自己一个个移植,后来果断转向arduino。
以下是主要代码部分:
驱动温湿度传感器:
void read_temp()
{
//定义数组以存储获取的6个数据
unsigned char data[6];
//开始传输,设置I²C从机地址
Wire.beginTransmission(Addr_SHT30);
//发送测量命令0x2C06,由于一次只能发一个8位数据,因此分开发两次
Wire.write(0x2C);
Wire.write(0x06);
//I²C停止
Wire.endTransmission();
//延时(等待测量数据)
delay(20);
//请求获取6字节的数据,传入对应的从机地址
Wire.requestFrom(Addr_SHT30, 6);
//判断是否成功读取到6个字节
if (Wire.available() == 6) {
//成功读取,则将数据存入data数组
for (int i = 0; i <= 5; i++) {
data[i] = Wire.read();
}
} else {
//读取失败则打印"error!"
Serial.println("error!");
return;
}
//计算得到的数据将其转化为直观的温度和湿度,公式参考下方说明
cTemp = ((((data[0] * 256) + data[1]) * 175.0f) / 65535.0f) - 45.0f;
humidity = ((((data[3] * 256) + data[4]) * 100.0f) / 65535.0f);
}
驱动屏幕:
tft.fillScreen(TFT_BLACK);
//设置起始坐标(20, 10),4 号字体
tft.setCursor(20, 10, 4);
// 设置文本颜色为白色,黑色文本背景
tft.setTextColor(TFT_WHITE, TFT_BLACK);
// 设置显示的文字,注意这里有个换行符 \n 产生的效果
tft.println("Temp PID System");
tft.setTextColor(TFT_YELLOW);
tft.setCursor(50, 120);
tft.print("on:");
tft.print((onoff == 0) ? 0 : 1);
tft.setCursor(50, 150);
tft.print("set temp:");
tft.print(set_temp);
tft.setCursor(50, 180);
tft.print("temp:");
tft.println(cTemp);
tft.setCursor(50, 210);
tft.print("humid:");
tft.println(humidity);
pid和按键交互:
Input = cTemp;
Setpoint = set_temp;
if(onoff != 0){
myPID.Compute();
analogWrite(PIN_OUTPUT, Output);
}
else
{
analogWrite(PIN_OUTPUT, 0);
}
if(digitalRead(buttonPin_add)== LOW)
{
delay(10);
{
if(digitalRead(buttonPin_add)== LOW);
set_temp++;
}
}
if(digitalRead(buttonPin_sub)== LOW)
{
delay(10);
{
if(digitalRead(buttonPin_sub)== LOW);
set_temp--;
}
}
if(digitalRead(buttonPin_onoff)== LOW)
{
delay(20);
{
if(digitalRead(buttonPin_onoff)== LOW);
onoff = ~onoff ;
}
}