用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程序進行適當修改,可以改變照片的切入切出形式)
用ARM實現音樂電子相冊