项目介绍
本项目是基于树莓派RP2040设计制作一个图形化显示、超温报警的温度计。项目预定实际需求如下:
- 在LCD屏上显示一个图形化的温度计,并实时显示当前的温度(通过RP2040内部的温度传感器测量)
- 可以通过摇杆或按键设定报警温度阈值(如上图下面的部分,需要补充上数字)
- 可以对芯片稍微加温,使温度超过设定的阈值,温度图示颜色变红,且蜂鸣器发出报警声音
- 给芯片降温到阈值一下,温度传感器颜色变绿,蜂鸣器停止报警
项目说明
根据设计需求分别需要实现的功能模块包括RP2040温度传感器读取模块、温度计UI模块、摇杆控制模块、蜂鸣器驱动模块和主逻辑模块等几部分组成。
1 RP2040温度传感器读取模块
RP2040带有一个内部温度传感器,它使用了ADC的通道4,数字并不是温度,而是需要进行转换。参照datesheet实现实现一个带有简单滤波功能的温度读取模块。根据描述板载温度传感器对参考电压的误差非常敏感。 正产情况下 ADC返回值891 这将对应于 20.1°C 的温度。 但是,如果参考电压比 3.3 V 低 1%,则891 的相同读数对应于 24.3°C。 也就是参考电压变化 1%温度变化超过 4°C。
#temperature import machine import utime sensor_temp = machine.ADC(4) conversion_factor = 3.3 / (65535) def getTempValue(): avgnum = 10 temp_sum = 0 for i in range(avgnum): temp_sum += sensor_temp.read_u16() reading = (temp_sum/avgnum) * conversion_factor temperature = 27 - (reading - 0.706)/0.001721 #print(temperature) return temperature
2 温度计UI模块
温度计UI模块是在st7789模块的基础之上实现了基于hline函数的circle函数实现、并在此基础之上进一步实现界面绘制函数drawBasicUI、温度更新函数drawTempUI以及超温报警数值刷新和实时温度刷新函drawTempNum。
其中drawBasicUI绘制了由两个圆和一个矩形组成的温度计,并在体身上绘制好刻度。使用circle函数绘制两个circle,使用rect/fill_rect绘制体身。上圆心位置为(120,20)半径20,下方圆位置(120,210)半径30,也就是温度计显示刻度长度为160个像素点,温度范围设定为0-40度,每4行像素点表示一度的温度变化。每次温度变化时调用drawTempUI更新温度计显示。
def circle( x, y, r, color): ox = r oy = 0 err = -r while ox >= oy: last_oy = oy err += oy oy = oy+1 err += oy display.hline(x - ox, y + last_oy, ox * 2 + 1, color) if last_oy != 0: display.hline(x - ox, y - last_oy, ox * 2 + 1, color) if err >= 0 and ox != last_oy: display.hline(x - last_oy, y + ox, last_oy * 2 + 1, color) if ox != 0: display.hline(x - last_oy, y - ox, last_oy * 2 + 1, color); err -= ox ox=ox-1 err -= ox def drawBasicUI(): circle(120,210,30,st7789.WHITE) circle(120,20,20,st7789.WHITE) display.fill_rect(100,20,40,190,st7789.WHITE) display.fill_rect(100,180-TemperatureUsedCount,40,TemperatureUsedCount,st7789.GREEN) for i in range(5): display.hline(100, 20+40*(i),10, st7789.BLUE); display.hline(100, 20+40*(i)+1,10, st7789.BLUE); #0-60 (170) def drawTempUI(temp, flag): global back_color color =0 if flag == 0: color = st7789.GREEN else: color = st7789.RED circle(120,210,26,color) county = 180-20 countx = 40 tempcount =40 #0-40 TemperatureUsedCount = int(temp*(county/tempcount)) #print(TemperatureUsedCount) display.fill_rect(110,180-TemperatureUsedCount,20,TemperatureUsedCount,color) if flag != back_color: display.fill_rect(110,20,20,180-TemperatureUsedCount,st7789.WHITE) back_color = flag def drawTempNum(temp, cmptemp): display.text(font2, str(int(temp)), 50, 200) display.text(font2, "/"+str(cmptemp), 160, 200)
3 摇杆控制模块
摇杆控制模块是基于servo模块进行修改,对ADC数据区分进实现对摇杆控制方向的判断逻辑。
from machine import Pin,PWM, ADC import time pwm = PWM(Pin(15)) pwm.freq(50) control = ADC(2) def getServoAction(): # 摇杆上下摇动控制舵机 adc = control.read_u16() duty = int(adc * (6553-3276)/0xffff) + 3276 pwm.duty_u16(duty) print(duty) if duty < 4000: return 1 if duty > 5000: return -1
4 蜂鸣器驱动模块
蜂鸣器的发声原理由振动装置和谐振装置组成,蜂鸣器经常用于电脑、打印机、万用表这些设备上做提示音,提示音一般也很简单,就是简单发出个声音就行。
我们这里是直接调用buzzer_music库实现蜂鸣器的开启和关闭。
5 主逻辑模块
主逻辑模块是实时获取温度计摇杆控制方向并对屏幕进行刷新显示,当温度超过超温报警温度时启动蜂鸣器报警及屏幕报警显示红色温度计。当温度再次低于预警温度时关闭蜂鸣器报警同时刷新屏幕显示为绿色。在摇杆发生动作的时候会对超温预警阈值进行调节并刷新在屏幕上进行显示。
![]()
import servo import tempUi import temperature from buzzer_music import music from machine import Pin song = '0 A#4 1 1;2 F5 1 1;4 D#5 1 1;8 D5 1 1;11 D5 1 1;6 A#4 1 1;14 D#5 1 1;18 A#4 1 1;20 D#5 1 1;22 A#4 1 1;24 D5 1 1;27 D5 1 1;30 D#5 1 1;32 A#4 1 1;34 F5 1 1;36 D#5 1 1;38 A#4 1 1;40 D5 1 1;43 D5 1 1;46 D#5 1 1;50 A#4 1 1;52 D#5 1 1;54 G5 1 1;56 F5 1 1;59 D#5 1 1;62 F5 1 1;64 A#4 1 1;66 F5 1 1;68 D#5 1 1;70 A#4 1 1;72 D5 1 1;75 D5 1 1;78 D#5 1 1;82 A#4 1 1;84 D#5 1 1;86 A#4 1 1;88 D5 1 1;91 D5 1 1;94 D#5 1 1;96 A#4 1 1;100 D#5 1 1;102 A#4 1 1;104 D5 1 1;107 D5 1 1;110 D#5 1 1;114 A#4 1 1;116 D#5 1 1;118 G5 1 1;120 F5 1 1;123 D#5 1 1;126 F5 1 1;98 F5 1 1' mySong = music(song, pins=[Pin(23)]) tempUi.drawBasicUI() CmpTempValue = 35 while True: temp = temperature.getTempValue()-18 print("T:", temp) ser = servo.getServoAction() if ser == 1 and CmpTempValue<40: CmpTempValue += 1 if ser == -1 and CmpTempValue>10: CmpTempValue -= 1 print("S:", CmpTempValue) if temp >= CmpTempValue: tempUi.drawTempUI(temp, 1) tempUi.drawTempNum(temp, CmpTempValue) mySong = music(song, pins=[Pin(23)]) mySong.tick() else: tempUi.drawTempUI(temp, 0) tempUi.drawTempNum(temp, CmpTempValue) mySong.stop()
遇到的主要难题及解决方法
超温后回温的图像刷新频闪问题:
一开始在在实现温度更新刷屏函数时采用的方案是每次温度变化调用两次fill_rect函数分别实现对温度的更新,猜想是应该是由于fill_rect函数的实现原因连续调用两次会造成屏幕出现频闪的现象。后来重新对需求进行分析,确定其实清屏操作只需要在回温过程的红色进行清除。最后从新设置全局变量监测屏显模式切换实现只有在模式切换时才会清屏的效果。
未来的计划或建议等
移植图形库进行图形优化,增加温度动态曲线绘制及保存功能