项目总结报告
一、项目简介:
该项目是一个图形化显示、超温报警的温度计。使用micropython开发基于树莓派RP2040的嵌入式系统学习平台。实现的功能有:
1、在LCD屏上显示一个图形化的温度计,并实时显示当前的温度(通过RP2040内部的温度传感器测量);
2、可以通过摇杆或按键设定报警温度阈值;
3、芯片温度超过设定的阈值,温度图示颜色变红,且蜂鸣器发出报警声音;
4、芯片降温到阈值以下,温度图示颜色变绿,蜂鸣器停止报警;
二、项目硬件介绍:
此项目完全使用基于树莓派RP2040的嵌入式系统学习平台,未外接器件。使用到了板载的RP2040 MCU、轻触按键A、摇杆、IPS LCD屏幕、蜂鸣器;使用ADC读取摇杆值和内部温度传感器温度,使用PWM驱动蜂鸣器发声,使用SPI驱动显示屏,使用GPIO读取按键A;
三、项目设计思路:
1、图形化温度计:使用静态背景图像加动态矩形条的形式显示。绘制温度计外形并将图像转换成240*240分辨率、24位色彩,再将其转换成bin文件用于加载显示(实际上可以计算好后直接绘制线条);在合适位置绘制上下两个矩形条模拟温度计内液体及空气,改变矩形条长度即可模拟改变液面高度,改变颜色即可模拟改变液体颜色;
2、设置报警温度阈值:按下按键A并保持进入设置阈值模式,左右摇动摇杆,通过ADC读取电阻值并映射到0到80作为阈值设定值,松开按键A即可保存设定;使用一根横轴和一个矩形块表示阈值设定值,可以形象地调节阈值;
3、报警:当ADC读取计算得到温度超过阈值时,输出PWM驱动蜂鸣器发声,模拟液体颜色由绿色变红色;当温度回落至阈值以下后蜂鸣器停止,液体变回绿色;
四、实现功能展示:
五、主要代码及说明:
1、绘制圆形(增加在st7789.py中),原理是利用绘制许多水平直线形成圆形:
import math
def fill_circle(self, x, y, radius, color):
"""
Draw a circle at the given location, size and filled with color.
Args:
x (int): Center x coordinate
y (int): Center y coordinate
radius (int): Radius in pixels
color (int): 565 encoded color
"""
ii = radius
while ii >= -radius :
delta_x = int(math.sqrt(radius**2 - ii**2))
self.hline(x-delta_x, y+ii, delta_x*2, color)
ii=ii-1
2、定义常量、变量,包括图片文件地址、显示坐标、温度阈值、屏幕引脚、屏幕像素等:
image_file0 = "/back.bin" #图片文件地址
image_file1 = "/logo.bin"
ther_x = 113
ther_y = 160
slider_x = 110
slider_y = 217
ther_color = st7789.GREEN
threshold = 40
threshold_temp = 40
st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
3、初始化外设,包括初始化SPI、LCD、ADC、GPIO、PWM:
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
print(spi0)
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)
Joy_x = machine.ADC(29)
Joy_y = machine.ADC(28)
buttonB = machine.Pin(5,machine.Pin.IN, machine.Pin.PULL_UP) #B
buttonA = machine.Pin(6,machine.Pin.IN, machine.Pin.PULL_UP) #A
Buzz = machine.PWM(machine.Pin(23))
SensorTemp = machine.ADC(4)
offset = 3.3/65535
4、开机画面,先显示文字信息,然后显示硬禾LOGO:
display.fill(st7789.BLACK)
display.text(font2, "Hello! RPi Pico", 10, 10)
display.text(font2, "HGF", 10, 40)
display.text(font2, "MicroPython", 35, 100)
display.text(font2, "EETREE", 35, 150)
display.text(font2, "www.eetree.cn", 30, 200)
utime.sleep(1)
f_image = open(image_file1, 'rb')
for column in range(1,240):
buf=f_image.read(480)
display.blit_buffer(buf, 1, column, 240, 1)
utime.sleep(1)
5、温度计初始化显示,显示静态背景、阈值滑块及文字描述:
f_image = open(image_file0, 'rb')
for column in range(1,240):
buf=f_image.read(480)
display.blit_buffer(buf, 1, column, 240, 1)
display.hline(30, 222, 180, st7789.BLACK)
display.text(font1, "Temp:", 10, 60, st7789.BLACK, st7789.WHITE)
display.text(font1, "Thre:", 10, 100, st7789.BLACK, st7789.WHITE)
display.fill_rect(slider_x, slider_y, 10, 10, st7789.BLACK)
display.text(font1, str(threshold_temp), 52, 100, st7789.BLACK, st7789.WHITE)
6、温度计主要功能(while True内),测量并显示温度,超过阈值报警:
display.fill_circle(121,170,18,ther_color)
temperature = round(27 - (SensorTemp.read_u16()*offset - 0.706)/0.001721,2)
print(temperature)
display.text(font1, str(temperature)+' ', 52, 60, st7789.BLACK, st7789.WHITE)
if temperature >= threshold :
ther_color = st7789.RED
Buzz.freq(500)
Buzz.duty_u16(500)
elif temperature <= threshold-1 :
ther_color = st7789.GREEN
Buzz.deinit()
ther_y = int(153 - temperature*1.53)
display.fill_rect(ther_x, 30, 17, ther_y-30, st7789.WHITE)
display.fill_rect(ther_x, ther_y, 17, int(temperature*1.7), ther_color)
7、阈值设置功能(while True内),按下按键A进入阈值设置,松开退出并保存:
if buttonA.value() == 0 :
utime.sleep(0.05)
while buttonA.value() == 0 :
threshold_temp = int( 40+(Joy_x.read_u16()-32768)/830)
print(threshold_temp)
display.fill_rect(slider_x, slider_y, 10, 10, st7789.WHITE)
display.hline(slider_x, 222, 10, st7789.BLACK)
slider_x = 38+int(threshold_temp*2)
display.fill_rect(slider_x, slider_y, 10, 10, st7789.BLACK)
display.text(font1, str(threshold_temp)+' ', 52, 100, st7789.BLACK, st7789.WHITE)
else :
threshold = threshold_temp
六、主要难题及解决方法:
显示图形化的温度计:分解图形,使用绘制组件和固定背景结合的方式实现,把模拟的温度计图形分解为背景、白色矩形条、绿色(或红色)矩形条、绿色(或红色)圆形;
七、未来的计划或建议:
通过此次寒假活动,了解学习了micropython的开发方式,对使用交互式语言开发单片机有了更多理解,未来会进一步学习应用;
八、源代码:
1、st7789.py(基于硬禾demo,故只列出增加部分):
import math
def fill_circle(self, x, y, radius, color):
"""
Draw a circle at the given location, size and filled with color.
Args:
x (int): Center x coordinate
y (int): Center y coordinate
radius (int): Radius in pixels
color (int): 565 encoded color
"""
ii = radius
while ii >= -radius :
delta_x = int(math.sqrt(radius**2 - ii**2))
self.hline(x-delta_x, y+ii, delta_x*2, color)
ii=ii-1
2、main.py:
import uos
import machine
import utime
import st7789 as st7789
from fonts import vga2_8x8 as font1
from fonts import vga1_16x32 as font2
import random
import framebuf
#==============================================
image_file0 = "/back.bin" #图片文件地址
image_file1 = "/logo.bin"
ther_x = 113
ther_y = 160
slider_x = 110
slider_y = 217
ther_color = st7789.GREEN
threshold = 40
threshold_temp = 40
st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
print(uos.uname())
#----------------------------------------------
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
print(spi0)
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)
Joy_x = machine.ADC(29)
Joy_y = machine.ADC(28)
buttonB = machine.Pin(5,machine.Pin.IN, machine.Pin.PULL_UP) #B
buttonA = machine.Pin(6,machine.Pin.IN, machine.Pin.PULL_UP) #A
Buzz = machine.PWM(machine.Pin(23))
SensorTemp = machine.ADC(4)
offset = 3.3/65535
#==============================================
print("Thermometer by HGF")
display.fill(st7789.BLACK)
display.text(font2, "Hello! RPi Pico", 10, 10)
display.text(font2, "HGF", 10, 40)
display.text(font2, "MicroPython", 35, 100)
display.text(font2, "EETREE", 35, 150)
display.text(font2, "www.eetree.cn", 30, 200)
utime.sleep(1)
f_image = open(image_file1, 'rb')
for column in range(1,240):
buf=f_image.read(480)
display.blit_buffer(buf, 1, column, 240, 1)
utime.sleep(1)
f_image = open(image_file0, 'rb')
for column in range(1,240):
buf=f_image.read(480)
display.blit_buffer(buf, 1, column, 240, 1)
display.hline(30, 222, 180, st7789.BLACK)
display.text(font1, "Temp:", 10, 60, st7789.BLACK, st7789.WHITE)
display.text(font1, "Thre:", 10, 100, st7789.BLACK, st7789.WHITE)
display.fill_rect(slider_x, slider_y, 10, 10, st7789.BLACK)
display.text(font1, str(threshold_temp), 52, 100, st7789.BLACK, st7789.WHITE)
#==============================================
while True:
display.fill_circle(121,170,18,ther_color)
temperature = round(27 - (SensorTemp.read_u16()*offset - 0.706)/0.001721,2)
print(temperature)
display.text(font1, str(temperature)+' ', 52, 60, st7789.BLACK, st7789.WHITE)
if temperature >= threshold :
ther_color = st7789.RED
Buzz.freq(500)
Buzz.duty_u16(500)
elif temperature <= threshold-1 :
ther_color = st7789.GREEN
Buzz.deinit()
ther_y = int(153 - temperature*1.53)
display.fill_rect(ther_x, 30, 17, ther_y-30, st7789.WHITE)
display.fill_rect(ther_x, ther_y, 17, int(temperature*1.7), ther_color)
if buttonA.value() == 0 :
utime.sleep(0.05)
while buttonA.value() == 0 :
threshold_temp = int( 40+(Joy_x.read_u16()-32768)/830)
print(threshold_temp)
display.fill_rect(slider_x, slider_y, 10, 10, st7789.WHITE)
display.hline(slider_x, 222, 10, st7789.BLACK)
slider_x = 38+int(threshold_temp*2)
display.fill_rect(slider_x, slider_y, 10, 10, st7789.BLACK)
display.text(font1, str(threshold_temp)+' ', 52, 100, st7789.BLACK, st7789.WHITE)
else :
threshold = threshold_temp
#break
3、vga1_16x32.py、vga2_8x8.py均使用硬禾demo,故不列出。