博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Nios II实用之音频控制
阅读量:4599 次
发布时间:2019-06-09

本文共 7013 字,大约阅读时间需要 23 分钟。

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

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

软核部分:

1、在SOPC Builder中添加PWM,

 

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

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

 

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

ContractedBlock.gif
ExpandedBlockStart.gif
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。

软件部分:

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

音调定义:

ContractedBlock.gif
ExpandedBlockStart.gif
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

音调长度定义:

ContractedBlock.gif
ExpandedBlockStart.gif
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首:

ContractedBlock.gif
ExpandedBlockStart.gif
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
};

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

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

ContractedBlock.gif
ExpandedBlockStart.gif
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行:将定时器的时间设置成节拍的时间长度值,最后使能定时器。

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

ContractedBlock.gif
ExpandedBlockStart.gif
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
}

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

ContractedBlock.gif
ExpandedBlockStart.gif
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是定义的宏,没写出)听起来效果还不错哦。这次就先写到这里吧,就当要写论文前的小练笔吧,写作水平还有待于提高啊。呵呵。

转载于:https://www.cnblogs.com/kongtiao/archive/2011/03/24/1993878.html

你可能感兴趣的文章
Unity3d android开发之触摸操作识别-双击,滑动去噪处理
查看>>
Custom view * is not using the 2- or 3-argument View constructors; XML attributes will not work
查看>>
模型选择准则
查看>>
安卓动态增加按钮
查看>>
iOS7程序后台运行
查看>>
maven+testng+reportng的pom设置
查看>>
IT telephone interview
查看>>
gitlab安装配置
查看>>
ps载入画笔
查看>>
悲怆:IT人的一声叹息->一个程序员的自白[转帖]
查看>>
[SpringMVC]自定义注解实现控制器访问次数限制
查看>>
日记(序)
查看>>
A == B ?
查看>>
洛谷P3763 [Tjoi2017]DNA 【后缀数组】
查看>>
GSM模块_STM32实现GPRS与服务器数据传输经验总结
查看>>
5.Python进阶_循环设计
查看>>
【NLP】揭秘马尔可夫模型神秘面纱系列文章(一)
查看>>
Android采访开发——2.通用Android基础笔试题
查看>>
UVa 442 Matrix Chain Multiplication(矩阵链,模拟栈)
查看>>
多种方法求解八数码问题
查看>>