电路原理图:
- 一、 项目要求
- 将多张照片保存在SD卡中,能够在240*240的LCD屏幕上以至少3种不同的切换模式轮流播放照片,模式的切换由按键控制。
- 播放照片的同时,播放背景音乐,通过蜂鸣器或耳机插孔输出。
- 利用姿态传感器,旋转板卡,照片可以自动旋转,保证无论板卡是什么方向,照片的方向都是正的。
- 二、 设计思路
- 播放照片。照片文件存储在SD卡中,树莓派通过接口读取SD卡中的照片文件,将照片数据传输到显示屏中显示。
- 播放音乐。在文件中按照一定格式写出音符,在while循环中播放。一次循环播放一个音符。
- 图片切换模式的选择。更改切换模式使用一个按键控制,在程序中可以使用中断函数。按下按键后,标记符号做出相应变化,选择相应的切换模式。
- 切换照片。本次实验我使用按键来控制播放下一张照片,而非自动切换。这一点也是通过中断函数来实现的。
- 姿态检测。在while循环中,每一次循环都要检测一下当前姿态,这通过调用函数来实现。如果姿态有变化,则要重新加载图片。
- 三、 设计步骤
-
照片的读取和播放模式的切换。
本实验使用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的二进制文件,以便树莓派读取。
读取文件时,使用文件指针,并将读到的数据保存在缓存器中,缓存器中的数据将以像素点的形式展示在屏幕中。
用不同的模式来播放照片,就是要规定文件指针移动的规则和屏幕显示像素点的顺序。
根据我们的实验要求,我们就写了三种照片切换模式,如下所示。
模式一
模式二
模式三
其代码如下所示。
其中的标记符way代表了第几种切图模式。它的值通过中断函数的触发来改变。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)
def ways(self): global way if way==2: way=0 else: way=way+1 sleep(0.01)
- 音乐的播放
音乐的播放需要用到另一个优秀同学写的模块buzzer_music,里面写了音乐music的类,因此在我的函数中,只要写出符合这一模块的格式的音符即可。对于音符,我挑选了较为简单的《生日歌》,播放音乐的流程大致是:一个while循环中,播放一个音符,若在播放音符之间有中断函数触发,则暂停音乐的播放,直至中断处理完成,则继续播放音符。
这样的播放方式有一些缺点,第一,如果在播放音符的过程中中断触发,那么蜂鸣器会一直保持这个音符不停播放;第二,因为图片切换速度较慢,切换图片的过程中蜂鸣器处于等待过程,这会导致两个音符相隔的时长变长。
- 姿态变化引起照片方向的调整
重力传感器是通过I2C的方式与树莓派相连。当姿态一发生变化,显示屏就应当做出反映,因此程序需要时刻对传感器进行监测。由于这里的I2C接口不方便使用中断函数,这里我就直接将这个监测函数直接放在while循环中。当姿态发生变化时,因此屏幕坐标方向的变化,从而改变图片显示的方向。
姿态变化前
姿态变化后
这一函数的代码如下所示。
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
- 项目总结
实验中遇到的问题:
- 音符在while循环中播放,遇到按键中断时,音符会暂停。这导致了音乐的不连贯。我做了一个猜想,不知道能不能通过定时器中断来控制音符的播放,并将其的优先级设置比按键中断高。每隔一定时间触发定时器中断,播放一个音符,这样能保证音符播放的连贯性。不过这样的缺点是会影响播放照片的流畅性。
- 图片切换过程比较慢,尤其是对于切换模式更复杂一些的需要等待更多时间。在硬件无法改变的情况下,我只能精简程序的复杂度,尽可能简化文件移动的步骤,从而避免切换图片时间过长。