一.项目介绍
1.项目功能介绍
本项目基于树莓派RP2040平台和十二指神探传感器扩展板实现了恒温控制系统,利用RP2040主控,用加热电阻调节温度,温湿度传感器监测环境温湿度,拨轮按键设定目标温度,LCD屏幕显示目标温度、实时温度、实时湿度。
项目任务:
- 至少使用一种自控算法控制,如PID等
- 可用按键或拨轮控制目标温度
- 可在LCD屏上显示目标温度及实时温度
2.功能展示
初始设定温度为30度,可以拨动拨轮调整温度,往左拨是减1度,往右是加1度。
3.设计思路
- 先实现当前环境的温度、湿度数据采集,并动态显示在LCD屏幕上。利用RP2040单片机控制LCD屏幕和扩展板上的温湿度传感器NSHT30可以实现。
- 然后给定一个较高的目标温度,实现环境温度向目标温度的靠近。利用RP2040单片机控制加热电阻可以实现。为了实现温度控制的稳定,需要使用PID算法。
- 最后用RP2040单片机实现拨轮控制目标温度,此时目标温度可以人为设定。
4.硬件介绍
4.1 RP2040
主要使用接口为:
- TYPE-C接口用于供电和数据传输
- 两个可程控按键和一个拨轮用于自定义功能
- 搭载240*240分辨率的LCD彩屏,通过SPI接口进行通信,控制器为常用的ST7789芯片
- 扩展接口包含5v、3.3v输出、GND。9个GPIO,可同时使能最多三个通道ADC
4.2 带屏十二指神探
带屏版的12指神探,它是在原板基础上,配备了一块240*240分辨率的LCD彩屏以及两个可程控按键和一个拨轮,丰富了人机交互功能,方便信息观察、界面切换等使用方式。此外还配备了白色外壳,精心设计的包装不仅使板卡日常使用时更加美观也便于板卡的站立以及使用安全。
4.3 传感器扩展板
主要使用接口为:
- NSHT30温湿度传感器模块,与主控板之间的通信采用I2C通信协议。I2C总线只使用两条总线线路,SDA、SCL。每个连接到总线的设备都有一个独立的地址,主控可以利用这个地址进行不同设备之间的访问。
- 加热电阻,通过GPIO口控制,当IO22处于高电平输出状态时,加热电阻工作,同时LED指示灯亮起。
5.软件流程图
二.代码说明
1.读取NSHT30传感器的温湿度
# 初始化I2C总线
i2c = I2C(0, scl=Pin(21), sda=Pin(20))
# NSHT30的I2C地址
NSHT30_ADDR = 0x44
# 读取NSHT30传感器温湿度值的函数
def read_nsht30():
# 发送启动测量命令
i2c.writeto(NSHT30_ADDR, b'\x2c\x10')
utime.sleep_ms(20) # 等待测量完成
# 读取温湿度值
data = i2c.readfrom(NSHT30_ADDR, 6)
temperature = ((data[0] << 8) | data[1]) * 175 / 0xFFFF - 45
humidity = ((data[3] << 8) | data[4]) * 100 / 0xFFFF
return temperature, humidity
首先,NSHT30传感器通过I2C通信协议传输数据,查看数据手册确认SDA接口对应Pin(20),SCL接口对应Pin(21),NSHT30的地址是0x44。
然后,向NSHT30的地址发送信号,开始测量温度。发送指令\x2c\x10。NSHT30收到信号后会进行温度测量,这时我们需要等待约20毫秒,让温度传感器完成测量。
一旦NSHT30完成测量,我们就可以从其地址读取6个字节的数据。这些数据包含了当前的温度和湿度值。最后,对这些数据进行转换,即可得到当前的温、湿度值。
2.PID控制器
# 初始化PID控制器
class PIDController:
def __init__(self):
self.Kp = 15000
self.Ki = 0.001
self.Kd = 200
self.previous_error = 0
self.integral = 0
def update(self, setpoint, measured_value):
error = setpoint - measured_value
self.integral += error
derivative = error - self.previous_error
output = self.Kp * error + self.Ki * self.integral + self.Kd * derivative
self.previous_error = error
return output
# 初始化PID控制器
pid = PIDController()
在PID控制器中,P代表比例(Proportional),I代表积分(Integral),D代表微分(Derivative)。它们各自的作用如下:
比例(Proportional):
- 比例控制是根据偏差的大小来调整控制输出的量。偏差是当前值与目标值之间的差异。
- P项的作用是使系统快速响应,并且与偏差成正比,因此当偏差较大时,P项对控制输出的影响也较大。
- 适当的比例增益可以确保系统的稳定性和快速的响应,但过大的比例增益可能导致震荡或者过冲。
积分(Integral):
- 积分控制是根据偏差的累积值来调整控制输出的量。它消除了静态误差,因为它对系统的长期行为进行修正。
- I项的作用是消除稳态误差,即系统长时间偏离目标值的情况。它可以缓慢但持续地调整控制输出,直到偏差为零。
- 适当的积分时间常数可以确保系统的稳定性和准确性,但过大的积分时间常数可能导致系统响应过于迟缓。
微分(Derivative):
- 微分控制是根据偏差的变化率来调整控制输出的量。它可以抑制系统的振荡和过冲,提高系统的动态响应速度。
- D项的作用是预测未来的偏差变化趋势,通过减小偏差变化速率来稳定系统。
- 适当的微分时间常数可以减小系统的振荡和过冲,但过大的微分时间常数可能导致系统对于噪声过于敏感。
根据实际情况进行参数的调试,最终选定K=15000,I=0.001,D=200
3.PID算法调整PWN占空比
#加热电阻初始化
heat = Pin(22)
heating_pwm = PWM(heat)
heating_pwm.freq(50)
heating_pwm.duty_u16(0)
# 使用PID控制器计算加热器输出
output = pid.update(target_temperature, temperature)
# 更新PWM占空比
control = min(65536, max(0, int(output)))
heating_pwm.duty_u16(control) # 将PID输出作为PWM的占空比
参考:【04_PID控制算法及PWM占空比信号的实现-哔哩哔哩】https://b23.tv/RYl4GHP
4.主循环中拨轮控制调整目标温度
# 初始设定温度
target_temperature = 30.0
temp = 30.0
blink = False
# 屏幕显示
display.fill(st7789.BLACK)
display.text(font2, "Target:", 20, 20)
display.text(font2, str(target_temperature), 20, 50)
display.text(font2, "Temperature:", 20, 80)
display.text(font2, "Humidity:", 20, 140)
# 主循环
while True:
# 读取NSHT30传感器的温度和湿度值
temperature, humidity = read_nsht30()
# 读取按钮状态、设定目标温度
buttonValueL = buttonL.value()
buttonValueR = buttonR.value()
buttonValuePRESS = buttonPRESS.value()
if buttonValueL == 0:
temp -= 1
blink = True
elif buttonValueR == 0:
temp += 1
blink = True
# 如果press键被按下,更新目标温度
if buttonValuePRESS == 0:
target_temperature = temp # 或者根据实际需求更新目标温度
blink = False
# 使用PID控制器计算加热器输出
output = pid.update(target_temperature, temperature)
# 更新PWM占空比
control = min(65536, max(0, int(output)))
heating_pwm.duty_u16(control) # 将PID输出作为PWM的占空比
# 如果目标温度开始闪烁,则在屏幕上显示闪烁的目标温度
if blink:
display.fill_rect(20, 50, 100, 40, st7789.BLACK)
utime.sleep(0.1)
display.text(font2, str(temp), 20, 50)
utime.sleep(0.1)
display.text(font2, str(temperature), 20, 110)
display.text(font2, str(humidity), 20, 170)
设定如果拨轮被拨动,则屏幕上的设定温度开始闪烁,按下拨轮此温度被确认,目标温度被更改,屏幕停止闪烁。此处使用了一个布尔型变量blink和一个简单的判断语句实现。
三.主要难题及解决方法
1.PID参数设置
通过调试,发现K值超过15000就会使得系统升温速度过快,低于15000就会使系统升温过慢,往往达不到预设温度就开始降温。又发现I值大于0.001会导致温度上升至超过设定值也不会马上降温,系统反应迟缓。最后将D设为200可以让系统温度更稳定的维持在设定值附近。
2.设定温度闪烁的实现
不知道如何使用占空比来实现数字闪烁效果,于是通过移除LCD屏上的字再显示来实现闪烁效果。由于屏幕刷新率为50Hz,因此只要闪烁的频率低于这个频率即可被人眼观察到,设置闪烁周期sleep(0.1+0.1)秒。但是这会影响到主循环的时长而导致温度控制变慢。
四.未来计划
使用图形化界面,增加美观度。希望将屏幕闪烁独立,不影响主循环。