• Nios II实用之音频控制


      最近想整理一下割草机里面所设计到的小技术,先大体了解下它的整体框架,它以FPGA为核心,两个PIC对传感器的数据进行处理,然后通过串口发送给FPGA数据。在FPGA中,Nios处理器添加必要的中断,捕捉传感器信号,进行简单的防卫功能。

      今天想对车子上的声音控制做一个总结,声音是通过PWM来控制的,PWM的频率能变化出不同的音调,音节的长短,可以通过定时器来控制,当选择好一个音节后,音节响的过程中是不占用处理器的。

    软核部分:

    1、在SOPC Builder中添加PWM,

     

           这里我只是针对声音的控制,还有的模块添加没有说明,当一切都添加完后,对Nios处理器进行编译,我们就能得到最终的模块,如下图,

    2、在SOPC Builder中添加定时器,

     

    编译好后,在NIOS II IDE中的system.h中会生成如下内容:

    View Code
    1 /*
    2 * pwm_speaker configuration
    3 *
    4 */
    5  #define PWM_SPEAKER_NAME "/dev/pwm_speaker"
    6  #define PWM_SPEAKER_TYPE "pwm_avalon_interface"
    7  #define PWM_SPEAKER_BASE 0x08002270
    8  #define PWM_SPEAKER_SPAN 16
    9  #define PWM_SPEAKER_HDL_PARAMETERS ""
    10  #define ALT_MODULE_CLASS_pwm_speaker pwm_avalon_interface
    11
    12  /*
    13 * timer_2_ms configuration
    14 *
    15 */
    16  #define TIMER_2_MS_NAME "/dev/timer_2_ms"
    17  #define TIMER_2_MS_TYPE "altera_avalon_timer"
    18  #define TIMER_2_MS_BASE 0x080020c0
    19 #define TIMER_2_MS_SPAN 32
    20 #define TIMER_2_MS_IRQ 13
    21 #define TIMER_2_MS_ALWAYS_RUN 0
    22 #define TIMER_2_MS_FIXED_PERIOD 0
    23 #define TIMER_2_MS_SNAPSHOT 1
    24 #define TIMER_2_MS_PERIOD 1.0
    25 #define TIMER_2_MS_PERIOD_UNITS "ms"
    26 #define TIMER_2_MS_RESET_OUTPUT 0
    27 #define TIMER_2_MS_TIMEOUT_PULSE_OUTPUT 0
    28 #define TIMER_2_MS_LOAD_VALUE 49999
    29 #define TIMER_2_MS_MULT 0.001
    30 #define TIMER_2_MS_FREQ 50000000
    31 #define ALT_MODULE_CLASS_timer_2_ms altera_avalon_timer

      他们对应先前添加的2个模块,在后面的代码中会用到他们的基地址PWM_SPEAKER_BASE和TIMER_2_MS_BASE。

    软件部分:

      下面首先是准备音乐的前期工作,定义好它的音调与音调长度(说的有点不专业啊- -!)

    音调定义:

    View Code
    1 /* 低音 */
    2 #define _1DO 262
    3 #define _1RE 294
    4 #define _1MI 330
    5 #define _1FA 349
    6 #define _1SO 392
    7 #define _1LA 440
    8 #define _1TI 494
    9
    10 /* 中音 */
    11 #define _DO 523
    12 #define _RE 587
    13 #define _MI 659
    14 #define _FA 698
    15 #define _SO 784
    16 #define _LA 880
    17 #define _TI 988
    18
    19 /* 高音 */
    20 #define _DO1 1047
    21 #define _RE1 1175
    22 #define _MI1 1319
    23 #define _FA1 1397
    24 #define _SO1 1568
    25 #define _LA1 1760
    26 #define _TI1 1976

    音调长度定义:

    View Code
    1 // 以4分音符为1拍
    2 #define TEMPO 8
    3 #define _0 0
    4 #define _1 TEMPO*4 //全音符
    5 #define _1d TEMPO*6 //附点全音符
    6 #define _2 TEMPO*2 //2音符
    7 #define _2d TEMPO*3 //附点2音符
    8 #define _4 TEMPO*1 //4分音符
    9 #define _4d TEMPO*3/2 //附点4分音符
    10 #define _8 TEMPO*1/2 //8分音符
    11 #define _8d TEMPO*3/4 //附点8音符
    12 #define _16 TEMPO*1/4 //16分音符
    13 #define _16d TEMPO*3/8 //附点16分音符
    14 #define _32 TEMPO*1/8 //32分音符
    15 #define _END 100 //音频结束

    歌谱:

      从网上找了2个家喻户晓的曲子,一首是欢乐颂,一首是茉莉花,根据感觉用上面的音调和音调长度谱了下面2首:

    View Code
    1 int Music_Buf27[]=//欢乐颂
    2 {
    3 _MI,_4,_MI,_4,_FA,_4,_SO,_4,
    4 _SO,_4,_FA,_4,_MI,_4,_RE,_4,
    5 _DO,_4,_DO,_4,_RE,_4,_MI,_4,
    6 _MI,_4d,_RE,_8,_RE,_2,
    7 _MI,_4,_MI,_4,_FA,_4,_SO,_4,
    8 _SO,_4,_FA,_4,_MI,_4,_RE,_4,
    9 _DO,_4,_DO,_4,_RE,_4,_MI,_4,
    10 _RE,_4d,_DO,_8,_DO,_2,
    11 _RE,_4,_RE,_4,_MI,_4,_DO,_4,
    12 _RE,_4,_MI,_8,_FA,_8,_MI,_4,_DO,_4,
    13 _RE,_4,_MI,_8,_FA,_8,_MI,_4,_RE,_4,
    14 _DO,_4,_RE,_4,_1SO,_4,_MI,_4,
    15 _MI,_4,_MI,_4,_FA,_4,_SO,_4,
    16 _SO,_4,_FA,_4,_MI,_4,_FA,_8,_RE,_8,
    17 _DO,_4,_DO,_4,_RE,_4,_MI,_4,
    18 _RE,_4d,_DO,_8,_DO,_2,_0,_4,_END,
    19 };
    20
    21 int Music_Buf28[]=//茉莉花
    22 {
    23 _MI,_4,_MI,_8,_SO,_8,_LA,_8,_DO1,_8,_DO1,_8,_LA,_8,
    24 _SO,_4,_SO,_8,_LA,_8,_SO,_2,
    25 _MI,_4,_MI,_8,_SO,_8,_LA,_8,_DO1,_8,_DO1,_8,_LA,_8,
    26 _SO,_4,_SO,_8,_LA,_8,_SO,_2,
    27 _SO,_4,_SO,_4,_SO,_4,_MI,_8,_SO,_8,
    28 _LA,_4,_LA,_4,_SO,_2,
    29 _MI,_4,_RE,_8,_MI,_8,_SO,_4,_MI,_8,_RE,_8,
    30 _DO,_4,_DO,_8,_RE,_8,_DO,_2,
    31 _MI,_8,_SO,_8,_DO,_8,_MI,_8,_RE,_4d,_MI,_8,
    32 _SO,_4,_LA,_8,_DO1,_8,_SO,_2,
    33 _RE,_4,_MI,_8,_SO,_8,_RE,_8,_MI,_8,_DO,_8,_1LA,_8,
    34 _1SO,_2,_1LA,_4,_DO,_4,
    35 _RE,_4d,_MI,_8,_DO,_8,_RE,_8,_DO,_8,_1LA,_8,
    36 _1SO,_2d,_0,_4,_END,
    37 };

    注:数组的结构是:一个音调和一个节拍相间隔,数字越大,节拍越短。

    下面就是代码的主体部分,音乐的接口函数:

    View Code
    1 void music ( unsigned int type )
    2 {
    3 if ( ( type != OFF ) && ( Music_Replay >1 ) ) return;
    4 altera_avalon_pwm_disable ( PWM_SPEAKER_BASE );
    5 alt_irq_disable ( TIMER_2_MS_IRQ );
    6 if ( type == OFF ) { Music_Replay=0; return;}
    7
    8 Music_Replay= ( type&0xffff00 ) >>8;
    9 if ( Music_Replay==0 ) Music_Replay=1;
    10 Music_Syllable = 0;
    11 int Track = ( type & 0xff ); //曲目缓冲
    12 switch ( Track )
    13 {
    14 case MUSIC_9_3:
    15 Music_Buf= Music_Buf27;
    16 break;
    17 case MUSIC_9_4:
    18 Music_Buf= Music_Buf28;
    19 break;
    20 }
    21
    22 if ( Music_Buf[Music_Syllable]!=_0 )
    23 {
    24 int PWMMR0 = 35000000 / Music_Buf[Music_Syllable]; // 设置输出频率
    25 altera_avalon_pwm_init ( PWM_SPEAKER_BASE,PWMMR0,PWMMR0*3/4 );
    26 altera_avalon_pwm_enable ( PWM_SPEAKER_BASE );
    27 }
    28 Music_Syllable++; // 设置延时
    29 int delay=Music_Buf[Music_Syllable]*TIMER_1_SECOND*0.025;
    30 IOWR_ALTERA_AVALON_TIMER_PERIODL ( TIMER_2_MS_BASE, ( delay & 0xffff ) );
    31 IOWR_ALTERA_AVALON_TIMER_PERIODH ( TIMER_2_MS_BASE, ( ( delay>>16 ) &0xffff ) );
    32 IOWR_ALTERA_AVALON_TIMER_CONTROL ( TIMER_2_MS_BASE, ALTERA_AVALON_TIMER_CONTROL_ITO_MSK|ALTERA_AVALON_TIMER_CONTROL_START_MSK|ALTERA_AVALON_TIMER_CONTROL_CONT_MSK );
    33 IOWR_ALTERA_AVALON_TIMER_STATUS ( TIMER_2_MS_BASE, 0 ); //清TO标志
    34 alt_irq_enable ( TIMER_2_MS_IRQ );
    35 }

    注:

      第8行:变量Music_Replay是控制音乐循环播放的次数,默认是播放1遍;

      第24~26行:对音调处理,然后通过PWM表现,初始并且使能它;

      第29~34行:将定时器的时间设置成节拍的时间长度值,最后使能定时器。

    对定时器的控制,先是初始化:

    View Code
    1 void init_timer2()
    2 {
    3 IOWR_ALTERA_AVALON_TIMER_PERIODL ( TIMER_2_MS_BASE, TIMER_1_SECOND&0xffff );
    4 IOWR_ALTERA_AVALON_TIMER_PERIODH ( TIMER_2_MS_BASE, ( TIMER_1_SECOND>>16 ) &0xffff );
    5 IOWR_ALTERA_AVALON_TIMER_CONTROL ( TIMER_2_MS_BASE, ALTERA_AVALON_TIMER_CONTROL_ITO_MSK|ALTERA_AVALON_TIMER_CONTROL_START_MSK|ALTERA_AVALON_TIMER_CONTROL_CONT_MSK );
    6 alt_irq_register ( TIMER_2_MS_IRQ, NULL, timer2_ISR );
    7 alt_irq_disable ( TIMER_2_MS_IRQ );
    8 }

    然后是定时器中断函数的编写:

    View Code
    1 static void timer2_ISR ( void* context, alt_u32 id )
    2 {
    3 altera_avalon_pwm_disable ( PWM_SPEAKER_BASE );
    4 alt_irq_disable ( TIMER_2_MS_IRQ );
    5 Music_Syllable++;
    6 if ( Music_Buf[Music_Syllable]==_END )
    7 {
    8 Music_Replay--;
    9 if ( Music_Replay == 0 ) return;
    10 Music_Syllable=0;
    11 }
    12
    13 if ( Music_Buf[Music_Syllable]!=_0 )
    14 {
    15 int PWMMR0 = 35000000 / Music_Buf[Music_Syllable]; // 设置输出频率
    16 altera_avalon_pwm_init ( PWM_SPEAKER_BASE,PWMMR0,PWMMR0*3/4 );
    17 altera_avalon_pwm_enable ( PWM_SPEAKER_BASE );
    18 }
    19 Music_Syllable++; // 设置延时
    20 int delay=Music_Buf[Music_Syllable]*TIMER_1_SECOND*0.04;
    21 IOWR_ALTERA_AVALON_TIMER_PERIODL ( TIMER_2_MS_BASE, ( delay & 0xffff ) );
    22 IOWR_ALTERA_AVALON_TIMER_PERIODH ( TIMER_2_MS_BASE, ( ( delay>>16 ) &0xffff ) );
    23 IOWR_ALTERA_AVALON_TIMER_CONTROL ( TIMER_2_MS_BASE, ALTERA_AVALON_TIMER_CONTROL_ITO_MSK|ALTERA_AVALON_TIMER_CONTROL_START_MSK|ALTERA_AVALON_TIMER_CONTROL_CONT_MSK );
    24 IOWR_ALTERA_AVALON_TIMER_STATUS ( TIMER_2_MS_BASE, 0 ); //清TO标志
    25 alt_irq_enable ( TIMER_2_MS_IRQ );
    26 }

    注:

      第6~10行是对播放次数的分析;下面的基本同于上面一个函数。

    最后当然是测试音乐的效果了,

      调用函数music(MUSIC_9_3);则播放欢乐颂;

      调用函数music(MUSIC_9_4);则播放茉莉花;如果想循环播放3遍,则调用函数music(MUSIC_9_4|0x300);

    (MUSIC_9_3、MUSIC_9_4是定义的宏,没写出)听起来效果还不错哦。这次就先写到这里吧,就当要写论文前的小练笔吧,写作水平还有待于提高啊。呵呵。

  • 相关阅读:
    Using X++ Code Create Meeting Request in Outlook
    程序员的健康
    LinkType Property
    C#一些实用的,容易被遗忘的特性,经验和技巧
    如何面试程序员(转)
    uniapp:授权(以微信小程序为例)
    C#(Windows窗口):窗口最大化、最小化
    Docker 安装和启用Tomcat
    Docker 安装和启用ngnix
    Uniapp: 扫码(以微信小程序为例)
  • 原文地址:https://www.cnblogs.com/kongtiao/p/1993878.html
Copyright © 2020-2023  润新知