项目介绍
本项目是基于硬禾学堂2024年“寒假在家一起练”活动的搭配带屏12指神探的传感器扩展板卡,实现的多功能感应及报警系统。该系统可以检测门窗的开关状态,人体经过或靠近检测,可在LCD屏上显示基本信息并通过蜂鸣器发出报警状态音。此外,本项目还通过PID自动控制算法集成了恒温控制系统,目标温度可以通过按键和拨轮控制。
硬件介绍
本项目所采用的硬件为带屏版的12指神探和传感器扩展板。其中带屏版的12指神探采用树莓派Pico核心芯片RP2040作为主控芯片,配备了一块240*240分辨率的LCD彩屏以及两个可程控按键和一个拨轮。其通过Type C的USB接口提供供电、下载以及通信的功能。传感器扩展板上配有常见的传感器和功能模块,包括麦克风、蜂鸣器、红外收发、霍尔效应开关、加热电阻、温湿度传感器、六轴传感器、接近/环境光/IR传感器和颜色传感器。
丰富的硬件资源为项目的开发提供了坚实的基础。
硬件框图
项目的硬件框图如下图所示,主要使用的硬件资源有霍尔传感器、温湿度传感器、接近传感器、LCD显示屏、蜂鸣器和加热电阻。另外还用RP2040主控芯片内部集成的温度传感器。
其中接近传感器和温湿度传感器通过I2C协议进行通信,LCD显示屏通过SPI协议进行通信,加热电阻通过PWM波进行控制,蜂鸣器和霍尔传感器通过IO的高低电平来控制和传感。
设计思路
本项目为多功能感应及报警系统,为了实现这一目标,主要设计思路为信息的输入与输出,通过传感器如霍尔传感器、温湿度传感器等获取环境信息,并对信息进行处理,处理后的信息由LCD显示屏和蜂鸣器进行输出,用作报警。此外由于系统中集成了恒温控制系统,通过加热电阻实现温度的控制。
软件流程图
图片展示
主要代码片段及说明
为了使代码具有清楚的设计架构,将各个传感器和功能模块封装了独立的函数,在主函数中进行调用。主函数从各个模块进行import。
from test.detect import near_detect, rsinit
from test.hall import hall_detect
from test.heat import heat_res
from test.nsht30 import nsht30_read, nsht30_send
from test.tem import thermometer
from test.beep import beep_beep
首先完成初始化工作。定义了各个外设变量,包括spi,button,hall等。然后在循环外面将一些固定显示的内容提前刷新出来,以节约循环中的时间消耗。最大的心思是将各个显示信息的名称放在循环外,在循环中只刷新传感信息。
heat_r = Pin(22,Pin.OUT, value=0) #B
hpwm = PWM(heat_r)
hpwm.freq(2000)# 500us
nsh = I2C(0, scl=Pin(21), sda=Pin(20))
hall_de = Pin(24,Pin.IN, Pin.PULL_UP) #B
sensorTemp = ADC(4)
detect_i2c = I2C(0, scl=Pin(21), sda=Pin(20))
rsinit(detect_i2c)
beep = Pin(23,Pin.OUT, value=0) #B
display.fill(st7789.BLACK)
display.text(font2, " Multi-Function", 0, 0, RED, GREEN)
display.text(font2, "Sensin&AlarmSys", 0, 34, RED, GREEN)
display.text(font2, "Ttem:", 0*16,34*2)
display.text(font2, "Atem:", 0*16,34*3)
display.text(font2, "Ctem:", 0*16,34*4)
display.text(font2, "Body:", 0*16,34*5)
display.text(font2, "Door:", 0*16,34*6)
display.text(font2, "25 ", 6*16,34*2, MAGENTA, CYAN)
display.text(font2, "25 ", 6*16,34*3, MAGENTA, CYAN)
display.text(font2, "25 ", 6*16,34*4, MAGENTA, CYAN)
display.text(font2, "far ", 6*16,34*5, BLUE, YELLOW)
display.text(font2, "open ", 6*16,34*6, BLUE, YELLOW)
主循环的主要内容与软件流程图基本一致。首先检测按键状态,按键检测附加了按键消抖功能。这里主要使用了波轮上的三个按键输入,包括左波,右波与按下。左波的效果是控制恒温系统的温度目标减小,右波的效果是控制目标温度增加。调整后的目标温度不会立即生效,而是要等到拨轮中键按下后才会生效。目标温度的范围做了限制,调整区间为5-60摄氏度,温度过低没有实际意义,温度过高容易损坏扩展板,也具有烫伤风险。
buttonValueR = buttonR.value()
if(buttonValueR == 0):
sleep_ms(5)
del_flag1 = 1
if(buttonValueR == 0):
bul_cnt = bul_cnt + 1
if(bul_cnt == 1):
bul_cnt = 0
if(Ttem_t < 60):
Ttem_t = Ttem_t + 1
else:
bul_cnt = 0
else:
del_flag1 = 0
bul_cnt = 0
之后是霍尔传感器的检测,霍尔传感器检测磁场情况,并通过电平信号进行指示。为了方便对实际情况进行报警,当霍尔传感器当前检测的电平信号与上一次检测的电平信号不一致时,产生变化标志信号。
# HALL
hal_pre = hal_val
hal_val = hall_detect(hall_de) # 1 OPEN 0 CLOS
if(hal_val!=hal_pre):
hal_dif = 1
else:
hal_dif = 0
之后是接近传感器的检测,其与霍尔传感器类似,但其需要通过I2C协议进行读写配置,具体实现方式可以参见附件中的代码。其同样会在两次检测信号不一致时,产生变化标志信号。
# DETECT
det_pre = det_val
det_val = near_detect(detect_i2c) # 1 NEAR 0 FAR
if(det_val!=det_pre):
det_dif = 1
else:
det_dif = 0
之后是主控芯片内部集成的温度传感器检测,用于显示主控芯片的工作温度。
# TEM
core_tem = thermometer(sensorTemp)
def thermometer(sensorTemp):
temp_a = 0
for i in range(5):
read = sensorTemp.read_u16() * 3.3/(65535)
temp = 27 - (read - 0.706) / 0.001721
temp_a += temp
return round(temp_a/5.0, 1)
之后是蜂鸣器报警部分的实现。根据霍尔传感器和接近传感器的变化标记进行报警,两种报警分别采用不同的声音频率,用以区分报警对应的来源。
#beep
if(hal_dif == 1):
hbeep_flag = 1
hbeep_cnt = 0
if(hbeep_flag):
beep_beep(200, 200) #0.4ms的周期,重复200次,80ms
hbeep_cnt = hbeep_cnt + 1
if(hbeep_cnt==2):
hbeep_flag = 0
def beep_beep( times, fre_t):
val = fre_t
i=0
while(i<times):
i=i+1
sleep_us(val)
beep.value(1)
sleep_us(val)
beep.value(0)
之后是数据显示刷新部分。这里为了提高显示屏的刷新率,只对必要内容进行刷新。如目标温度只在通过拨轮改变以后才刷新对应数据,霍尔传感器和接近传感器的信号只在产生对应变化标志信号时进行刷新。
# disp
# display.text(font2, str(Ttem_t)+" "+str(Atem)+" "+str(hal_val)+" "+str(det_val)+" "+str(core_tem), 0, 190)
if(del_flag1==1 or del_flag2==1):
display.text(font2, str(Ttem_t)+' ', 6*16,34*2, MAGENTA, CYAN)
display.text(font2, str(Atem), 6*16,34*3, MAGENTA, CYAN)
display.text(font2, str(core_tem), 6*16,34*4, MAGENTA, CYAN)
if(det_dif == 1):
if(det_val==1):
display.text(font2, "near", 6*16,34*5, BLUE, YELLOW)
else:
display.text(font2, "far ", 6*16,34*5, BLUE, YELLOW)
if(hal_dif == 1):
if(hal_val==1):
display.text(font2, "open ", 6*16,34*6, BLUE, YELLOW)
else:
display.text(font2, "close", 6*16,34*6, BLUE, YELLOW)
之后是加热电阻的控制。控制的前提是传感,需要先通过温湿度传感器获取实际温度信息,再根据设定温度进行控制。由于温湿度传感器配置为单次读写模式,所以在每一次读取温度前,需要先通过I2C协议进行配置。即对温湿度芯片进行先写后读,读写之间需要一定的时间。为了保证时序要求,将I2C的写命令放在while循环的开头,而读命令放在while循环的结尾,这样便可以省去延时的时间而提高屏幕的刷新率。
# write i2c
nsht30_send(nsh)
# HAET
Atem = heat_res(hpwm, nsh, Ttem)
def heat_res(hpwm, nsh, adj):
val = nsht30_get(nsh)
if(val[0]<adj):
num = int((adj-val[0])*45000)
if(num>65535):
num = 65535
hpwm.duty_u16(num)
else:
hpwm.duty_u16(0)
return round(val[1], 1)
遇到的主要难题及解决方法
最大的困难是保障屏幕的刷新率。由于本项目没有采用中断的方式,所有程序的执行都是在while循环中进行实现,这就必须要保证,while循环的时间消耗是可控的。为次,对按键检测进行设计,对温湿度传感器的读写进行设计,对屏幕的刷新内容进行限制等等。最终将屏幕的刷新率和按键的相应时间控制在一个较为满意的范围。
其次是编程语言中的困难。由于python语言并不是自己使用的主力语言,在编程过程中使用相关语法经常需要查阅相关内容,造成很大的时间浪费。此外,对解释性语言并没有十分深刻的理解,很多时候还是以写编译型语言的方式去写解释性语言。
最后是传感器的不熟悉。本项目中使用了很多传感器,这些传感器很多需要通过寄存器配置来实现某些特定的功能。为此,我查阅了他们的数据手册,其中提供了C++语言的用例,通过将C++转换为python语言实现了对传感器的配置。
未来的计划或建议等
本次项目有两大遗憾。
一是恒温控制系统只是采用了PID中的比例项。由于室内温度环境较为简单,只采用比例项就实现了温度的稳定,因此没有加入微分和积分项。在后续的时间里会将这两项加上去,以实现更高精度和更快响应速度的恒温控制系统。
二是由于个人对面向对象设计方法并不熟悉,在将C++语言转换为python语言时,将原来面向对象的设计方法转换为了面向过程的设计方法。这一行为降低了程序的健壮性,代码也没有原有的优美,后续希望能够完善这一点。
此外,由于时间的限制,未能将颜色传感器、六轴传感器和红外发射接收纳入到项目中,后续会加强这些内容的研究。
致谢
最后,感谢硬禾学堂提供的活动和机会,感谢折腾的自己。