分四部分:按键驱动,声卡驱动,Madplay播放器移植,MP3主播放器处理
按键1:播放,按键2:停止,按键3:上一曲,按键4:下一曲
UA1341内核自带声卡驱动

.解压内核: tar zxvf linux..清理中间件,配置文件:cd linux-linux2.6.29;make clean
.选择参考配置文件:cp config-mp3.config

.配置内核:
make menuconfig ARCH=arm
CROSS_COMPILE=arm-linux-
选择声卡驱动:device drivers-->sound card support-->advanced linux sound architecture-->alsa for soc audio support-->UA134x

.编译内核:
make uImage ARCH=arm
CROSS_COMPILE=arm-linux-
内核映像uImage位于arch/arm/boot
将其拷贝到tftpboot目录

.解压rootfs.tar.gz并拷贝到nfsroot

.按键驱动移植:
cd SDK-MP3/driver
make clean;make
cp mini2440_buttons.ko /nfroot/rootfs/mp3

.madplay移植见最后

9.播放处理:cd SDK-MP3/app;make clean;makecp app-mp3 /nfsroot/rootfs/mp3

10.测试采用NFS方式起文件系统,加载按键驱动,运行mp3程序:insmod mini2440_buttons.ko./app-mp3会显示播放列表,播放option,1,2,3,4按键控制播放。
主要程序为mp3播放控制程序:

/*
 *     mp3播放器控制程序
 *       功能:
              k1:播放、暂停
              k2:停止播放
              k3:上一首
              k4:下一首
 *     附加:歌曲自动循环播放
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

/*共享内存申请标记*/
#define PERM S_IRUSR|S_IWUSR                                                    

/*双向循环列表:存放歌曲名*/
struct song
{
    ];
    struct song *prev;
    struct song *next;
};

/*孙子进程id号*/
pid_t gradchild;

/*子进程id号*/
pid_t pid;

/*共享内存描述标记*/
int shmid;

char *p_addr;

/*播放标记*/
;
;

/*************************************************
Function name: play
Parameter    : struct song *
Description     : 播放函数
Return         : void
Argument     : void
Autor & date : ada 09,12,07
**************************************************/
void play(struct song *currentsong)
{
    pid_t fd;
    char *c_addr;
    char *p;
    int len;
    ]="/mp3/song/";
    while(currentsong)
    {
        /*创建子进程,即孙子进程*/
        fd = fork();
        )
        {
            perror("fork");
            exit();
        }
        )
        {
            /*把歌曲名加上根路径*/
            strcat(my_song,currentsong->songname);
            p = my_song;
            len = strlen(p);

            /*去掉文件名最后的'\n'*/
            my_song[len-]='\0';

            printf("THIS SONG IS %s\n",my_song);
            execl("/mp3/madplay","madplay",my_song,NULL);
            printf("\n\n\n");
        }
        else
        {
            /*内存映射*/
            c_addr = shmat(shmid,,);

            /*把孙子进程的id和当前播放歌曲的节点指针传入共享内存*/
            memcpy(c_addr,&fd,sizeof(pid_t));
            memcpy(c_addr + ,&currentsong,);
            /*使用wait阻塞孙子进程,直到孙子进程播放完才能被唤醒;
              当被唤醒时,表示播放MP3期间没有按键按下,则继续顺序播放下一首MP3*/
            if(fd == wait(NULL))
            {
                currentsong = currentsong->next;
                printf("THE NEXT SONG IS %s\n",currentsong->songname);
            }
        }
    }
}

/*************************************************
Function name: creat_song_list
Parameter    : void
Description     : 创建歌曲名的双向循环链表
Return         : struct song *
Argument     : void
Autor & date : ada 09.12.07
**************************************************/
struct song *creat_song_list(void)
{
    FILE *fd;
    size_t size;
    size_t len;
    char *line = NULL;
    struct song *head;
    struct song *p1;
    struct song *p2;
    system("ls /mp3/song >song_list");
    fd = fopen("song_list","r");

    p1 = (struct song *)malloc(sizeof(struct song));

    printf("==================================song list=====================================\n");
    system("ls /mp3/song");
    printf("\n");
    printf("================================================================================\n");
    size = getline(&line,&len,fd);

    strncpy(p1->songname,line,strlen(line));
    head = p1;
    )
    {
        p2 = p1;
        p1 = (struct song *)malloc(sizeof(struct song));
        strncpy(p1->songname,line,strlen(line));
        p2->next = p1;
        p1->prev = p2;
    }
    p1->next = head;
    head->prev = p1;
    p1 = NULL;
    p2 = NULL;
    system("rm -rf song_list");
    return head;
}
/*************************************************
Function name: startplay
Parameter    : pid_t *,struct song *
Description     : 开始播放函数
Return         : void
Argument     : void
Autor & date : ada 09.12.07
**************************************************/
void startplay(pid_t *childpid,struct song *my_song)
{
    pid_t pid;
    int ret;
    /*创建子进程*/
    pid = fork();

    )
    {
        *childpid = pid;
        play_flag = ;
        sleep();
        /*把孙子进程的pid传给父进程*/
        memcpy(&gradchild,p_addr,sizeof(pid_t));
    }
     == pid)
    {
        /*子进程播放MP3函数*/
        play(my_song);
    }
}
/*************************************************
Function name: my_pause
Parameter    : pid_t
Description     : 暂停函数
Return         : void
Argument     : void
Autor & date : ada 09,12,07
**************************************************/
void my_pause(pid_t pid)
{
    printf("=======================PAUSE!PRESS K1 TO CONTINUE===================\n");
    kill(pid,SIGSTOP); //对孙子进程发送SKGSTOP信号
    play_flag = ;
}

/*************************************************
Function name: my_pause
Parameter    : pid_t
Description     : 停止播放函数
Return         : void
Argument     : void
Autor & date : ada 09,12,07
**************************************************/
void my_stop(pid_t g_pid)
{

    printf("=======================STOP!PRESS K1 TO START PLAY===================\n");
    kill(g_pid,SIGKILL); //对孙子进程发送SKGKILL信号
    kill(pid,SIGKILL);   //对子进程发送SKGKILL信号
    first_key=;

}

/*************************************************
Function name: conti_play
Parameter    : pid_t
Description     : 继续函数
Return         : void
Argument     : void
Autor & date : ada 09,12,07
**************************************************/
void conti_play(pid_t pid)
{
    printf("===============================CONTINUE=============================\n");
    kill(pid,SIGCONT); //对孙子进程发送SIGCONT信号
    play_flag=;
}

/*************************************************
Function name: next
Parameter    : pid_t
Description     : 下一首函数
Return         : void
Argument     : void
Autor & date : ada 09.12.07
**************************************************/
void next(pid_t next_pid)
{
    struct song *nextsong;

    printf("===============================NEXT MP3=============================\n");
    /*从共享内存获得孙子进程播放歌曲的节点指针*/
    memcpy(&nextsong,p_addr + ,);
    /*指向下首歌曲的节点*/
    nextsong = nextsong->next;
    /*杀死当前歌曲播放的子进程,孙子进程*/
    kill(pid,SIGKILL);
    kill(next_pid,SIGKILL);
    wait(NULL);
    startplay(&pid,nextsong);
}

/*************************************************
Function name: prev
Parameter    : pid_t
Description     : 上一首函数
Return         : void
Argument     : void
Autor & date : yuanhui 09.12.08
**************************************************/
void prev(pid_t prev_pid)
{
    struct song *prevsong;
    /*从共享内存获得孙子进程播放歌曲的节点指针*/
    printf("===============================PRIOR MP3=============================\n");
    memcpy(&prevsong,p_addr + ,);
    /*指向上首歌曲的节点*/
    prevsong = prevsong->prev;
    /*杀死当前歌曲播放的子进程,孙子进程*/
    kill(pid,SIGKILL);
    kill(prev_pid,SIGKILL);
    wait(NULL);
    startplay(&pid,prevsong);
}

/*************************************************
Function name: main
Parameter    : void
Description     : 主函数
Return         : int
Argument     : void
Autor & date : ada 09.12.07
**************************************************/
int main(void)
{
    int buttons_fd;
    int key_value;
    struct song *head;
    /*打开设备文件*/
    buttons_fd = open();
    ) {
        perror("open device buttons");
        exit();
    }

  /*创建播放列表*/
    head = creat_song_list();
    printf("===================================OPTION=======================================\n\n\n\n");
    printf("        K1:START/PAUSE     K2:STOP   K3:NEXT      K4:PRIOR\n\n\n\n");
    printf("================================================================================\n");

  /*共享内存:用于存放子进程ID,播放列表位置*/
    ,PERM))== -)
        exit();
    p_addr = shmat(shmid,,);
    memset(p_addr,);

    )
    {
        fd_set rds;
        int ret;

        FD_ZERO(&rds);
        FD_SET(buttons_fd, &rds);

        /*监听获取键值*/
        ret = , &rds, NULL, NULL, NULL);
        )
        {
            perror("select");
            exit();
        }
        )
            printf("Timeout.\n");
        else if (FD_ISSET(buttons_fd, &rds))
        {
            int ret = read(buttons_fd, &key_value, sizeof key_value);
            if (ret != sizeof key_value)
            {
                if (errno != EAGAIN)
                    perror("read buttons\n");
                continue;
            }
            else
            {
                //printf("buttons_value: %d\n", key_value+1);

                /*首次播放,必须是按键1*/
                if(first_key){
                    switch(key_value)
                    {
                    :
                        startplay(&pid,head);
                        first_key=;
                        break;
                    :
                    :
                    :
                        printf("=======================PRESS K1 TO START PLAY===================\n");
                        break;
                    default:
                        printf("=======================PRESS K1 TO START PLAY===================\n");
                        break;
                    } //end switch
                }//end if(first_key)
                /*若不是首次播放,则根据不同键值处理*/
                else if(!first_key){
                    switch(key_value)
                    {
                    :
                        //printf("play_flag:%d\n",play_flag);
                        if(play_flag)
                            my_pause(gradchild);
                        else
                            conti_play(gradchild);
                        break;
                    :
                        my_stop(gradchild);
                        break;
                    :
                        next(gradchild);
                        break;
                    :
                        prev(gradchild);
                        break;
                    } //end switch
             }//end if(!first_key)

            }

        }
    }

    close(buttons_fd);
    ;
}

all:
arm-linux-gcc -static app.c -o app-mp3

clean:
rm -rf app-mp3

 
mini2440_buttons.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#define DEVICE_NAME     "buttons"

//#define DEBUG
struct button_irq_desc {
    int irq;
    int pin;
    int pin_setting;
    int number;
    char *name;
};

#if !defined (CONFIG_QQ2440_BUTTONS)
static struct button_irq_desc button_irqs [] = {
    {IRQ_EINT8 , S3C2410_GPG0 ,  S3C2410_GPG0_EINT8  , , "KEY0"},
    {IRQ_EINT11, S3C2410_GPG3 ,  S3C2410_GPG3_EINT11 , , "KEY1"},
    {IRQ_EINT13, S3C2410_GPG5 ,  S3C2410_GPG5_EINT13 , , "KEY2"},
    {IRQ_EINT14, S3C2410_GPG6 ,  S3C2410_GPG6_EINT14 , , "KEY3"},
    {IRQ_EINT15, S3C2410_GPG7 ,  S3C2410_GPG7_EINT15 , , "KEY4"},
    {IRQ_EINT19, S3C2410_GPG11,  S3C2410_GPG11_EINT19, , "KEY5"},
};
#else /* means QQ */
static struct button_irq_desc button_irqs [] = {
    {IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, , "KEY0"},
    {IRQ_EINT11, S3C2410_GPG3,  S3C2410_GPG3_EINT11,  , "KEY1"},
    {IRQ_EINT2,  S3C2410_GPF2,  S3C2410_GPF2_EINT2,   , "KEY2"},
    {IRQ_EINT0,  S3C2410_GPF0,  S3C2410_GPF0_EINT0,   , "KEY3"},
    {       -,            -,                 -,    , "KEY4"},
    {       -,            -,                 -,    , "KEY5"},
};
#endif
//static volatile char key_values [] = {'0', '0', '0', '0', '0', '0'};
;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

;

static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
    struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
    int down;
    // udelay(0);

    /*上升沿触发,GPIO DAT 应该为非0 的数*/
    down = !s3c2410_gpio_getpin(button_irqs->pin);
    if (!down) {
    //printk("rising\n");
    key_values = button_irqs->number;
        ev_press = ;
        wake_up_interruptible(&button_waitq);
    }
   else {
    //printk("falling\n");
    ev_press = ;
    ;
   }
    return IRQ_RETVAL(IRQ_HANDLED);
}

static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
{
    int i;
    ;

    ; i < ]); i++) {
    ) {
        continue;
    }

     /* 设置中断触发方式 IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH ;我们这里设置为上升沿触发*/
        //err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,
        //                  button_irqs[i].name, (void *)&button_irqs[i]);
        err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING,
                          button_irqs[i].name, (void *)&button_irqs[i]);
        if (err)
            break;
    }

    if (err) {
        i--;
        ; i--) {
        ) {
        continue;
        }
        disable_irq(button_irqs[i].irq);
            free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
        }
        return -EBUSY;
    }

    ev_press = ;

    ;
}

static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
{
    int i;

    ; i < ]); i++) {
    ) {
        continue;
    }
    free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
    }

    ;
}

static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
    unsigned long err;
    //int i=0;
    if (!ev_press) {
    if (filp->f_flags & O_NONBLOCK)
        return -EAGAIN;
    else
        wait_event_interruptible(button_waitq, ev_press);
    }
    if(count != sizeof key_values)
    return -EINVAL;
    ev_press = ;
    err = copy_to_user(buff, &key_values, sizeof(key_values));
    return sizeof(key_values);
}

static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
{
    unsigned ;
    poll_wait(file, &button_waitq, wait);
    if (ev_press)
        mask |= POLLIN | POLLRDNORM;
    return mask;
}

static struct file_operations dev_fops = {
    .owner   =   THIS_MODULE,
    .open    =   s3c24xx_buttons_open,
    .release =   s3c24xx_buttons_close,
    .read    =   s3c24xx_buttons_read,
    .poll    =   s3c24xx_buttons_poll,
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops,
};

static int __init dev_init(void)
{
    int ret;

    ret = misc_register(&misc);
#ifdef DEBUG
    printk("debug test\n");//ykz
#endif
    printk (DEVICE_NAME"\tinitialized\n");

    return ret;
}

static void __exit dev_exit(void)
{
    misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");

ifneq ($(KERNELRELEASE),)

obj-m := mini2440_buttons.o

else
KDIR := /home/project/mp3/SDK-MP3/kernel/linux-2.6.29
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers app-key

endif

Madplay移植说明

一.准备
移植Madplay所需四个软件包分别为libid3tag-0.15.1b.tar.gz,
libmad-.tar.gz,madplay-0.15.2b.tar.gz

二.解压
   .mkdir /mp3 建立MP3目录
         . tar -zxvf libid3tag-0.15.1b.tar.gz -C /mp3
         . tar -zxvf ibmad-0.15.1b.tar.gz -C /mp3
       . tar -zxvf zlib-.tar.gz -C /mp3
       . tar -zxvf madplay-0.15.2b.tar.gz -C /mp3

三.编译zlib
#cd /mp3/zlib-
#./configure --prefix=/usr/local/arm//arm-none-linux-gnueabi/libc/usr/lib
    修改Makefile
    AR=/usr/local/arm//bin/arm-linux-ar rcs
    CC=/usr/local/arm//bin/arm-linux-gcc
    RANLIB=/usr/local/arm//bin/arm-linux-ranlib

  执行  #make
          #make install

四.编译libid3tag
#cd /mp3/libid3tat-0.15.1d
#./configure --host=arm-linux CC=arm-linux-gcc --disable-debugging --disable-shared --prefix=/usr/local/arm//arm-none-linux-gnueabi/libc/usr/lib

    #make
    #make install

五.编译libmad
#cd /mp3/libmad-0.15.1b
#./configure --enable-fpm=arm --host=arm-linux --disable-shared --disable-debugging --prefix=/usr/local/arm//arm-none-linux-gnueabi/libc/usr/lib
修改 Makefile 129行 去掉 –fforce-mem

    #make
    #make install

六.编译madplay
#cd /mp3/madplay-0.15.2b
#./configure --host=arm-linux CC=arm-linux-gcc --disable-debugging --disable-shared
    #make
    但是,这样得到的是动态连接的。
    #rm madplay
    拷贝make的最后一个连接的命令,在最后加上-static 和 -lz,然后运行,得到静态连接的程序
        如

arm-linux-gcc -Wall -O2 -fomit-frame-pointer -o madplay madplay.o getopt.o getopt1.o version.o resample.o filter.o tag.o crc.o rgain.o player.o audio.o audio_aiff.o audio_cdda.o audio_hex.o audio_null.o audio_raw.o audio_snd.o audio_wave.o audio_oss.o  -lmad -lid3tag -lm -lz -static
最后把madplay下到板子就可以了.

嵌入式mp3播放器的更多相关文章

  1. 基于Stm32的MP3播放器设计与实现

    原创博文,转载请注明出处 这是我高级电子技术试验课做的作业,拿来共享一下.项目在安福莱例程基础之上进行的功能完善,里面的部分内容可参考安福莱mp3例程.当然用的板子也是安福莱的板子,因为算起来总共做了 ...

  2. C# wave mp3 播放器探寻

    C# wave mp3 播放器探寻   最近无聊,想听听歌曲.可怜新电脑上歌曲就两三首,要听其它的就得在旧电脑上播放.可是,那台古董但不失健壮的本本被老婆无情的霸占了.无奈. 思来想去,得,写个程序播 ...

  3. MP3播放器团队项目

    一.设计思路 程序要求能播放MP3文件,因此需调用库中的播放方法:右键工具箱选择项,添加com组件,选择window media player后工具箱就会多一个控件,然后拖到窗体中就OK了.另在窗体中 ...

  4. 你也可以用java的swing可以做出这么炫的mp3播放器_源码下载

    I had published the blog : 你用java的swing可以做出这么炫的mp3播放器吗? and to display some screenshots about this M ...

  5. 你用java的swing可以做出这么炫的mp3播放器吗?

    这个mp3播放器是基于java的swing编写的,我认为界面还是可以拿出来和大家看一看评一评. 先说说创作的初衷,由于前段时间工作不是很忙,与其闲着,还不如找一些东西来给自己捣腾捣腾,在 之前写的 j ...

  6. MP3播放器的实现

    今天,基本上实现了MP3播放器的基本功能,现在总结一下. 首先,下载服务器端的MP3列表,这里用到了下载技术和解析XML文件技术. 下载参考(http://blog.csdn.net/huim_lin ...

  7. 安卓MP3播放器开发实例(1)之音乐列表界面

    学习安卓开发有一年了,想想这一年的努力,确实也收获了不少.也找到了比較如意的工作. 今天准备分享一个以前在初学阶段练习的一个项目.通过这个项目我真正的找到了开发安卓软件的感觉,从此逐渐步入安卓开发的正 ...

  8. 开源mp3播放器--madplay 编译和移植 简记

    madplay是一款开源的mp3播放器. http://madplay.sourcearchive.com/ 下面简单记录一下madplay的编译与移植到ARM开发板上的过程 一.编译x86版本的ma ...

  9. x宝23大洋包邮的老式大朝华MP3播放器简单评测

    (纯兴趣测评,非广告) 最近逛X宝,看到了这个古董级MP3播放器居然还在售,于是脑抽+情怀泛滥买了一个. 然后呢,从遥远的深圳跨越好几千公里邮过来了这个玩意: 那节南孚5号电池是我自己的,是为了对比一 ...

随机推荐

  1. 在JAVA中生成RSA秘钥对实现SSH互信

    https://blog.csdn.net/u014196729/article/details/51496262 https://blog.csdn.net/u013066244/article/d ...

  2. day3 集合set()实例分析

        集合,我们在高中的时候专门学习过集合,并集,交集,差集等,下面来看一下集合的定义,如下: 集合(简称集)是数学中一个基本概念,它是集合论的研究对象,集合论的基本理论直到19世纪才被创立.最简单 ...

  3. Android 之XML数据解析(2)—— SAX解析

    (以下文章基本照抄郭霖大神的<第一行代码>) 在Android之 解析XML文件(1)—— Pull解析 中我们讲了Pull方式解析XML文件.今天讲另外一种方式,SAX解析XML文件. ...

  4. scrapy抓取拉勾网职位信息(八)——使用scrapyd对爬虫进行部署

    上篇我们实现了分布式爬取,本篇来说下爬虫的部署. 分析:我们上节实现的分布式爬虫,需要把爬虫打包,上传到每个远程主机,然后解压后执行爬虫程序.这样做运行爬虫也可以,只不过如果以后爬虫有修改,需要重新修 ...

  5. 二进制拆位(贪心)【p2114】[NOI2014]起床困难综合症

    Description 21世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm一直坚持与起床困难综合症作斗争.通过研究相关文献,他找到了 ...

  6. PlayMaker的Transition和Global Transition

    PlayMaker的Transition和Global Transition   在PlayMaker中,Transition是指从一个状态(State)过渡到另外一个状态.它由事件(Event)实现 ...

  7. urllib2 调用salt restapi

    1获取token #_*_coding:utf8_*_ import urllib2 import json def get_token(): url='http://10.20.32.86:8000 ...

  8. 【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

    3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 830  Solved: 338 Description ...

  9. BZOJ4552 HEOI2016排序

    太棒了!思路很不错. 没想到HEOID1三道线段树. 这题我们可以二分答案,将小于他的在线段树中设成0,大于他的设成1然后模拟操作复杂度O(mlog^2n) By:大奕哥 #include<bi ...

  10. fpdf中文乱码,添加字符集

    中文乱码 引入Olivier的chinese.php(点击下载) 支持中文,其中有Big5,GB两种 使用方法也很简单 $pdf->AddBig5Font(); $pdf->SetFont ...