1 项目介绍
基于树莓派RP2040,使用micropython编程语言,利用MMA7660重力感应传感器和ST7789LCD显示器制作一个水平仪。在LCD屏上显示一款水平仪,通过一个滚动的小球或气泡,来显示当前板子的倾斜度,当板子处于水平位置的时候,小球停在屏幕的正中间,倾斜板子,小球偏移,并能够显示偏移的角度(二维信息)。
2 设计思路(框图)
我的设计思路是先分别测试实现显示器和重力传感器的功能。导入MMA7660固件,调用machine库中的I2C函数,通过查阅电路图获取引脚信息,使用getSample函数获取重力传感器的参数。导入ST7789固件,使用矩形填充函数在设计完UI界面后,我将重力传感器的参数导入,然后将这个参数转为坐标,该坐标为圆心绘制圆,以实现滚动小球的功能。
3 简单的硬件介绍
我使用的硬件有,两块亚克力板,一根USB数据线,基于树莓派RP2040的嵌入式系统学习板,其中使用到了RP2040微控制器、MMA7660重力感应传感器和ST7789LCD显示器。
4 实现的功能及图片展示
4.1 实现滚动小球的功能
使用getSample函数获取重力传感器的参数后,即为倾斜的角度,然后将这个参数转为坐标,设置半径,该坐标为圆心绘制圆,并将其显示在屏幕上。
4.2 显示倾斜角度和标尺的功能
倾斜板子,小球偏移,并将倾斜的角度显示在屏幕右上方。
5 主要代码片段及说明
先导入仓库中的board文件、st7789和mma7660固件以及字体文件,通过查看电路图获取对应引脚信息。
5.1 实现UI界面设计和RGB色彩显示功能
导入ST7789固件后,可以看到已经预设了几种颜色参数。
BLACK = const(0x0000)
BLUE = const(0x001F)
RED = const(0xF800)
GREEN = const(0x07E0)
CYAN = const(0x07FF)
MAGENTA = const(0xF81F)
YELLOW = const(0xFFE0)
WHITE = const(0xFFFF)
在主模块中,从ST7789导入需要使用到的颜色作为color参数。
from st7789 import BLUE, WHITE, RED
绘制UI界面时,可以使用ST7789中的矩形填充函数,
def fill_rect(self, x, y, width, height, color):
self.set_window(x, y, x + width - 1, y + height - 1)
chunks, rest = divmod(width * height, _BUFFER_SIZE)
pixel = _encode_pixel(color)
self.dc.on()
if chunks:
data = pixel * _BUFFER_SIZE
for _ in range(chunks):
self.write(None, data)
if rest:
self.write(None, pixel * rest)
通过设置左上角坐标,长宽参数,即可绘制主屏幕、垂直副轴和水平副轴。然后使用text函数显示标尺刻度,UI界面即可设计完成。
display.fill(BLUE)
display.fill_rect(10, 50, 180, 180, WHITE)
display.fill_rect(10, 10, 180, 30, WHITE)
display.fill_rect(200, 50, 30, 180, WHITE)
display.text(font1,"""-90""".format(a), 15, 145, BLUE, WHITE)
display.text(font1,"""-45""".format(a), 55, 145, BLUE, WHITE)
display.text(font1,"""0""".format(a), 105, 145, BLUE, WHITE)
display.text(font1,"""45""".format(a), 135, 145, BLUE, WHITE)
display.text(font1,"""90""".format(a), 170, 145, BLUE, WHITE)
display.text(font1,"""90""".format(a), 105, 55, BLUE, WHITE)
display.text(font1,"""45""".format(a), 105, 90, BLUE, WHITE)
display.text(font1,"""-45""".format(a), 105, 175, BLUE, WHITE)
display.text(font1,"""-90""".format(a), 105, 215, BLUE, WHITE)
5.2 获取MMA7660重力感应传感器参数
通过查看电路图获取对应引脚信息,分别使用machine库中的I2C和SPI函数将两个固件的总线导入。
i2c1 = I2C(1, scl=Pin(pin_cfg.i2c1_scl), sda=Pin(pin_cfg.i2c1_sda))
acc = MMA7660(i2c1)
acc.on(True)
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)
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)
进入while true循环后,使用getSample函数获得重力传感器的参数,将其转换为坐标,使用ST7789的text函数将其显示在屏幕右上方。
display.text(font1,"""X:{0}""".format(a), 200, 10, BLUE, WHITE)
display.text(font1,"""Y:{0}""".format(c), 200, 20, BLUE, WHITE)
display.text(font1,"""Z:{0}""".format(r[2]), 200, 30, BLUE, WHITE)
然后以该坐标为圆心,设置半径,根据圆的极坐标公式分别绘制主界面和垂直、水平轴的滚动小球。
for theta in range(60):
x = int(a + 100 + 14 * math.cos(theta))
y = int(b + 140 + 14 * math.sin(theta))
display.fill_rect(x, y, 3, 3, RED)
x = int(a + 100 + 14 * math.cos(theta))
y = int(24 + 14 * math.sin(theta))
display.fill_rect(x, y, 3, 3, RED)
x = int(214 + 14 * math.cos(theta))
y = int(b + 140 + 14 * math.sin(theta))
display.fill_rect(x, y, 3, 3, RED)
最后使用矩形绘制函数不断刷新界面即可。
display.fill_rect(a + 85, b + 125, 33, 33, WHITE)
display.fill_rect(a + 85, 10, 32, 30, WHITE)
display.fill_rect(200, b + 125, 30, 32, WHITE)
display.fill_rect(200, 10, 40, 30, WHITE)
display.fill_rect(99, 50, 3, 180, BLUE)
display.fill_rect(10, 139, 180, 3, BLUE)
display.fill_rect(54, 10, 3, 30, BLUE)
display.fill_rect(99, 10, 3, 30, BLUE)
display.fill_rect(144, 10, 3, 30, BLUE)
display.fill_rect(200, 94, 30, 3, BLUE)
display.fill_rect(200, 139, 30, 3, BLUE)
display.fill_rect(200, 184, 30, 3, BLUE)
6 遇到的主要难题及解决方法
6.1 如何在屏幕上绘制圆
可以通过math库使用圆的极坐标公式绘制,也可以使用ST7789的blit_buffer函数导入圆的图片文件。
x = int(a + 100 + 14 * math.cos(theta))
y = int(b + 140 + 14 * math.sin(theta))
6.2 如何刷新屏幕
通过使用ST7789的矩形填充函数,每绘制一次就在圆球所在区域进行局部刷新,然后重新绘制坐标线和圆,不断重复上述步骤。
6.3 屏幕刷新速度过慢的问题
屏幕刷新速度过慢可能是因为使用数学函数绘制的问题,可除了上述使用局部刷新的方法之外,通过使用矩形填充函数绘制4乘4矩形代替绘制单个像素点,可提升刷新速度。
6.4 心得体会
虽然我已经是一名大三的学生,但是在此之前我完全没有接触过和该项目有关的软硬件知识。由于我所学的专业是通信工程,在此之前只浅显地接触过C语言,而且对什么是嵌入式、库、调用和python等知识不甚了解。因此,在刚开始着手进行项目时,我因为对这个树莓派RP2040一无所知,在畏难情绪影响下,我并没有打算脚踏实地从头开始学起,而是盘算着走个捷径。因此我在网上查找这十个项目的源代码,希望能自己拼接一下就能在板卡上跑起来,然后直接提交了事。然而,因为缺乏相关知识,我甚至不知道如何运行程序,看着IED上的不断报错,我觉得自己不能再浪费时间。我下定决心从头学习一遍
考虑到我使用的语言是micropython,所以我打算先从头开始,学习一遍python语言。我大概花了两三天左右学完了python,了解了python的调用方法,比如python的调用路径存放在sys.path变量里面等等知识,虽然我们现在所做的项目并没有用到这些。在学完python后,我确定了选择水平仪作为我的项目,根据该项目的要求,我又研究了该树莓派平台一些硬件的使用,譬如RP2040、ST7789和MMA7660的使用,在分别测试其功能后,我将各个模块拼接了起来,并最终完成了该项目。
7 未来的计划或建议等
我已经成功实现了水平仪的滚动小球和倾斜角度显示的功能,但目前的缺点是刷新速度太慢,滚动惯性不灵敏等问题,我计划下一步优化绘制和刷新方式,增加过滤器,提升刷新率和小球滚动效果,并更换UI界面为图片,不再使用函数绘制,以提高美观性。