2021暑假一起练-用树莓派pico做了一个带有背景音乐的数码相框
基于树莓派pico及其扩展板制作一个数码相框,能够播放背景音乐,有不同的切图模式以及能够跟随板子的旋转来调整照片显示方向。
标签
树莓派
嵌入式系统
PICO
Irving
更新2021-09-16
1291

电路原理图:

Fny7hzNScXCOrdM37MhPUinMFjcs

  • 一、 项目要求
  1. 将多张照片保存在SD卡中,能够在240*240的LCD屏幕上以至少3种不同的切换模式轮流播放照片,模式的切换由按键控制。
  2. 播放照片的同时,播放背景音乐,通过蜂鸣器或耳机插孔输出。
  3. 利用姿态传感器,旋转板卡,照片可以自动旋转,保证无论板卡是什么方向,照片的方向都是正的。
  • 二、 设计思路
  1. 播放照片。照片文件存储在SD卡中,树莓派通过接口读取SD卡中的照片文件,将照片数据传输到显示屏中显示。
  2. 播放音乐。在文件中按照一定格式写出音符,在while循环中播放。一次循环播放一个音符。
  3. 图片切换模式的选择。更改切换模式使用一个按键控制,在程序中可以使用中断函数。按下按键后,标记符号做出相应变化,选择相应的切换模式。
  4. 切换照片。本次实验我使用按键来控制播放下一张照片,而非自动切换。这一点也是通过中断函数来实现的。
  5. 姿态检测。在while循环中,每一次循环都要检测一下当前姿态,这通过调用函数来实现。如果姿态有变化,则要重新加载图片。
  •  三、 设计步骤
  1. 照片的读取和播放模式的切换。

    本实验使用micro python语言编程,在程序中,我们通过Soft SPI使SD卡和树莓派连接。这里面需要用到sdcard模块中的SDCard类的,这个模块我是搬运了其他优秀的同学写的模块。关于SD卡的连接,关键的参数设置如下所示。


    # 连接SD卡
    sd_spi= machine.SoftSPI(baudrate=1000000,polarity=0,bits=8,firstbit=SPI.MSB,sck=Pin(17), mosi=Pin(18), miso=Pin(19))
    print("sd_spi:",sd_spi)
    sd=sdcard.SDCard(spi=sd_spi,cs=machine.Pin(22,machine.Pin.OUT))
    sd.init_card()
    
    uos.mount(sd,'/sd')
    uos.chdir('sd/')
    print("SD_Listdir:",uos.listdir())

    我在SD卡中预先放置了四个图片文件,不过在此之前,需要把图片文件转化为扩展名为bin的二进制文件,以便树莓派读取。

    读取文件时,使用文件指针,并将读到的数据保存在缓存器中,缓存器中的数据将以像素点的形式展示在屏幕中。

    用不同的模式来播放照片,就是要规定文件指针移动的规则和屏幕显示像素点的顺序。

    根据我们的实验要求,我们就写了三种照片切换模式,如下所示。

     

     

     

    模式一

    Fsu4jWN1pE6tyI2TZMOf9NN3vlhL

     

     

    模式二

    Fvx3iR3q-x-QDHBWfAXCnli3V9Kb

    模式三

    Fmu603BupAu9XU627Vwp7W5eXwQo  

    其代码如下所示。

    def displayimag():
        global i#指第几张图
        global way#第几种切图模式
        if way==0:#第一种切图模式
            if i==0:
                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)
            elif i==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)
            elif i==2:
                f_image = open(image_file2, 'rb')
                for column in range(1,240):
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column, 240, 1)
            elif i==3:
                f_image = open(image_file3, 'rb')
                for column in range(1,240):
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column, 240, 1)
        elif way==1:#第二种切图模式
            if i==0:
                f_image = open(image_file0, 'rb')
                for column in range(1,81):
                    f_image.seek((column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+80, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+160, 240, 1)
            elif i==1:
                f_image = open(image_file1, 'rb')
                for column in range(1,81):
                    f_image.seek((column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+80, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+160, 240, 1)
            elif i==2:
                f_image = open(image_file2, 'rb')
                for column in range(1,81):
                    f_image.seek((column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+80, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+160, 240, 1)
            elif i==3:
                f_image = open(image_file3, 'rb')
                for column in range(1,81):
                    f_image.seek((column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+80, 240, 1)
                    f_image.seek(80*480,1)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+160, 240, 1)
        elif way==2:#第三种切图模式
            if i==0:
                f_image = open(image_file0, 'rb')
                for column in range(1,121):
                    f_image.seek((120-column)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, 121-column, 240, 1)
                    f_image.seek((120+column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+120, 240, 1)
            elif i==1:
                f_image = open(image_file1, 'rb')
                for column in range(1,121):
                    f_image.seek((120-column)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, 121-column, 240, 1)
                    f_image.seek((120+column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+120, 240, 1)
            elif i==2:
                f_image = open(image_file2, 'rb')
                for column in range(1,121):
                    f_image.seek((120-column)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, 121-column, 240, 1)
                    f_image.seek((120+column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+120, 240, 1)
            elif i==3:
                f_image = open(image_file3, 'rb')
                for column in range(1,121):
                    f_image.seek((120-column)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, 121-column, 240, 1)
                    f_image.seek((120+column-1)*480,0)
                    buf=f_image.read(480)
                    display.blit_buffer(buf, 1, column+120, 240, 1)
    
    其中的标记符way代表了第几种切图模式。它的值通过中断函数的触发来改变。
    def ways(self):
        global way
        if way==2:
            way=0
        else:
            way=way+1
        sleep(0.01)
    
  2. 音乐的播放

    音乐的播放需要用到另一个优秀同学写的模块buzzer_music,里面写了音乐music的类,因此在我的函数中,只要写出符合这一模块的格式的音符即可。对于音符,我挑选了较为简单的《生日歌》,播放音乐的流程大致是:一个while循环中,播放一个音符,若在播放音符之间有中断函数触发,则暂停音乐的播放,直至中断处理完成,则继续播放音符。

    这样的播放方式有一些缺点,第一,如果在播放音符的过程中中断触发,那么蜂鸣器会一直保持这个音符不停播放;第二,因为图片切换速度较慢,切换图片的过程中蜂鸣器处于等待过程,这会导致两个音符相隔的时长变长。

  3. 姿态变化引起照片方向的调整

    重力传感器是通过I2C的方式与树莓派相连。当姿态一发生变化,显示屏就应当做出反映,因此程序需要时刻对传感器进行监测。由于这里的I2C接口不方便使用中断函数,这里我就直接将这个监测函数直接放在while循环中。当姿态发生变化时,因此屏幕坐标方向的变化,从而改变图片显示的方向。

    姿态变化前

    FtsP0s2818pjXiBGp-AbvU_cLNXJ  

     

    姿态变化后

    Fn9WjI8xdDa8yG6JK8g7yO0XYMga  

    这一函数的代码如下所示。

    def posture():
        global last_pose
        global pose
        global flag
    
        TILT=mma7660.readfrom_mem(76, 3, 8, addrsize=8) # 姿态数据读取
    #     print(bin(TILT[0])) #输出读取到的TILT[0]值,即mma7660检测到的位置信息
        if (TILT[0]==0b00000000 or TILT[0]==0b00000001 or TILT[0]==0b00000010):
            pose=0 # 位置状态Unkown,则默认为Up
            display.rotation(0)
            display.xstart = 0
            display.ystart = 0
        if (TILT[0]==0b00011000 or TILT[0]==0b00011001 or TILT[0]==0b00011010):
            pose=0 # 位置状态Up
            display.rotation(0)
            display.xstart = 0
            display.ystart = 0
        if (TILT[0]==0b00001000 or TILT[0]==0b00001001 or TILT[0]==0b00001010):
            pose=3 # 位置状态Right
            display.rotation(3)
            display.xstart = 80
            display.ystart = 0
        if (TILT[0]==0b00010100 or TILT[0]==0b00010101 or TILT[0]==0b00010110):
            pose=2 # 位置状态Down
            display.rotation(2)
            display.xstart = 0
            display.ystart = 80
        if (TILT[0]==0b00000100 or TILT[0]==0b00000101 or TILT[0]==0b00000110):
            pose=1 # 位置状态Left
            display.rotation(1)
            display.xstart = 0
            display.ystart = 0
            
        if last_pose!=pose:
            display.fill(st7789.BLACK)
            flag=0
            last_pose=pose
        return
    
  • 项目总结 

    实验中遇到的问题:

    1. 音符在while循环中播放,遇到按键中断时,音符会暂停。这导致了音乐的不连贯。我做了一个猜想,不知道能不能通过定时器中断来控制音符的播放,并将其的优先级设置比按键中断高。每隔一定时间触发定时器中断,播放一个音符,这样能保证音符播放的连贯性。不过这样的缺点是会影响播放照片的流畅性。
    2. 图片切换过程比较慢,尤其是对于切换模式更复杂一些的需要等待更多时间。在硬件无法改变的情况下,我只能精简程序的复杂度,尽可能简化文件移动的步骤,从而避免切换图片时间过长。
附件下载
src.zip
源代码
团队介绍
浙江大学信息与电子工程学院
团队成员
Irving
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号