1.1.1 娱乐助手简介及框架 (1) 娱乐助理系统介绍:该系统的主要设计目标是在实验箱上进行娱乐相关操作,并在液晶显示屏上显示相关操作流程。因此,本主题设计的系统主要完成三个任务:1。显示界面的设计和实现,系统使用液晶显示屏完成任务;2。娱乐助理程序的设计和编写;3。用户信息输入的收集。 (2) 娱乐助手的总体框架:根据系统的主要功能,将娱乐助手分为三部分,具体参考图1.1:
图1.1 系统总体框架图
1.1.2 划分和描述系统功能模块 参照上述总体框架,本文研究的娱乐助手系统可分为以下四个功能模块: (1) 系统初始化模块:该模块是系统的基本模块,负责系统界面的初始化和模块显示。 (2) 娱乐选择模块:该模块是整个系统中最关键的模块。它负责处理用户发出的控制请求。如果用户调用某个功能,主程序将跳转到相关程序代码段。调用功能模块后,调用系统显示模块。 (3) 系统输入控制模块:该模块以矩阵键盘为输入端,用户通过键盘选择功能和信息输入。键盘扫描程序通过扫描按钮收集输入信息。输入控制程序筛选和包装信息。 (4) 通过系统显示控制模块:LCD显示功能选择、输入和游戏等信息。 1.1.3 系统使用说明 本文研究的系统是一个简单的娱乐助手系统。由于硬件条件的限制,该系统缺乏一些市场娱乐系统的可操作性和娱乐性。为了方便用户使用该系统,本文对该系统的使用制定了一些规定,如下所述。 (1) 功能选择界面。 该界面显示四大选项,包括猜数字游戏、MP3播放、蜂鸣器播放音乐、键盘弹钢琴等四种娱乐功能,进入系统后可通过矩阵键盘输入1、2、3、4种功能进行选择。 (2) 猜数字界面 该界面程序将有10个随机数字,每个随机数字将使用LED显示灯的形式,用户需要输入键盘读取的数字,然后LCD提示高、低、正确。 (3) MP3播放界面 界面将被调用Madplay,播放的音乐信息显示在超级终端上。 (4) 蜂鸣器音乐界面 该界面可通过蜂鸣器释放内置的蜂鸣器节奏,达到蜂鸣器的音乐效果。 (5) 键盘钢琴界面 按下界面时,按钮可以发出1-7音调*返回选择界面时。 1.2.设计和实现娱乐选择模块 1.2.1 系统设计要求 本文采用传统的软件工程方法来分析娱乐助手的需求。通过分析实验箱的需求和现有硬件,我们制定了详细的设计要求: (1) 在选择模块操作时,按下按钮可以立即跳转到相关模块操作,如果按下其他按钮,系统将无反应。 (2) 猜数字模块,LED灯的显示应准确,按下按钮后应及时提示正确错误或按钮过慢。猜测10次后,返回功能选择模块。 (3) 在MP播放和蜂鸣器播放后,程序自动返回功能选择界面。 (4) 按下矩阵键盘后,蜂鸣器矩阵键盘后,蜂鸣器立即发出相应的音调。同时,当按下两个按钮时,程序将根据按钮的顺序调用蜂鸣器发出声音。 1.2.2 娱乐助手流程图 图1.二是娱乐助手操作流程图。
图1.2 娱乐助手流程图
1.2.3 猜测数字模块的具体实现 首先,随机调用程序的随机数LED显示函数ioctl,同时检查按钮是否按下。按下时,程序检测随机数字是否与按下数字相同。 LED电路原理图: 实验平台的核心板上有四个LED灯。四个核心板LED与处理器直接连接,连接方式简单。电路图如图3所示.3所示:
图1.3 LED电路图 左图为处理器引脚,右图为LED有些电路,线路上的标签相同,说明这两条线的电气属性直接连接,比如左图nLED_这条线和右图nLED_这条线直接连接。四个LED(LED1、LED2、LED3、LED4)采用共阳极连接方式,以LED1为例,当LED1左侧电位为低电平(即处理器相应引脚输出低电平)LED从右到左有电流流过,LED1处于导通状态,因此被点亮。当LED1左侧电位为高电平(即处理器相应引脚输出高电平)LED1上没有足够大的电流流过,LED1处于截止状态,因此未点亮。因此,控制相应的引脚输出电平可以通过控制处理器相关的引脚来实现LED亮灭的目的。
1.2.4 MP具体实现3播放器 (1) 介绍音频接口 本试验箱采用I2S接口,I2S 接口(Inter-IC Sound)飞利浦首先在20世纪80年代用于消费音频,并在一个名字中被称为LRCLK(Left/Right CLOCK)通过多路转换,将两个音频信号转换为单一的数据队列。当LRCLK左声道数据在高时传输;LRCLK右声道数据在低时传输。与PCM相比,IIS更适合立体声系统。当然,I2S辩论还支持多通道的复用,因此可以支持多声道。 S3C2440内置I2S总线接口可直接连接8/16比特的立体声CODEC,基于此开发板I2S总线的UDA1341芯片实现音频解码系统,采用芯片内部寄存器的初始化和设置L3-bus实现了总线连接控制,这里我们沿用了三星公板的设计,分别使用CPU的GPB2、GPB3、GPB实现4端口模拟L3-Bus规范的L3MODE、L3DATA、L3CLOCK,它们在初始化完UDA1341之后就不再有用了,所以这三条控制线也可以用普通的单片机模拟。
图1.4 典型的数字音频系统电路 在Linux音频设备的三个框架相继出现在系统中:OSS、ALSA和ASoC,这里Linux配置内核时,配置内核ALSA这里主要介绍驱动框架ALSA驱动。集成在嵌入式控制器中PCM、I2S或AC‘97音频接口可以通过连接外部音频解码器来实现声音AD和DA转换,如图3.4所示。 (2) Linux ALSA音频设备驱动 虽然OSS它已经很成熟了,但它毕竟是一种没有完全开放源代码的商业产品ALSA (Advanced Linux Sound Architecture)正好弥补了这个空白,符合GPL,是在Linux另一种可选的声卡驱动系统结构用于音频编程,其官方网站为 http://www.alsa-project.org/。ALSA除了像OSS除了提供一组核心驱动程序模块外,它还为简化应用程序的编写提供了相应的函数库OSS提供的基于ioctl与原始编程接口相比,ALSA使用函数库更方便。ALSA除了像OSS除了提供一组核心驱动程序模块外,它还为简化应用程序的编写提供了相应的函数库OSS提供的基于ioctl与原始编程接口相比,ALSA使用函数库更方便。ALSA主要特点有: ? 支持多种声卡设备 ? 模块化内核驱动程序 ? 支持SMP和多线程 ? 提供应用开发函数库(alsa-lib)简化应用程序开发 ? 支持OSS API,兼容OSS应用程序 ALSA 编程界面更友好,完全兼容OSS,这无疑是应用程序员的更好选择。ALSA系统包括驱动包alsa-driver、开发包 alsa-libs、开发包插件alsa-libplugins、设置管理工具包alsa-utils、其他声音相关处理小程序包alsa-tools、特殊音频固件支持包alsa- firmware、OSS接口与模拟层工具兼容alsa-oss共有7个子项目,只有驱动包包。 alsa-driver指内核驱动程序,包括硬件相关代码和一些公共代码,非常大,总代码达到数十万行;alsa-libs为应用程序提供用户空间的函数库,应用程序应包括头文件asoundlib.h,并使用共享库libasound.so;alsa-utils包含一些基础ALSA控制声卡的应用程序,如alsaconf(检测系统中声卡,写一个合适的ALSA配置文件),alsactl(控制ALSA声卡驱动的高级设置), alsamixer(基于ncurses混音器程序),amidi(用于读写ALSA RawMIDI)、amixer(ALSA声卡混音器的命令行控制),aplay(播放基于命令行的声音文件),arecord(录制基于命令行的声音文件)等。 ? 目前ALSA内核为用户提供的接口包括: ? 信息接口(Information Interface,/proc/asound) ? 控制接口(Control Interface,/dev/snd/controlCX) ? 混音器接口(Mixer Interface,/dev/snd/mixerCXDX) ? PCM接口(PCM Interface,/dev/snd/pcmCXDX) ? Raw迷笛接口(Raw MIDI Interface,/dev/snd/midiCXDX) ? 音序器接口(Sequencer Interface,/dev/snd/seq) ? 定时器接口(Timer Interface,/dev/snd/timer) 和OSS类似地,上述接口也以文件的形式提供,区别在于这些界面是提供的alsa-lib使用,而不是直接使用应用程序。最好使用应用程序alsa-lib,或更先进的接口,如jack提供的接口。 (3) madplay mad是高质量的MPEG目前支持音频解码器。MPEG-1和MPEG-2扩展到较低的采样频率,以及事实MPEG 2.5格式。实现了三个音频层次。mad不支持MPEG-2多声道音频(虽然要向后兼容)不支持AAC。 mad具有以下特点: ? 24位PCM输出 ? 计算100%定点(整数) ? 新的实现基础ISO / IEC标准 ? GNU一般公共许可证条款下(GPL) mad提供完整的24位PCM输出,应用程序使用了能够产生非常高质量的音频。即使输出设备只支持16位PCM,通过抖动和噪声整形手术,可以使用额外的分辨率来提高声音的动态范围。采用整数运算而非浮点数,非常适合架构无浮点单元。所有计算均以32位定点整数表示。mad是一种新的ISO/IEC标准执行。mad不是ISO推导参考源或任何其他代码。GPL的条款下OSI由于开源软件的认证,mad它可以自由使用其他软件,也可以立即获得商业许可评估。
1.2.5 蜂鸣器播放音乐的具体实现 蜂鸣器简介及电路原理图 驱动蜂鸣器的微处理器有两种方法:一种是PWM 另外,输出口直接驱动种是利用I/O 定时翻转电平产生驱动波形对蜂鸣器进行驱动,在本系统中,我们使用PWM输出口直接驱动方式。PWM 输出口直接驱动是利用PWM 输出口本身可以输出一定的方波来直接驱动蜂鸣器。在单片机的软件设置中有几个系统寄存器是用来设置PWM 口的输出的,可以设置占空比、周期等等,通过设置这些寄存器产生符合蜂鸣器要求的频率的波形之后,只要打开PWM 输出,PWM 输出口就能输出该频率的方波,这个时候利用这个波形就可以驱动蜂鸣器了。比如频率为2000Hz 的蜂鸣器的驱动,可以知道周期为500μs,这样只需要把PWM 的周期设置为500μs,占空比电平设置为250μs,就能产生一个频率为2000Hz 的方波,通过这个方波再利用三极管就可以去驱动这个蜂鸣器了。 在实验平台的液晶显示器左侧配有一个蜂鸣器可用作此次实验,其电路原理图如图3.5所示。
图1.5 蜂鸣器电路图 PWM是指脉冲宽度调制,它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。 脉冲宽度调制是一种模拟控制方脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。 随着电子技术的发展,出现了多种PWM技术,其中包括:相电压控制PWM、脉宽PWM法、随机PWM、SPWM法、线电压控制PWM等,而在镍氢电池智能充电器中采用的脉宽PWM法,它是把每一脉冲宽度均相等的脉冲列作为PWM波形,通过改变脉冲列的周期可以调频,改变脉冲的宽度或占空比可以调压,采用适当控制方法即可使电压与频率协调变化。可以通过调整PWM的周期、PWM的占空比而达到控制充电电流的目的。 操控PWM主要分为以下四步: (1) PWM是通过引脚TOUT0输出的,而这个引脚是与GPB0复用的,因此要实现PWM功能首先要把相应的引脚配置成TOUT输出。 (2) 再设置定时器的输出时钟频率,它是以PCLK为基准,再除以用寄存器TCFG0配置的prescaler参数,和用寄存器TCFG1配置的divider参数。 (3) 然后设置脉冲的具体宽度,它的基本原理是通过寄存器TCNTBn来对寄存器TCNTn(内部寄存器)进行配置计数,TCNTn是递减的,如果减到零,则它又会重新装载TCNTBn里的数,重新开始计数,而寄存器TCMPBn作为比较寄存器与计数值进行比较,当TCNTn等于TCMPBn时,TOUTn输出的电平会翻转,而当TCNTn减为零时,电平会又翻转过来,就这样周而复始。因此这一步的关键是设置寄存器TCNTBn和TCMPBn,前者可以确定一个计数周期的时间长度,而后者可以确定方波的占空比。由于s3c2410的定时器具有双缓存,因此可以在定时器运行的状态下,改变这两个寄存器的值,它会在下个周期开始有效。 (4) 最后就是对PWM的控制,它是通过寄存器TCON来实现的,一般来说每个定时器主要有4个位要配置(定时器0多一个死区位):启动/终止位,用于启动和终止定时器;手动更新位,用于手动更新TCNTBn和TCMPBn,这里要注意的是在开始定时时,一定要把这位清零,否则是不能开启定时器的;输出反转位,用于改变输出的电平方向,使原先是高电平输出的变为低电平,而低电平的变为高电平;自动重载位,用于TCNTn减为零后重载TCNTBn里的值,当不想计数了,可以使自动重载无效,这样在TCNTn减为零后,不会有新的数加载给它,那么TOUTn输出会始终保持一个电平(输出反转位为0时,是高电平输出;输出反转位为1时,是低电平输出),这样就没有PWM功能了,因此这一位可以用于停止PWM。 播放音乐实现 通过定义频率数组和节拍数组,调用set_buzzer_freq函数设置蜂鸣器响频率,自定义Delay函数,延时值为节拍数组的值。这样定义好的频率和节拍就可以让蜂鸣器发出制定的音乐。
1.2.5 键盘弹钢琴的具体实现 定义1-7按键分别为音调1-7,每当按下按键时就会发出制定的音调,按照特定铺子弹奏就可以发出歌曲的声音。
1.3 系统输入模块的设计与实现 1.3.1 系统输入模块功能分析 本功能模块的主要功能有三个:一、设置键盘键值;二、扫描键盘,采集按键信息;三、获取用户输入信息并进行处理。 1.3.2 矩阵式键盘原理图 矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组,在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。这样,一个8脚端口就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(共计9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。 矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,例如,行线通过电阻接正电源,并将列线所接的单片机的I/O口作为输出端,而行线所接的I/O口则作为输入。这样,当按键没有按下时,所有的输入端都是高电平,代表无键按下。列线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可 得知是否有键按下了。 矩阵键盘来确定键盘上何键被按下本实验采用的是“行扫描法”。行扫描法又称为逐行(或列)扫描查询法,是一种常见的按键识别方法,如图3.6所示键盘,介绍过程如下。 (1) 首先判断键盘中有无按键按下。驱动程序中采用中断的方式来判断有无按键按下,将矩阵键盘横行各I/O引脚与中断函数关联,当有按键按下时,程序自动跳转到中断函数中,每一行配置了特有了中断号和中断名称,从而可以识别是哪一行的按键被按下;如果没有按键按下,程序将继续等待,不会向下运行。 (2) 然后判断按键所在列的位置,在初始时刻列线所在端口为输出状态且均为低电平,按键按下后,逐列将其所对应的I/O引脚电平置为高电平,然后读取已确定的行端口电平,若为低电平,则不是该列的按键按下;若为高电平,则可以判断按键的位置就在该列。
图1.6 矩阵键盘与中央处理器的连线图 图1.6是本实验箱的矩阵键盘与中央处理器的连线图,其中键盘的纵列(col)从左到右依次连接EINT15、EINT5、EINT4和EINT3,对应芯片的引脚依次为GPG7、GPF5、GPF4和GPF3;同理在横向(irq)从上到下依次连接EINT2、EINT1、EINT13和EINT14,对应的芯片引脚为GPF2、GPF1、GPG5和GPG6。 1.3.3 矩阵式键盘测试代码分析 int main(void) { int buttons_fd; char buttons[2] = {‘0’, ‘0’}; char first_flag = 0; buttons_fd = open(“/dev/dial_key”, 0);//打开设备 if (buttons_fd < 0) { //打开设备失败 perror(“open device buttons failed!”); exit(1); } for (;;) {//持续检测键盘输入 int i; char current_buttons[2]; char realchar; if (read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons) {//等待键盘读入数据 perror(“read buttons:”); exit(1); } if(first_flag == 0)//这里first_flag没有用,没有大括号会直接往下运行 first_flag = 1; else { //判断是否和上一个按键相同 if(buttons[0]!=current_buttons[0]|| buttons[1]!=current_buttons[1]) { buttons[0] = current_buttons[0]; buttons[1] = current_buttons[1]; switch(buttons[0])//识别按键行号 { case 51: switch(buttons[1])//识别按键列号 { case 51:realchar=’1’;break; case 50:realchar=’2’;break; case 49:realchar=’3’;break; case 48:realchar=’A’;break; }break; case 50: switch(buttons[1]) { case 51:realchar=’4’;break; case 50:realchar=’5’;break; case 49:realchar=’6’;break; case 48:realchar=’B’;break; }break; case 49: switch(buttons[1]) { case 51:realchar=’7’;break; case 50:realchar=’8’;break; case 49:realchar=’9’;break; case 48:realchar=’C’;break; }break; case 48: switch(buttons[1]) { case 51:realchar=’*’;break; case 50:realchar=’0’;break; case 49:realchar=’#’;break; case 48:realchar=’D’;break; }break; } printf(“key(%c) is pressed!\n”, realchar); } } } close(buttons_fd); return 0; }
1.4 系统显示模块的设计与实现 本系统使用一块七英寸LCD液晶屏作为主要显示,并且系统基于Linux的帧缓冲对LCD进行图形界面的设计。 1.4.1 显示系统界面设计 设计图形界面时本文把系统分为功能选择界面和具体操作界面。
功能选择界面图
功能操作界面图
1.4.2 LCD设备显示原理 Framebuffer是Linux为图形设备提供的一个抽象接口,它允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。由于Linux工作在保护模式,所以用户态进程无法像DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出Framebuffer这个设备来供用户态进程实现直接写屏。在使用Framebuffer时,Linux是将显卡置于图形模式下的。Framebuffer就是模仿显卡的功能,相当于抽象的显卡硬件结构,实现了通过Framebuffer的读写直接对显存进行操作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反映在屏幕上。这种操作是抽象的、统一的。用户不必关心物理显存的位置、换页机制等具体细节,因为这些都是有Framebuffer设备驱动来完成的。Framebuffer设备还提供了若干ioctl命令,通过这些命令,可以获得显示设备的一些固定信息与显示模式有关的可变信息等[6]。 实现在LCD显示的关键是Framebuffer驱动程序的使用,利用驱动程序将LCD的显存与实验板的内存映射到一起,向映射的内存中写东西,然后刷新显存,LCD就会按照计算的位置在LCD屏幕上显示写入的数据信息。 要实现LCD的显示,首先需要清楚相关的硬件信息,包括屏幕的大小、能够映射的内存空间大小。其次,需要知道显示缓存与显示点的对应关系,而要搞清楚它们之间的关系必需弄明白液晶显示屏在当前显示状态下的显示灰度。灰度级别能够控制LCD显示的色彩信息,并且能够确定每一个像素是由多少位来控制的,如果1级灰度,那么在此情况下LCD只可以显示黑白两种颜色,一个bit位就可以一个像素点,也就是说一个内存单元可以容纳8个像素点的信息,只有了解了这些才能在写显存的时候确定好像素的颜色和位置等信息[7]。 1.4.3 字符的显示实现 设计思路是使用字模提取软件将A-Z等字模提取出来,然后调用自定义的wirte_single函数通过Framebuffer的方式显示在屏幕的指定位置。显示代码如下: struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; char *fbp = 0; void wirte_single(int lenth,int height,char c[][1]) { int x = 0, y = 0,z = 0; long int location = 0; int b,g,r;
vinfo.xoffset = lenth; // (计算屏幕图像在屏幕中间一块区域显示)Where we are going to put the pixel (x坐标偏移量:111) 要分清一块屏有宽和高,宽即用x坐标表示,高用y表示,和直角坐标系一样
vinfo.yoffset = height; // (y坐标偏移量:70) 即该区域的左上角的像素点坐标为(x,y)=(110,70),右下角的坐标为(x,y)= (110+420,70+340)
b = 0; // 即blue : 0000 0010
g = 0; // A little green 即green: 0000 0100
r = 255; // A lot of red 即red : 0000 0100
// Figure out where in memory to put the pixel
for ( y = 0; y < 16; y++ ) // 行扫描
for ( x = 0; x < 1; x++ ) { // 列扫描
for(z=0;z<8;z++) {
if(c[y][x]&(0x80>>z)) {
location = (x*8+z+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + // 定位到具体哪一行的第几个像素
(y+vinfo.yoffset) * finfo.line_length; //定位到哪一行(即该行的第一个像素的地址) 这两句即是实现求某一个像素的地址的功能
if ( vinfo.bits_per_pixel == 32 ) { //
*(fbp + location) = b; // Some blue
*(fbp + location + 1) = g; // A little green
*(fbp + location + 2) = r; // A lot of red
*(fbp + location + 3) = 0; // No transparency
} else { //16bpp: r:g:b=5:6:5 //assume 16bpp
unsigned short int t = r<<11 | g << 5 | b;
*((unsigned short int*)(fbp + location)) = t;
}
}
}
}
} int Show_title_in_LCD(char title[],int length,int height)//显示字符函数 { int fbfd = 0,i=0; char c; struct fb_cmap cmapinfo; long int screensize = 0; //定义a-z,_, char zimu[27][16][1]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x0C,0x34,0x44,0x4C,0x36,0x00,0x00, 0x00,0x00,0x00,0x00,0xC0,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x64,0x58,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x40,0x40,0x40,0x22,0x1C,0x00,0x00, 0x00,0x00,0x00,0x00,0x06,0x02,0x02,0x3E,0x42,0x42,0x42,0x42,0x46,0x3B,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x42,0x3C,0x00,0x00, 0x00,0x00,0x00,0x00,0x0C,0x12,0x10,0x7C,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x44,0x44,0x38,0x40,0x3C,0x42,0x42,0x3C, 0x00,0x00,0x00,0x00,0xC0,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00, 0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00, 0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x1C,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x78, 0x00,0x00,0x00,0x00,0xC0,0x40,0x40,0x4E,0x48,0x50,0x70,0x48,0x44,0xEE,0x00,0x00, 0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x49,0x49,0x49,0x49,0x49,0xED,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0x64,0x42,0x42,0x42,0x64,0x58,0x40,0xE0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1A,0x26,0x42,0x42,0x42,0x26,0x1A,0x02,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0x32,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x40,0x3C,0x02,0x42,0x7C,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x10,0x10,0x12,0x0C,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0x42,0x42,0x42,0x42,0x46,0x3B,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDB,0x89,0x4A,0x5A,0x54,0x24,0x24,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x24,0x18,0x18,0x18,0x24,0x6E,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x18,0x18,0x10,0x10,0x60, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x44,0x08,0x10,0x10,0x22,0x7E,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}; // Open the file for reading and writing fbfd = open(“/dev/fb0”, O_RDWR); // 打开Frame Buffer设备 if (fbfd < 0) { printf(“Error: cannot open framebuffer device.%x\n”,fbfd); exit(1); }
printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { // 获取设备固有信息
printf("Error reading fixed information.\n");
exit(2);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { // 获取设备可变信息
printf("Error reading variable information.\n");
exit(3);
}
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
// Map the device to memory 通过mmap系统调用将framebuffer内存映射到用户空间,并返回映射后的起始地址
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
fbfd, 0);
if ((int)fbp == -1) {
printf("Error: failed to map framebuffer device to memory.\n");
exit(4);
}
printf("The framebuffer device was mapped to memory successfully.\n");
memset(fbp,0,screensize);//clear screen
// int temp_l=length,temp_h=height; for(i=0;(c=title[i])!=’\0’;i++) { if(c==’ ‘) temp_l+=8; else if(c==’/’) { temp_h+=16; temp_l=length; } else if(c==’_’) { wirte_single(temp_l,temp_h,zimu[26]); temp_l+=8; } else { wirte_single(temp_l,temp_h,zimu[c-‘a’]); temp_l+=8; } } munmap(fbp, screensize); close(fbfd); return 0; }
2 娱乐助手系统的测试 测试任何产品都有两种方法:如果已经知道了产品应该具有的功能,可以通过测试来检验是否每个功能都能正常使用;如果知道产品内部工作过程,可以通过测试来检验产品内部动作是否按照规格说明书的规定正常进行。前一个方法称为黑盒测试,又称为功能性测试,后一个方法称为白盒测试[12]。 本章节对已经实现的娱乐助手系统进行测试,主要采用功能性测试方法进行测试。用户对娱乐助手的请求有多种可能性,所以我们选取以下测试用例来对系统进行测试。 (1) 选取测试条件为用户选择猜数字游戏,LED能够按照随机出的数字显示,并且程序可以按照规则对按键所按下的数字进行大小正确的判断,猜数进行10次后程序自动返回功能选择界面。 (2) 选取测试条件为用户选择MP3播放,在实验箱耳机插口插上耳机后,能够听到程序内置的歌曲,按Ctrl+C可以退出播放。 (3) 选取测试条件为用户选择蜂鸣器歌曲,选择后蜂鸣器可以响起内置的旋律和节奏,按Ctrl+C可以退出播放。 (4) 选取测试条件为用户选择键盘弹钢琴,选择后按下1-7号键蜂鸣器可以发出不同频率的声音,按下“*”可以退出弹奏。