本题目为音乐流水灯的设计,目的是熟练掌握DSP定时器的控制、中断系统的应用以及程序的编写调试。
1、让DSP发出不同的音乐音调;
2、存储一个简单音乐(自选);
3、音乐的音调对应不同的灯
4、启动开关按下时,音乐流水灯开始运行,在播放音乐的同时,LED灯根据不同音调点亮;
5、按要求编写课程设计报告书,正确、完整的阐述设计和实验结果。
我们单片机的发声是通过蜂鸣器发出的,所以我们先了解一下蜂鸣器:
1.蜂鸣器介绍
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、 打印机、 复印机、 报警器、 电子玩具、 汽车电子设备、 电话机、 定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
压电式蜂鸣器主要由多谐振荡器、 压电蜂鸣片、 阻抗匹配器及共鸣箱、 外壳等组成。 多谐振荡器由晶体管或集成电路构成, 当接通电源后( 1.5~15V 直流工作电压),多谐振荡器起振,输出 1.5~5kHZ 的音频信号, 阻抗匹配器推动压电蜂鸣片发声。(无源蜂鸣器)
所以要使蜂鸣器发声,只需要频率在1.5到5khz之间即可
下面我们通过一个实验使DSP芯片发声:
打开ccs软件
1.新建一个项目:在我之前的博客写过
2.项目中的文件如下:(采用的是模块化编程),每个模块写好之后具有移植性
leds.c
#include "leds.h"
/*******************************************************************************
* 函 数 名 : LED_Init
* 函数功能 : LED初始化函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LED_Init(void)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1;// 开启GPIO时钟
//LED1端口配置
GpioCtrlRegs.GPCMUX1.bit.GPIO68=0;//设置为通用GPIO功能
GpioCtrlRegs.GPCDIR.bit.GPIO68=1;//设置GPIO方向为输出
GpioCtrlRegs.GPCPUD.bit.GPIO68=0;//使能GPIO上拉电阻
//LED2端口配置
GpioCtrlRegs.GPCMUX1.bit.GPIO67=0;
GpioCtrlRegs.GPCDIR.bit.GPIO67=1;
GpioCtrlRegs.GPCPUD.bit.GPIO67=0;
//LED3端口配置
GpioCtrlRegs.GPCMUX1.bit.GPIO66=0;
GpioCtrlRegs.GPCDIR.bit.GPIO66=1;
GpioCtrlRegs.GPCPUD.bit.GPIO66=0;
//LED4端口配置
GpioCtrlRegs.GPCMUX1.bit.GPIO65=0;
GpioCtrlRegs.GPCDIR.bit.GPIO65=1;
GpioCtrlRegs.GPCPUD.bit.GPIO65=0;
//LED5端口配置
GpioCtrlRegs.GPCMUX1.bit.GPIO64=0;
GpioCtrlRegs.GPCDIR.bit.GPIO64=1;
GpioCtrlRegs.GPCPUD.bit.GPIO64=0;
//LED6端口配置
GpioCtrlRegs.GPAMUX1.bit.GPIO10=0;
GpioCtrlRegs.GPADIR.bit.GPIO10=1;
GpioCtrlRegs.GPAPUD.bit.GPIO10=0;
//LED7端口配置
GpioCtrlRegs.GPAMUX1.bit.GPIO11=0;
GpioCtrlRegs.GPADIR.bit.GPIO11=1;
GpioCtrlRegs.GPAPUD.bit.GPIO11=0;
GpioDataRegs.GPCSET.bit.GPIO68=1;
GpioDataRegs.GPCSET.bit.GPIO67=1;
GpioDataRegs.GPCSET.bit.GPIO66=1;
GpioDataRegs.GPCSET.bit.GPIO65=1;
GpioDataRegs.GPCSET.bit.GPIO64=1;
GpioDataRegs.GPASET.bit.GPIO10=1;
GpioDataRegs.GPASET.bit.GPIO11=1;
EDIS;
}
leds.h
#ifndef _LEDS_H_
#define _LEDS_H_
#include "DSP2833x_Device.h" // DSP2833x 头文件
#include "DSP2833x_Examples.h" // DSP2833x 例子相关头文件
#define LED1_OFF (GpioDataRegs.GPCSET.bit.GPIO68=1)
#define LED1_ON (GpioDataRegs.GPCCLEAR.bit.GPIO68=1)
#define LED1_TOGGLE (GpioDataRegs.GPCTOGGLE.bit.GPIO68=1)
#define LED2_OFF (GpioDataRegs.GPCSET.bit.GPIO67=1)
#define LED2_ON (GpioDataRegs.GPCCLEAR.bit.GPIO67=1)
#define LED2_TOGGLE (GpioDataRegs.GPCTOGGLE.bit.GPIO67=1)
#define LED3_OFF (GpioDataRegs.GPCSET.bit.GPIO66=1)
#define LED3_ON (GpioDataRegs.GPCCLEAR.bit.GPIO66=1)
#define LED3_TOGGLE (GpioDataRegs.GPCTOGGLE.bit.GPIO66=1)
#define LED4_OFF (GpioDataRegs.GPCSET.bit.GPIO65=1)
#define LED4_ON (GpioDataRegs.GPCCLEAR.bit.GPIO65=1)
#define LED4_TOGGLE (GpioDataRegs.GPCTOGGLE.bit.GPIO65=1)
#define LED5_OFF (GpioDataRegs.GPCSET.bit.GPIO64=1)
#define LED5_ON (GpioDataRegs.GPCCLEAR.bit.GPIO64=1)
#define LED5_TOGGLE (GpioDataRegs.GPCTOGGLE.bit.GPIO64=1)
#define LED6_OFF (GpioDataRegs.GPASET.bit.GPIO10=1)
#define LED6_ON (GpioDataRegs.GPACLEAR.bit.GPIO10=1)
#define LED6_TOGGLE (GpioDataRegs.GPATOGGLE.bit.GPIO10=1)
#define LED7_OFF (GpioDataRegs.GPASET.bit.GPIO11=1)
#define LED7_ON (GpioDataRegs.GPACLEAR.bit.GPIO11=1)
#define LED7_TOGGLE (GpioDataRegs.GPATOGGLE.bit.GPIO11=1)
void LED_Init(void);
#endif /* LED_H_ */
beep.c
#include "beep.h"
void BEEP_Init(void)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK=1;//开启GPIO时钟
//BEEP端口配置
GpioCtrlRegs.GPAMUX1.bit.GPIO6=0;
GpioCtrlRegs.GPADIR.bit.GPIO6=1;
GpioCtrlRegs.GPAPUD.bit.GPIO6=0;
EDIS;
GpioDataRegs.GPACLEAR.bit.GPIO6=1;
}
beep.h
#ifndef BEEP_H_
#define BEEP_H_
#include "DSP2833x_Device.h" // DSP2833x 头文件
#include "DSP2833x_Examples.h" // DSP2833x 例子相关头文件
#define BEEP_ON (GpioDataRegs.GPASET.bit.GPIO6=1)
#define BEEP_OFF (GpioDataRegs.GPACLEAR.bit.GPIO6=1)
#define BEEP_TOGGLE (GpioDataRegs.GPATOGGLE.bit.GPIO6=1)
void BEEP_Init(void);
#endif /* BEEP_H_ */
我们先了解一下音乐与单片机如何结合在一起的原理
通过这些频率取倒数,得到周期,再除以2,即得到一个音调高电平持续的时间。
下面是一些表格计算的周期时间:
有了这些数据,我们便可以使用数组来存储这些值。
有关音乐的知识在这里就不再写了,大家可以百度上去查看,
最重要的是 音调加节奏
节奏就是一个音持续多长时间,这里我可以先简单说一下,
4分音符 8分音符 16分音符 2分音符
一般我们是以4分音符为标准,假如让它的时值为1,
那么2分音符就是它的时值的两倍。
8分音符的时值就是它的1/2。
16分音符的时值就是它的1/4.
这样每个音持续的时间我们也可以用一个1数组存起来。
下面我们以一闪一闪亮晶晶这首歌为例子
4/4表示的是以四份音符为一拍,每小节四拍
比如 1 1 5 5 都是四分音符,刚好四个合在一起为4拍。
—表示的声音的延长,如果与5结合的话,表示的是两拍。所以我们把四分音符定义为2的速度的··话,5-表示的四
下图所示即我们的音乐
Uint16 Song[]={1,1,5,5,6,6,5,4,4,3,3,2,2,1,5,5,4,4,3,3,2,5,5,4,4,3,3,2,22}; //一闪一闪亮晶晶
Uint16 DT[] ={2,2,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,2,2,4}; //节拍
我们课设的第三个任务是音乐的音调对应不同的灯,我们又写了一个函数,LEDx_TOGGLE表示的是LED翻转,我们通过a来控制
void ledSelect(int a)
{
switch(a)
{
case 0: LED1_TOGGLE; break;
case 1: LED2_TOGGLE; break;
case 2: LED3_TOGGLE; break;
case 3: LED4_TOGGLE; break;
case 4: LED5_TOGGLE; break;
case 5: LED6_TOGGLE; break;
case 6: LED7_TOGGLE; break;
}
}
最后是与这句话连接在一起的,song是我们前面创建的歌曲的音调数组,addr从0开始,比如song[0]=1, 1+1=2, 2%7=2, 2-对应第三盏LED灯亮 也就是
do--3
re--4
mi--5
fa--6
sol-7
la--1
xi--2
ledSelect((Song[addr]+1) % 7);
addr++;
main.c如下
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
#include "leds.h"
#include "key.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
#include "leds.h"
#include "beep.h"
Uint16 Musi[23]={ //单位us,不同频率下,不同声调的声音
0, //静止符
3816, //L_do
3496, //L_re
3215, //L_mi
2865, //L_fa
2551, //L_so
2272, //L_la
2024, //L_xi
1912, //do
1703, //re
1517, //mi
1432, //fa
1275, //so
1136, //la
1013, //xi
956, //H_do
851, //H_re
758, //H_mi
716, //H_fa
638, //H_so
568, //H_la
506, //H_xi
0xFF //STOP
};
//Uint16 Song[]={1,1,5,5,6,6,5,4,4,3,3,2,2,1,5,5,4,4,3,3,2,5,5,4,4,3,3,2,22}; //一闪一闪亮晶晶
//Uint16 DT[] ={2,2,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,2,2,4}; //节拍
//Uint16 Song[]={5,5,6,5,8,7,5,5,6,5,8,7,5,5,5,10,8,7,6,11,10,8,9,8,22}; //祝你生日快乐
//Uint16 DT[] ={2,2,5,4,6,8,2,2,5,6,6,9,4,2,5,4,6,12,2,2,5,6,8,12 }; //节拍
Uint16 Song[]={15,16,13,15,12,19,21,20,19,17,19,16,16,17,14,13,
12,13,15,16,10,15,13,12,13,15,12,17,19,14,16,13,
15,12,10,12,10,12,13,14,16,13,12,13,15,16,19,17,
16,17,16,15,13,12,10,10,15,13,15,13,12,10,12,13,
15,12,22}; //梁祝
Uint16 DT[] ={3,1,1,1,2,3,1,1,1,1,1,4,3,1,2,2,
3,1,2,2,2,2,1,1,1,1,4,3,1,2,2,1,
1,4,1,2,2,1,1,1,1,4,1,1,3,1,2,2,
2,1,1,2,1,1,2,4,4,3,1,1,1,1,1,1,
1,4}; //节拍
Uint32 gain = 600000;//以600ms为一个四分音符的节拍,
void ledSelect(int a)
{
switch(a)
{
case 0: LED1_TOGGLE; break;
case 1: LED2_TOGGLE; break;
case 2: LED3_TOGGLE; break;
case 3: LED4_TOGGLE; break;
case 4: LED5_TOGGLE; break;
case 5: LED6_TOGGLE; break;
case 6: LED7_TOGGLE; break;
}
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
InitSysCtrl();
LED_Init();
BEEP_Init();
KEY_Init();
while(1)
{
Uint16 addr = 0;
while(1)
{
if(Musi[Song[addr]] == 0xFF)//如果music到了停止符,
{
break;//跳出循环,停止播放音乐
}
else
{
Uint32 countTime = 0;//countTime来计算时间
ledSelect((Song[addr]+1) % 7);
while(countTime < gain * DT[addr])//
{
if(countTime % Musi[Song[addr]] == 0)
BEEP_TOGGLE;//蜂鸣器响
countTime++;
}
ledSelect((Song[addr]+1) % 7);
Uint32 i = 0;
for(i = 0;i < gain; i++);
addr++;
}
}
}
}