用ARM实现音乐电子相册
(前段时间在做嵌入式的课程设计,特将学习心得整理如下)
一、开发工具及环境介绍
1、ARM处理器
ARM处理器是一个32位元精简指令集(RISC)处理器架构,其广泛地使用在许多嵌入式系统设计。
ARM处理器特点:
- 体积小、低功耗、低成本、高性能;
- 支持Thumb(16位)/ARM(32位)双指令集,能很好的兼容8位/16位器件;
- 大量使用寄存器,指令执行速度更快;
- 大多数数据操作都在寄存器中完成;
- 寻址方式灵活简单,执行效率高;
- 指令长度固定。
2、交叉编译环境
2.1、交叉编译
交叉编译(cross-compilation)是指在某个主机平台上(比如PC上)用交叉编译器编译出可在其他平台上(比如ARM上)运行的代码的过程。嵌入式软件开发需要交叉开发环境,这是其开发的一显著特点,交叉编译器只是交叉开发环境的一部分,我们说的交叉开发环境是指编译、链接和调试嵌入式应用软件的环境,它与运行嵌入式应用软件的环境有所不同,常采用宿主机----目标机模式。
2.2、关于交叉工具链:
它是交叉编译环境所需工具的集合体,是所需软件(binuntials、gcc与glibc等)的安装载体,主要包括:交叉编译器(arm-linux-gcc)、交叉汇编器(arm-linux-as)、交叉链接器(arm-linux-ld)、各种操作所依赖的库及用于处理可执行程序和库的一些基本工具(如arm-linux-strip)。
2.3硬件开发环境
开发环境:显卡:Intel(R) 82865G Graphics Controller(必须支持svga)
屏幕分辨率:1024*768像素。
颜色质量:最高(32位)。
DPI设置:正常尺寸(96 DPI)。
显卡模式:1024*768,真彩色(32位),85赫兹。
嵌入式,32位处理器,256m内存,320*240的屏幕分辨率。
二、设计流程
2.1、电子相册图片设置
将找到的图片用photoshop将图像大小设置为240*320,并保存为bmp格式。
(1) BMP图片显示
Bmp图片就是通常所说的位图,,是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。
(2) BMP图片的显示方法
bmp图片的显示方法主要有三种:
- 使用内存调用方法显示bmp图片。我们通常所说的屏幕就是屏显,在将bmp调色板区写入计算机调色板和已经读取bmp文件图像存储区到内存的基础上,再从内存将数据读取给显存只需要进行一个内存复制操作就可以了。
- 直接从文件读取到屏幕显示bmp文件。这种方法将通过显存显示bmp文件所需要的内存空间、读取数据到申请的空间、显示等多步任务简化成一步。事实上也就是将读取文件数据到申请内存变到显示内存。
- 采用绘点的方法将图片的像素按照图片文件的排列顺序逐个在屏幕上画出来。
2.2、音乐文件的转换
可用格式工厂对音乐文件格式进行转换,转换为wav格式。
2.3、音乐电子相册制作
(1)将文件放入电脑D盘的 share-ubuntu 文件夹中:
(2)打开虚拟机,从虚拟机下的share文件夹中将图片复制到 Student 文件夹下:
(3)进入Student文件夹,可以看到刚刚放入Student中的图片和音乐:
虚拟机:
开发板:
(4)对应用程序E_Album.c的编译、加载:
在虚拟机上交叉编译:
arm-linux-gcc -o E_Album E_Album.c //交叉编译应用程序
在开发板上执行应用程序:
./E_Album //在开发板侧执行程序
2.4、效果如图(10张图片进行循环切换,并带背景音乐):
三、示例代码
1、图片驱动程序LCD_img.c
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <string.h> #define DEVICE_NAME "/dev/fb0" #define XSIZE 240 #define YSIZE 320 #define PI 3.1415926 unsigned short *fb_mem_kernel; //16bit static void PutPixel(unsigned int x,unsigned int y,unsigned short rgb565); unsigned int size = XSIZE*YSIZE*2; int main(int argc, char *argv[]) { int fp, i, j; char Red32,Green32,Blue32,Red565,Green565,Blue565; unsigned short RGB565; FILE *img_fp; fp = open("/dev/fb0", O_RDWR); //用open打开设备文件 fb_mem_kernel = mmap(0,size,PROT_READ | PROT_WRITE, MAP_SHARED,fp,0); memset(fb_mem_kernel,0x00,size); img_fp = fopen(argv[1], "r"); //用fopen打开普通文件 fseek(img_fp, 0x36L, SEEK_SET); for(j=YSIZE;j>0;j--){ //rgb888 to rgb565 for(i=0;i<XSIZE;i++){ fread(&Blue32,sizeof(char),1,img_fp); fread(&Green32,sizeof(char),1,img_fp); fread(&Red32,sizeof(char),1,img_fp); Red565 = Red32 >> 3; // 5-bit red Green565 = Green32 >> 3; // 6-bit green Blue565 = Blue32 >> 3; // 5-bit blue RGB565 = (Red565<<(11))|(Green565<<5)|Blue565; PutPixel(i,j,RGB565) ; } } fclose(img_fp); close(fp); return 0; } static void PutPixel(unsigned int x,unsigned int y,unsigned short rgb565) { if ((x <= XSIZE) && (y <= YSIZE)){ *(fb_mem_kernel+(y-1)*XSIZE+(x-1))=rgb565; } }
2、音乐驱动程序Audio_player.c
#include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <linux/soundcard.h> //下面的三个参数是跟具体文件相关的,文件什么样,就设置成什么样 #define SAMPLE_RATE 22050 //采样率:22050(22 56 00 00) #define BIT_SIZE 16 //量化位数 #define CHANNELS 2 //通道数:1表示单声道,2为立体声 int main(int argc, char *argv[]) { FILE *wav_fd; int fd, *buf; int wav_length, arg, status; unsigned char *wav_buf; if(argc<2){ //如果argc的值是1,说明程序名后面没有命令行参数 printf("Usage:%s xxx.wav !\n",argv[0]); //argv[0]的值是启动该程序的程序名 exit(1); } wav_fd = fopen(argv[1], "r"); if (wav_fd == NULL) { printf("Open wav_file %s error !\n",argv[1]); exit(1); } printf("Test iis+UDA1341 OSS interface to play %s file.\n",argv[1]); fseek(wav_fd, 0x28L, SEEK_SET); //文件大小 buf = (int*) malloc(sizeof(int)); fread(buf,sizeof(int),1,wav_fd); wav_length = *buf; free(buf); printf("wav_file length is: %xH.\n",wav_length); printf("Play......\n"); fd = open("/dev/dsp", O_WRONLY); //arm中一般不可使用O_RDWR if (fd < 0) { printf("Open of /dev/dsp failed"); exit(1); } arg = CHANNELS; //设置通道数 status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg); if (status == -1) perror("SOUND_PCM_WRITE_CHANNELS ioctl failed."); arg = BIT_SIZE; //设置量化位数 status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg); if (status == -1) perror("SOUND_PCM_WRITE_BITS ioctl failed."); arg = SAMPLE_RATE; //设置采样率 status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg); if (status == -1) perror("SOUND_PCM_WRIT_RATE ioctl failed."); //从wav文件中读wav_length大小的内容,然后写入/dev/dsp中 fseek(wav_fd, 0x2cL, SEEK_SET); wav_buf =(unsigned char*) malloc(wav_length); fread(wav_buf, wav_length, 1, wav_fd); //读文件数据 write(fd, wav_buf, wav_length); free(wav_buf); fclose(wav_fd); close(fd); return 0; }
3、电子相册的驱动程序E_Album.c
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> static void sig_usr(int signo); static void sig_alarm(int signo); int i=1; pid_t child_pid; int main() { pid_t pid; if (signal(SIGALRM, sig_alarm) < 0) perror("signal SIGALRM error:"); if (signal(SIGUSR2, sig_usr) < 0) perror("signal SIGUSR2 error:"); pid=fork(); if ( pid == 0 ){ /* 子进程 */ printf("child_pid= %d\n",getpid()); for(;;){ system("./Audio_player RedStream.wav"); pause(); } exit(0); } else{ /* 父进程 */ child_pid=pid; for(;;){ alarm(3); pause(); } } return 0; } static void sig_usr(int signo){ int ret; printf("SIGUSR2 comming..... \n"); if((ret=kill(child_pid,SIGCONT))<0) perror("kill error:");} static void sig_alarm(int signo) { char *str0,*str1,Display_img[50]; str0 ="./LCD_img b_fly"; str1 =".bmp"; sprintf(Display_img, "%s%d%s", str0, i, str1); printf("Display_img= %s\n",Display_img); i++; kill(child_pid,SIGUSR2); //向子进程发信号 system(Display_img); if(i>10){ kill(child_pid,SIGINT); //结束子进程 kill(getpid(),SIGINT); //结束父进程 } }
四、总结
此次课程设计使我了解了如何在Linux和开发板上进行应用程序的交叉编译,对硬件的操作和对软件的使用也有所掌握。
(注:对LCD_img.c程序进行适当修改,可以改变照片的切入切出形式)
![](http://files.cnblogs.com/files/OctoptusLian/zhifubao.bmp)
您的资助是我最大的动力!
金额随意,欢迎来赏!
![](http://files.cnblogs.com/files/OctoptusLian/weixin.bmp)
本博客的所有打赏均将用于博主女朋友的化妆品购买以及养肥计划O(∩_∩)O。我是【~不会飞的章鱼~】!