一.项目介绍
1.1项目功能介绍
使用带屏12指神探即其传感器扩展板设计一个恒温控制系统,主要功能如下:
1.使用搭配带屏12指神探的传感器扩展板上的温湿度传感器-NSHT30测量环境的温度与湿度;
2.使用带屏12指神探上方的按键以及拨轮调节目标温度,按下左按键或拨轮左拨下调目标温度,按下右按键或拨轮右拨上调目标温度;
3.使用PID自控算法控制PWM加热电阻调节温度,使当前温度达到目标温度;
4.在带屏12指神探的LCD屏上显示目标温度、当前温度、当前湿度以及加热电阻是否正在加热。
1.2设计思路
本系统主要包括传感器温湿度测量、LCD屏显示、按键控制、PID算法、加热电阻五个模块。在控制系统的主循环中,系统通过温湿度传感器测量当前环境的温湿度,通过检测按键是否被按下或拨轮是否被拨动,来改变目标温度;通过当前温度和目标温度,以及PID算法的三个参数,计算PID的控制量;通过PID控制量的正负与大小控制PWM的输出占空比,从而调节加热电阻是否工作及其功率大小,以达到恒温控制效果。
1.3软件流程图
二.硬件介绍
2.1带屏幕12指神探
带屏版的12指神探是在原板基础上,配备了一块240*240分辨率的LCD彩屏以及两个可程控按键和一个拨轮,丰富了人机交互功能,方便信息观察、界面切换等使用方式。采用树莓派Pico核心芯片RP2040,初学者可以使用MicroPython快速上手进行开发。
2.2搭配带屏12指神探的传感器扩展板
作为12指神探的传感器扩展板,接口完全适配,正确方向插入后即可使用。扩展板搭载了几款常见传感器和功能模块,包括为初学者准备的麦克风、蜂鸣器、、红外收发、霍尔效应开关、加热电阻,为进阶操作准备的温湿度传感器、六轴传感器、接近/环境光/IR传感器、颜色传感器。其中温湿度传感器、六轴传感器、接近传感器、颜色传感器可拆卸为单个模块,通过杜邦线等连接线延伸其使用的空间范围。出厂默认传感器正面朝上使用。若需背面朝上使用,则自行焊接排母后按指示方向插入。
三.功能展示
3.1实现功能
1.使用搭配带屏12指神探的传感器扩展板上的温湿度传感器-NSHT30测量环境的温度与湿度;
2.使用带屏12指神探上方的按键以及拨轮调节目标温度,按下左按键或拨轮左拨下调目标温度,按下右按键或拨轮右拨上调目标温度;
3.使用PID自控算法控制PWM加热电阻调节温度,使当前温度达到目标温度;
4.在带屏12指神探的LCD屏上显示目标温度、当前温度、当前湿度以及加热电阻是否正在加热。
3.2 图片展示
1.恒温控制系统显示初始预设温度为30摄氏度,且可以显示当前环境温度与湿度,以及加热电阻工作状态;
2. 按下右按键或将拨轮向右拨,将目标温度上调到35摄氏度,可以看到加热电阻工作,当前环境温度逐渐上升到35摄氏度附近,并基本稳定在其上下(误差小于±0.5摄氏度);
3.按下左按键或将拨轮向左拨,将目标温度下调到32摄氏度,可以看到加热电阻不工作,当前环境温度逐渐下降到32摄氏度附近,并基本稳定在其上下(误差小于±0.5摄氏度)。
四.主要代码片段及说明
4.1初始化系统
1.初始化传感器,查询电路图可知管脚编号与温湿度传感器地址:
#配置I2C协议与引脚
sda=Pin(20)
scl=Pin(21)
i2c=machine.I2C(0,sda=sda,scl=scl,freq=400000)
#定义温湿度传感器NSHT30地址
NSHT30_ADDR = 0x44
初始化显示屏:
# 初始化LCD显示屏
st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
spi_sck=Pin(2)
spi_tx=Pin(3)
spi0=SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width, disp_width,
reset=machine.Pin(st7789_res, machine.Pin.OUT),
dc=machine.Pin(st7789_dc, machine.Pin.OUT),
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
display.text(font2, "Temperature", 10, 10)
display.text(font2, "Controller", 10, 40)
初始化按键和拨轮,管脚定义见电路图:
# 配置按键和拨轮
# 左按键
button_left = Pin(5,Pin.IN, Pin.PULL_UP)
# 右按键
button_right = Pin(6,Pin.IN, Pin.PULL_UP)
# 拨轮左拨
button_wheelL = Pin(7,Pin.IN, Pin.PULL_UP)
# 拨轮右拨
button_wheelR = Pin(9,Pin.IN, Pin.PULL_UP)
初始化加热电阻PWM,最开始的输出占空比设置为0:
# 初始化加热电阻PWM
heater = PWM(Pin(22))
heater.freq(100)
heater.duty_u16(0)
4.2传感器测量温湿度
根据温湿度传感器的使用指南,可知其采集温湿度数据的指令,以及返回数据的内容,即从芯片I2C地址回读6Bytes数据,包含温度值,温度CRC值,湿度值和湿度CRC值。读取的数据经过CRC校验结果判定无异常后,根据转换公式转换为温度值、相对湿度值。
# 读取温湿度数据
def get_temperature_humidity():
# 定义读取温度和湿度的命令
# 单次测量模式,高可重复性,使用指南2.1.1
CMD_get_temp_humi = bytearray([0x24,0x00])
# 向NSHT30发送读取温湿度的命令
i2c.writeto(NSHT30_ADDR, CMD_get_temp_humi)
# 延时0.02s等待测量完毕
utime.sleep(0.02)
# 从I2C总线回读6bytes数据
# 分别为温度,温度CRC,湿度,湿度CRC
data = i2c.readfrom(NSHT30_ADDR, 6)
# 进行验证
temp = (data[0]<<8)|data[1]
humi = (data[3]<<8)|data[4]
# 计算温度和湿度,手册p18,19
temperature = 175.0*temp/65535.0-45.0
humidity = 100.0*humi/65535.0
# 保留两位小数
temperature = round(temperature, 2)
humidity = round(humidity, 2)
return temperature, humidity
4.3按键控制
在主循环中通过.value()获取当前按键或拨轮的状态:
display.text(font1, "current humidity:" + str(current_humi) + "%", 20, 180)
# 按键或拨轮调节目标温度
# 检测按键是否被按下
buttonValue_Left = button_left.value()
buttonValue_Right = button_right.value()
buttonValue_WheelL = button_wheelL.value()
buttonValue_WheelR = button_wheelR.value()
按下右按键或拨轮右拨,提升目标温度,最大90度;按下左按键或拨轮左拨,降低目标温度,最小0度:
# 按下右按键或拨轮右拨,提升目标温度,最大90度
if buttonValue_Right == 0 or buttonValue_WheelR == 0 and target_temp <= 90.0:
target_temp += 1.0
# 重置PID参数
PID_Reset()
# 按下左按键或拨轮左拨,降低目标温度,最小0度
elif buttonValue_Left == 0 or buttonValue_WheelL == 0 and target_temp >= 0.0:
target_temp -= 1.0
# 重置PID参数
PID_Reset()
4.4PID算法控制
PID算法是控制领域比较经典和实用的算法,其中P、I、D分别指proportion、integration和differentiation,即比例、积分和微分:
# PID
#PID参数
# 比例增益Kp
Kp=5
# 积分增益Ki
Ki=1
# 微分增益Kd
Kd=0.5
# 初始化微分项所需的前一误差值与积分项
#前一误差值
prev_error = 0
# 积分项
integral = 0
# PID自控算法,接收当前温度和目标温度作为参数
def PID_Controller(current_temperature, target_temperature):
global prev_error, integral
# 误差值
error = target_temperature - current_temperature
# 计算P、I、D项
#计算比例项P,比例增益乘以当前误差
proportional = Kp * error
#计算积分项I,积分增益乘以累积误差
integral = Ki * (error + integral)
#计算微分项D,微分增益乘以当前误差与前一误差的差值
derivative = Kd * (error - prev_error)
# 输出
output = proportional + integral + derivative
# 更新前一误差值
prev_error = error
return output
每当目标温度变化,PID参数重置:
# 每次改变目标温度重置PID参数(前一误差值和积分项归零)
def PID_Reset():
global prev_error, integral
prev_error = 0.0
integral = 0.0
4.5加热电阻
通过PID算法计算出的控制量调节PWM的输出占空比,从而控制加热电阻输出功率,即与目标高温相差较多时,加热功率大,升温快,反之升温慢;控制量小于等于零时,加热电阻不工作,温度自然降低。以此实现恒温控制。
# 加热电阻,控制温度
def heat_on(difference_temperature):
if difference_temperature <= 0:
heater.duty_u16(0)
display.text(font1, "Heater: OFF", 20, 140)
elif difference_temperature > 0:
# 使用PID控制量控制PWM输出占空比
heat_duty = min(1, difference_temperature*0.01)
heat_duty_u16=int(65535*heat_duty)
heater.duty_u16(heat_duty_u16)
display.text(font1, "Heater: O N", 20, 140)
4.6LCD显示
使用display.text()函数显示目标温度、当前温度、当前湿度以及加热电阻是否工作。
# 主循环
while True:
# 在显示屏上显示设定温度和实际温度
current_temp, current_humi = get_temperature_humidity()
display.text(font1, "target temperature(0℃-90):" + str(target_temp), 20, 100)
display.text(font1, "current temperature:" + str(current_temp), 20, 120)
display.text(font1, "current humidity:" + str(current_humi) + "%", 20, 180)
五.遇到的主要难题及解决方法
遇到问题:在传感器进行采集时,不知道要向I2C总线发出的指令是什么。
解决方法:查询温湿度传感器手册可知。
六.未来计划
6.1优化PID算法参数
本项目基本实现了测量当前环境温湿度、设定目标温度并使用PID算法控制环境温度维持在目标温度附近。根据PID算法的原理,可以适当调整参数Kp、Ki、Kd,优化系统的稳定性、精确度和响应速度。
6.2图形界面
本项目仅实现了文字和数字显示温度、湿度与加热电阻工作状态。下一步可以通过添加图形界面使系统的显示更加直观和美观。
6.3恒湿控制
因为扩展板仅包含加热电阻部件用来改变温度,而没有改变湿度的部分,所以无法实现恒湿控制系统。期待尝试更多部件实现题目中描述的恒湿控制功能,并将两者结合,实现恒温、恒湿控制系统。