基于树莓派RP2040利用MMA7660重力感应传感器实现一个水平仪
基于树莓派RP2040利用MMA7660重力传感器实现一个水平仪并将结果显示在240 * 240 LCD显示屏上
标签
嵌入式系统
显示
2022寒假在家练
水平仪
tony
更新2022-03-02
南京信息工程大学
1055

项目简介:

       该项目是一个电子水平仪。使用硬禾学堂推出的基于树莓派rp2040的嵌入式系统学习平台。实现的功能有:

  • 在LCD屏上显示一个图形化的水平仪,并实时显示本设备当前的姿态(通过本平台自带的MMA7660三轴姿态传感器)
  • 可以将MMA7660三轴姿态传感器读出的数据传输给计算机,为以后利用计算机对传感器数据的处理提供便利。

项目设计思路:

       首先需要从MMA7660三轴姿态传感器中读取数据并进行处理。而后在显示屏上画出水平仪的显示框架。设定水平情况下小球(气泡)应处于显示框架的中心位置。当此平台所处的位置有倾斜应当与三轴姿态传感器的数据进行比对并处理,得到于正常情况下水平仪中小球(气泡)应处在的位置,并用 LCD屏幕显示出来。

FgpwDKcjg1DaJkdkaOHY7o657rqI

硬件介绍:

       该电子水平仪项目用到该平台的部分元件:RP2040、MMA7660、ST7789驱动的LCD屏幕。

微控制器RP2040的性能指标:

  • 双核 Arm Cortex-M0+ @ 133MHz
  • 264KB 片内RAM,内部6个独立的RAM块, 在总线中心进行交换,可以让内核和DMA并行运行而无冲突
  • 通过专用的QSPI总线可以支持最高16MB的片外Flash存储器
  • DMA控制器
  • Interpolator and integer divider peripherals
  • 30 GPIO管脚, 其中的4个可以用于模拟输入
  • 2 × UARTs, 2 × SPI控制器, 和2 × I2C控制器
  • 16 × PWM通道
  • 1 × USB 1.1控制器和PHY,支持Host和Device 
  • 8 × 树莓派可编程I/O状态机
  • USB存储启动模式并支持UF2, 可以通过拖拽进行编程
  • 7*7 56管脚的QFN封装

MMA7660FC是具有数字输出的I²C、低功耗、紧凑型电容式微机械加速度传感器,提供低通滤波器、零重力加速度偏移和增益误差补偿,并可以转化为6位数字值,用户可配置输出数据的传输速率。该器件可通过中断引脚(INT)识别传感器的数据变化、产品的朝向和姿态等。

电路图FvFNSePyoFKoOPsrjAujUEzTkOf2

水平仪显示数值与方向示例图:

LCD屏幕左上角显示的数值与小球位置的关系如下图,符合数学中的二维坐标系。

FgCiYtOJ2MOl8Mg3mHjLXrq5x5sK

水平显示:

 

Flk-ZkuCUvwoiwudtzFkGtghOnDq

直立显示:

FuSYWmCs5oO3dZjn3K2ODMnxqcx8

向左躺:

FoSTXZwPheDlkACj5z_v-PCxqODU

向右躺:

Fuga-T9NCNrZ9TVOko76k7HYG-Qe

具体项目展示请观看视频。

 

下面展示的是本项目的主文件代码:

各部分功能已经用中文注释

 



"""
初始化配置
"""
#配置3轴传感器MMA7660
i2c1 = I2C(1, scl=Pin(game_kit.accelerometer_scl), sda=Pin(game_kit.accelerometer_sda))
acc = MMA7660(i2c1)
acc.on(True)
d = bytearray(3)
r = [0 for x in range(3)]

def twos_compliment(n, nbits):
    sign_bit = 1 << nbits - 1
    sign = 1 if n & sign_bit == 0 else -1
    val = n & ~sign_bit if sign > 0 else sign * ((sign_bit << 1) - n)
    return val

def thumb_filter(a):
    return a

#配置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=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)



#开始显示程序
#显示水平仪框架
display.fill(st7789.WHITE)#设置背景
#画圆与线段
display.vline(120,0,50,st7789.BLACK)
display.vline(120,190,50,st7789.BLACK)
display.hline(0,120,50,st7789.BLACK)
display.hline(190,120,50,st7789.BLACK)
display.draw_circle(120,120,70,st7789.BLACK)

while True:
    
    acc.getSample(d)#读取传感器数据
    for i in range(3):
        r[i] = twos_compliment(d[i], 6)
    print((r[0], r[1], r[2]))#将传感器数据打印出来,为以后可能的数据处理
    display.fill_circle(117-2*r[1], 112+2*r[0], 15,st7789.GREEN)#小球(气泡)
    #在LCD屏幕上显示x、y坐标
    display.text(font1, """x:{0}""".format(-r[1]), 10, 10,st7789.BLACK,st7789.WHITE)
    display.text(font1, """y:{0}""".format(-r[0]), 10, 20,st7789.BLACK,st7789.WHITE)
    sleep(0.5)
    display.fill_circle(117-2*r[1], 112+2*r[0], 15,st7789.WHITE)#将原先的小球擦除掉
    display.fill_rect(25, 0, 50, 50, st7789.WHITE)#将原先的x、y坐标擦除
    

 

在官方提供的st7798.py库中由于缺少画圆的函数,本人自行网上搜索并添加了部分函数,画圆函数提供两个,其画圆方式不同,可为以后使用提供多种方案。代码如下:

    def draw_circle(self,xpos0, ypos0, rad, col):
        x = rad-1
        y = 0
        dx = 1
        dy = 1
        err = dx - (rad << 1)
        while x >= y:
            self.pixel(xpos0 + x, ypos0 + y, col)
            self.pixel(xpos0 + y, ypos0 + x, col)
            self.pixel(xpos0 - y, ypos0 + x, col)
            self.pixel(xpos0 - x, ypos0 + y, col)
            self.pixel(xpos0 - x, ypos0 - y, col)
            self.pixel(xpos0 - y, ypos0 - x, col)
            self.pixel(xpos0 + y, ypos0 - x, col)
            self.pixel(xpos0 + x, ypos0 - y, col)
            if err <= 0:
                y += 1
                err += dy
                dy += 2
            if err > 0:
                x -= 1
                dx += 2
                err += dx - (rad << 1)
                
    def circle(self,x,y,r,color):
        '''
        画圆
        '''
        i = r
        while i >= -r:
            delta_x = int(math.sqrt(r**2-i**2))
            self.pixel(x-delta_x,y+i,color)
            self.pixel(x+delta_x,y+i,color)
            self.pixel(x+i,y-delta_x,color)
            self.pixel(x+i,y+delta_x,color)
            i=i-1
        
    def fill_circle(self,x,y,radius,color):
        '''
        画出实心圆
        '''
        i = radius
        while i >= -radius:
            delta_x = int(math.sqrt(radius**2-i**2))
            self.hline(x-delta_x,y+i,delta_x*2,color)
            
            i=i-1

注意:此部分代码需添加在st7789.py中ST7789类中,是ST7789的库函数。

总结:

      在本项目中,小球的圆位置刷新率不高,在群友的指点下,我了解到了“局刷”这项技术(只处理显示区域颜色改变的部分,在显示区域颜色不变的区域不处理)。但是在网上搜索很多,但就是找不到关于这种方法的具体代码操作,目前小球的刷新率仍不理想。我曾注意到官方提供的lecture文件夹中ball.py中显示的小球显示非常流畅,但是不知道breakout_colourlcd240x240这个库文件中都有哪些库函数,所以这个方法只能作废。

      希望以后能够学习更多关于屏幕显示底层方面的知识,能够自己编写关于屏幕的库,以提高显示的流畅度。本项目对该平台的利用率还很低,仍有许多元件未使用。希望以后能更多了解嵌入式方面的知识,更充分的利用该平台提供的资源,做出更优秀的产品。

      通过本次项目,我对嵌入式系统有了初步的了解。通过完成项目,自己的代码阅读与编写能力有了一定的提高,发现大学的C语言课程真的如网上所言顶多算上编程入门。还有,树莓派PICO的C/C++编程环境真的好难搭建啊,目前不知为何搭建完了还用不了,只能转用micropython,就当是学习一门新的语言了……希望树莓派基金会能推出一个更适合新手的环境搭建方法。

     

 

附件下载
level.py
主要代码main
st7789.py
all code.zip
项目代码
团队介绍
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号