美文网首页
PC蜂鸣器音乐

PC蜂鸣器音乐

作者: 网路元素 | 来源:发表于2019-10-30 07:26 被阅读0次

有了《使用procfs》、《I/O映射之I/O端口》、《内核读写磁盘文件》这三篇文章的基础后,我们将其结合,实现如下功能的实例: 

1.打开传入的音乐谱文件(通过procfs接口);
2.读取音乐谱文件(以“频率”、“延时”、“频率”、“延时”、……这样的格式保存);
3.解析读取的文件;
4.将解析的数据传送去操作8254,让PC蜂鸣器弹奏文件对应的音乐。 

好了,基础的内容看开头提及的文章,接下来上代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/timex.h>

#ifndef MAX_PATH
#define MAX_PATH 256
#endif

#define PACKAGE_SIZE 512

extern void msleep(unsigned int msecs);

struct proc_dir_entry * slam_dir = NULL;
struct proc_dir_entry * slam_entry = NULL;

static char * dir_name = "slam_song";
static char * entry_name = "path";

static void beep(unsigned int freq, unsigned int delay)
{
        unsigned int count;

        if (freq)
                count = PIT_TICK_RATE / freq;
        else
                count = 20;

        outb_p(0xB6, 0x43);
        outb_p(count & 0xff, 0x42);
        outb((count >> 8) & 0xff, 0x42);
        outb_p(inb_p(0x61) | 0x03, 0x61);
        msleep(delay);
        outb(inb_p(0x61) & 0xFC, 0x61);
}

static int play(char * filename)
{
        struct file * fp;
        mm_segment_t cur_mm_seg;
        loff_t fpos = 0;
        char buf;
        int data[PACKAGE_SIZE] = {0};
        int i = 0, j = 0; //i:data count,j:just temp value

        fp = filp_open(filename, O_RDONLY, 0644);
        if (IS_ERR(fp)) {
                printk("<xinu>filp_open error\n");
                return -1;
        }

        cur_mm_seg = get_fs();
        set_fs(KERNEL_DS);

        while(vfs_read(fp, &buf, sizeof(buf), &fpos)>0)
        {
                if(buf == ','){
                        i++;
                        continue;
                }

                if(buf == '\n' || buf == '\r')
                        continue;

                data[i] = data[i] * 10 + (buf - '0');
        }

        set_fs(cur_mm_seg);
        filp_close(fp, NULL);

        for (j = 0; j < i; j += 2) {
                beep(data[j], data[j+1]);
        }

        return 0;
}

static ssize_t song_path_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
        char filename[MAX_PATH];
        if(count > MAX_PATH){
                printk("The filename is too long,the length must < %d\n", MAX_PATH);
                return -EFAULT;
        }

        if(copy_from_user(filename, buf, count)){
                printk("copy_from_user error!\n");
                return -EFAULT;
        }

        filename[count-1] = '\0';
        play(filename);

        return count;
}

static const struct file_operations slam_fops =
{
        .owner = THIS_MODULE,
        .write = song_path_write,
};

static int beep_songs_init(void)
{
#ifdef CONFIG_PROC_FS
        slam_dir = proc_mkdir(dir_name, NULL);
        if (!slam_dir){
                printk("Create directory \"%s\" failed.\n", dir_name);
                return -1;
        }

        slam_entry = proc_create(entry_name, 0666, slam_dir, &slam_fops);
        if (!slam_entry){
                printk("Create file \"%s\" failed.\n", entry_name);
                return -1;
        }
#else
        printk("This module requests PROCFS support in linux kernel,need set CONFIG_PROC_FS configure Y\n");
#endif
        return 0;
}

static void beep_songs_exit(void)
{
#ifdef CONFIG_PROC_FS
        proc_remove(slam_entry);
        proc_remove(slam_dir);
#endif
        printk("Bye %s!\n", __func__);
}

module_init(beep_songs_init);
module_exit(beep_songs_exit);

MODULE_LICENSE("GPL");

相应的Makefile文件内容如下:

obj-m += beep_songs.o

CUR_PATH:=$(shell pwd)
LINUX_KERNEL_PATH:=/home/xinu/linux-3.13.6

all:
        make -C $(LINUX_KERNEL_PATH) M=$(CUR_PATH) modules

clean:
        make -C $(LINUX_KERNEL_PATH) M=$(CUR_PATH) clean

对应的源码文件目录树如下: 

/home/xinu/xinu/linux_kernel_driver_l1/beep_songs/
├── beep_songs.c
└── Makefile 

下面有两个实现好的音乐文件: 

1.中文版“生日快乐歌”(happy_birthday_chinese.txt):

392,375,392,125,440,500,392,500,523,500,494,1000,392,375,392,125,440,500,392,500,587,500,523,1000,392,375,392,125,784,500,659,500,523,500,494,500,440,1000,698,375,698,125,659,500,523,500,587,500,523,1000

2.周华健“朋友”(pengyou.txt):

0,900,587,450,659,450,523,900,587,450,659,450,587,900,659,450,784,450,880,900,784,450,659,450,659,900,587,450,659,450,523,900,587,450,659,450,392,900,587,450,659,450,587,900,440,450,523,4950,587,450,659,450,523,900,587,450,459,450,523,900,587,450,659,450,784,900,784,450,880,450,523,900,440,450,523,450,587,900,587,450,523,450,440,900,440,450,523,450,587,450,659,450,587,450,523,225,587,225,587,900,659,450,587,225,523,225,523,900,587,450,587,450,659,900,523,450,587,450,659,900,784,450,784,225,784,225,880,900,523,450,440,450,523,900,587,450,587,225,523,225,440,900,440,450,392,450,440,1800,523,900,0,450,659,225,659,225,784,450,784,450,784,450,784,225,880,1125,784,450,880,450,988,450,1046,450,880,450,880,225,784,1125,659,450,659,225,587,1125,523,450,523,225,880,1125,784,450,659,225,587,1125,523,225,523,225,440,1350,587,450,659,225,659,225,784,450,784,450,784,450,784,225,880,11,784,25,880,450,988,450,1046,450,880,450,880,450,784,225,659,1125,659,450,587,225,523,1125,523,450,880,225,784,1125,659,450,587,225,523,1125,440,450,440,225,523,675,523,1350

当我们将上面的模块编译加载后,会在/proc目录下有/proc/slam_song/path文件生成,然后我们将上面的音乐文件路径写入该文件后即可开始演奏,如下: 

echo “/home/xinu/happy_birthday_chinese.txt” > /proc/slam_song/path
echo “/home/xinu/pengyou.txt” > /proc/slam_song/path 

本例解决了之前相关例子里beep函数对freq为0时未做除数0的检查,还有本例有如下优化建议: 

1.在写入文件路径时需等待演奏结束才返回,此时可采用多线程方式解决;
2.采用多线程方式处理后,还需要使用同步机制对演奏过程中再次写入路径情况进行处理。 

关于这两条建议,我们将在后面的实例中再展开应用,你可先在本例基础上做些尝试。 

参考资料:

http://blog.csdn.net/sky_j123/article/details/19574955

相关文章

  • PC蜂鸣器音乐

    有了《使用procfs》、《I/O映射之I/O端口》、《内核读写磁盘文件》这三篇文章的基础后,我们将其结合,实现如...

  • Shell脚本弹奏中文版“生日快乐歌”

    在《Shell命令控制蜂鸣器发声》一文中,我们了解到了如何在Ubuntu下安装beep命令来控制PC主板上蜂鸣器发...

  • 内联汇编控制PC蜂鸣器

    有了《初识Linux汇编》和《I/O映射之I/O端口》两篇文章的基础学习后,我们对控制PC蜂鸣器的操作改为使用内联...

  • C编程使用内联汇编控制PC蜂鸣器发声

    有了《初识Linux汇编》和《内联汇编控制PC蜂鸣器》两篇文章的基础了解后,我们使用内联汇编来改造《C编程控制PC...

  • C编程控制PC蜂鸣器

    在《I/O映射之I/O端口》一文中,我们实现了在Linux内核驱动里实现IO端口操作8254定时计数器芯片里的寄存...

  • Arduino 演奏音乐并显示音符

    功能说明 按下开关蜂鸣器演奏音乐,并在数码管显示音符。 线路 需要的元件: 蜂鸣器 LED数码管 开关 电阻8个 ...

  • 【树莓派+arduino实验记录6】无源与有源蜂鸣器

    Arduino 有源蜂鸣器 无源蜂鸣器 树莓派 有源蜂鸣器 C Python 无源蜂鸣器 C Python

  • 使用arduino编写一个音乐播放程序,播放Super Mario music。需要一个蜂鸣器,音乐文件的音谱...

  • 树莓派基础实验9:蜂鸣器实验

    一、介绍    蜂鸣器是音频信号装置,蜂鸣器可分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器直接接上额定电源就可以连续发声...

  • MIDI音乐播放(STM 32)

    利用蜂鸣器发出一段音乐,此例程只写了buzzer的消息响应,main函数请自己添加

网友评论

      本文标题:PC蜂鸣器音乐

      本文链接:https://www.haomeiwen.com/subject/btqryctx.html