二、 课程设计教学目的:
1、了解并掌握系统电路的一般设计方法,具备初步的独立设计能力;
2、掌握Unix/Linux系统原理;
3、提高综合运用所学的理论知识独立分析和解决问题的能力;
4、进一步掌握ARM技术的开发流程。
三、设计要求
1、首先在PC机上实现mp3播放器的基本功能,包括播放一首或者几首mp3格式的歌曲,并实现快退、快进功能。
2、在ARM开发板上调试并实现上述功能,完成课程设计。
四、基本原理:
1、嵌入式系统基本介绍:
随着近20年来微电子技术、计算机技术和移动通信技术的迅速发展以及网络技术的广泛应用,实际情况已经产生了根本性的变化。例如在70年代末定义的微型计算机演变出来的个人计算机PC其处理速度已远远超过了当年对大、中、小型计算机的定义。随着计算机技术对其它行业的广泛渗透和与其它行业应用技术的相互结合,以应用为中心的分类方法变得似乎更加切合实际发展;按计算机的嵌入式应用和非嵌入式应用将其分为通用计算机和嵌入式计算机。而通用计算机具有一般计算机的基本标准形态,通过装配不同的应用软件,以基本雷同的面目出现并应用在社会的各个方面,其典型产品为PC;而非通用计算机的计算机-嵌入式计算机,则是非通用计算机形态的计算机应用,它是以作为嵌入式系统的核心部件的形式隐藏在各种装置、设备、产品和系统中。因此嵌入式计算机是计算机技术发展中的一种计算机存在的形式,是从计算机技术的发展中分离出来的。
2、linux操作系统简介:
Linux是一种*和开放源码的类Unix操作系统。目前存在着许多不同的Linux,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,从手机、平板电脑、路由器和视频游戏控制台,到台式计算机、大型机和超级计算机。Linux是一个领先的操作系统,世界上运算最快的10台超级计算机运行的都是Linux操作系统。严格来讲,Linux这个词本身只表示Linux内核,但实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU 工程各种工具和数据库的操作系统。
3、mp3音频格式:
MP3是MPEG-1 Audio Layer 3的简称,是当今比较流行的一种数字音频编码和有损压缩格式。MP3技术的应该可以用来大幅度的降低音频文件存储所需要的空间。它丢掉脉冲编码调制(PCM)音频数据中对人类听觉不重要得数据,从而达到了较高的压缩比(高达12:1-10:1)。简单地说,MP3在编码时先对音频文件进行频谱分析,然后用过滤器滤掉噪音电平,接着通过量化的方式将剩下的每一位打散排列,最后形成有较高压缩比的MP3文件,并使压缩后的文件在回放时也能够达到比较接近原音源的效果。
五、方案选择:
1、嵌入式系统开发方式的选择:
如今,嵌入式系统的开发有两种模式,其一是基于ARM芯片的,类似于单片机开发的一种
模式,即直接在硬件上进行编程,这显然是不合理的,这样难以有效的开发出能够处理复杂问题的嵌入式应用系统。其二就是基于嵌入式操作系统的开发模式。在嵌入式系统的开发过程中,一般采取交叉平台的开发方法。即在通用PC上编程,然后通过交叉编译和链接,将源程序编成能够在目标平台上运行的二进制代码格式映像。最后将映像下裁到目标平台上的特定位置,由目标板上启动代码(Bootloader)执行这段二行制代码,从而运行起嵌入式系统。而当今嵌入式的开发几乎都采用第二种开发模式。
因此,我们的课程设计自然是采用第二种开发模式。
2、开发流程的确定:
我们完全按照企业中嵌入式的开发流程,首先在pc机上构建linux操作系统开发环境。其次在开发板上构建linux编译、执行环境。然后再pc机上写程序,并进行交叉编译,在pc机上执行程序。最后把程序下载到开发板,完成整个设计。整个开发流程图如下:
六、pc机上构建linux操作系统开发平台
1、安装linux虚拟机Oracle VM VirtualBox:
本次课程设计用的是linuxdebian版本,2.6.26-2-686的内核。首先运行虚拟机安装程序,安装完成后,新建一个linux操作系统,输入用户名和密码进入操作系统就可以进行程序的编写了,至此第一步就完成了。
2、熟悉linux命令行操作及常用命令:
⑴与文件相关命令:
pwd:查看当前目录
ls :查看当前目录下包含的子目录
ls –l 文件名:查看指定文件的详细信息
ls –a:查看包括隐藏文件在内的所有文件的信息
cd:切换目录
cd /:切换到根目录
cd …:切换到上一级目录
mkdir 文件名:新建文件夹
rm 文件名:删除文件
rm –r 文件名:删除文件(无法恢复)
touch 文件名:新建文件
cat 文件名:查看文件内容
echo “内容”>> 文件名:把内容写到文件的末尾,不覆盖原来的内容
cat 文件1 >> 文件2:把文件1的内容复制到文件2
⑵程序编写过程中常用命令:
vim “文件名”:打开类似于windows记事本的编辑器,并命名为“文件名”,打开编译器后,默认为命令模式,不能进行输入。按“i”键,进入输入模式,此时可以进行代码编辑。按“Esc”键,回到命令模式。按“:”键进入末行模式。
w 文件名:在vim的末行模式下,保存文件为指定文件名。
q :在vim 的末行模式下退出vim
wq:在vim的末行模式下保存并退出文件
dd:删除整行
ndd :删除n行
dw :删除单词
ndw :删除n个单词
d$:删除从光标处到结尾的内容
y:复制
nyy:复制n行
p:粘贴
?或/ 要查找的内容:查找指定内容
%s/ / /g:进入末行模式后全部替换查找到的内容
u:撤销此次动作
ctrl+r:恢复到上一个状态
set nu:在末行模式下打开行号
set nonu:在末行模式下撤销行号
gcc 文件名:编译指定文件,输出可执行文件a.out
gcc 文件名1 –o文件名2:编译指定文件,输出可执行文件“文件名2”
./文件名:执行指定文件
vim makefile:编写makefile,集体编译文件
写法:输出可执行文件1:源文件1
gcc源文件1 –o 可执行文件1
输出可执行文件2:源文件2
gcc源文件2 –o 可执行文件2
……
make:执行makefile
man 2 函数名:查看函数使用手册
⑶安装声卡驱动
第一步:cd/lib/modules/2.6.26-2-686/kernel/sound/core/oss/
第二步:sudomodprobe snd-pcm-oss
到此,声卡驱动安装完成
七、编写源程序
1、首先实现播放wav格式音频文件,程序流程图如下:
源程序如下:
#include<stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include<stdlib.h> #include <sys/ioctl.h> #include <sys/soundcard.h> #include <termios.h> #include <unistd.h> int kbhit(void) { struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW,&newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf |O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW,&oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch, stdin); return 1; } return 0; } int main(int argc,char **argv) { char *buf=malloc(1024); int fd=open(argv[1],O_RDONLY|O_CREAT|O_APPEND,0666); int fd1=open(argv[2],O_WRONLY|O_CREAT|O_APPEND,0666); printf("%d,%d\n",fd,fd1); int du=1; while(du>0) { while(kbhit()) { switch(getchar()) { case '1':lseek(fd,1000000,SEEK_CUR);break; case '2':lseek(fd,-1000000,SEEK_CUR);break; default:break; } break; } du=read(fd,buf,50); int fmt=AFMT_S16_LE,channels=2,speed=44100; ioctl(fd1,SNDCTL_DSP_SETFMT,&fmt); ioctl(fd1,SNDCTL_DSP_CHANNELS,&channels); ioctl(fd1,SNDCTL_DSP_SPEED,&speed); int xie=write(fd1,buf,du); printf("%d %d ",du,xie); } close(fd); close(fd1); return 0; }
到此,实现了播放wav格式的音频文件。
2、实现播放mp3格式的音频文件,在上面的基础上加入mp3解码程序,并加以改进:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <sys/soundcard.h> #include <termios.h> #include <mad.h> struct mad_stream decode_stream; struct mad_frame decode_frame; struct mad_synth decode_synth; static inline signed int scale(mad_fixed_tsample) { sample+= (1L << (MAD_F_FRACBITS - 16)); if(sample >= MAD_F_ONE) sample = MAD_F_ONE - 1; else if(sample < -MAD_F_ONE) sample = -MAD_F_ONE; return sample >> (MAD_F_FRACBITS + 1 - 16); } int mad_init(void) { mad_stream_init(&decode_stream); mad_synth_init(&decode_synth); mad_frame_init(&decode_frame); return0;} int change_input_mode (void) { intret; structtermios new_opts; if(tcgetattr(0, &new_opts)<0){ printf ("error: tcgetattr()"); return 1;} new_opts.c_lflag&= ~(ICANON); new_opts.c_cc[VMIN]=0; new_opts.c_cc[VTIME]=0; if(tcsetattr(0,TCSANOW, &new_opts)<0){ printf ("error: tcsetattr()"); return 1; } return0; } int main(int argc,char **argv){ intfd,snd; charsnddata[32768]; charinput_buf[5*1024*1024]={0}; structstat st; inttotal=0; intret; intsize=4*1024*1024; intret_val; mad_init(); change_input_mode(); fd=open("../nuannuan.mp3",O_RDONLY); if(fd==-1){ printf("open audio fileerror\n"); return -1;} snd=open("/dev/dsp",O_WRONLY); if(snd==-1){ printf("open dsp error\n"); return -1;} read(fd,input_buf,size); mad_stream_buffer(&decode_stream,input_buf, size); while(1){ ret_val =mad_frame_decode(&decode_frame, &decode_stream); printf("%d\n",ret_val); if (ret_val == 0) { mad_synth_frame(&decode_synth,&decode_frame); intfmt=AFMT_S16_LE; ret=ioctl(snd,SNDCTL_DSP_SETFMT,&fmt); intchannel=decode_synth.pcm.channels; ret=ioctl(snd,SNDCTL_DSP_CHANNELS,&channel); intsamplerate=decode_synth.pcm.samplerate; ret=ioctl(snd,SNDCTL_DSP_SPEED,&samplerate); unsignedchar *tmp=snddata; unsignedint size=decode_synth.pcm.length; inti=0; while(i<size){ unsigned int sample; sample=scale(decode_synth.pcm.samples[0][i]); *tmp++=sample>>0; *tmp++=sample>>8; if(decode_synth.pcm.channels==2){ sample=scale(decode_synth.pcm.samples[1][i]); *tmp++=sample>>0; *tmp++=sample>>8; } i++; } if(decode_synth.pcm.channels==2) size=size*4; else size=size*2; write(snd,snddata,size); } } close(fd); close(snd); return0; }
到这里,播放mp3的软件就设计完成了。
八、把源程序编译、链接后的可执行文件烧写到ARM开发板。
九、结束语
其次,这次课程设计,也增加了我分析问题,解决问题的能力。例如,如何通过查找资料去学习新的东西,然后解决从来没有遇到过的问题。在这次课程设计过程中,老师只是布置了当天的任务,和讲解用到的新知识,然后由我们自己去完成任务,编写程序。这个过程培养了我独立思考问题的能力,为我将来从事这方面的工作打下了一定的基础。
在整个课程设计过程中,我也遇到了很多问题。例如,在编写程序实现把一个文件中的内容写入到另一个文件中时,总发现读入的内容是错误的,最后经过认真检查和调试,才发现是因为缓存变量没有赋初值。在如何实现快进、快退功能时,发现无法解决播放音乐的同时检测外部按键,经过上网查找资料,终于找到一个方法,就是kbhit()函数的应用。还有其它问题,最终,经过自己的思考或者请叫老师,都得到了解决。
最后,很高兴完成了我的课程设计,为我在这次课程设计中学到很多东西而感到充实。总的来说,这次课程设计让我学到了很多,收获很大。首先通过这次课程设计,我真正地了解到了嵌入式这门超前沿的学科,对嵌入式的一个典型应用——mp3透彻的了解。在课程设计过程中,亲身体验了嵌入式系统的开发流程,也充分体会到了嵌入式系统是如何实现如此复杂的功能的。这对自己将来所从事的工作有了全新的展望,也是对自己极大的激励