基于EVM_MSPM0L1306开发套件设计音乐键盘
该项目使用了EVM_MSPM0L1306开发套件,实现了音乐键盘的设计,它的主要功能为:基于MSPM0L1306,键盘按键检测,驱动无源蜂鸣器播放发出不同频率的声音,OLED显示和LED显示音量大小档位和其它信息,电阻ADC检测调整音量大小。
标签
测试
显示
ADC
开发板
weiwei4
更新2024-07-22
12

设计使用了EVM_MSPM0L1306开发套件,开发套件分为核心板与底板组成,核心板板载M0L1306主芯片,底板集成CMSIS-DAP调试器,无源蜂鸣器驱动,电阻ADC检测电路,DAC电路,eeprom芯片电路,flash芯片电路,拔动开关,LED显示电路,OLED模块电路。

音乐键盘功能主要硬件框图如下

使用键盘矩阵进行按键检测,不同的按键对应输出不同的音频驱动频率,ADC检测电阻大小,并将数值转换成0-100的音量大小,OLED进行功能的显示和音量大小数值显示,同时用LED显示音量档位,能更直观的知道当前音量大小数值。

1.键盘矩阵

键盘检测使用扫描方式,将具体需要检测的行清零输出,其余行置1,延时10ms后检测该行键盘是否有按下,并置给了相应的键值,具体扫描方法详见程序Key()函数。扫描方式的弊端是占用太多的时间片,后续可更改为中断方式扫描,可更好的缩短扫描按键占用时间。

2.ADC检测

ADC检测使用1K上拉电阻与10K可调电阻进行检测,ADC频率使用ULPCLK,进行8分频后为4MHz,选择单次转换模式,每次转换需要使能转换函数和启动转换函数。

DL_ADC12_enableConversions(ADC12_0_INST);
DL_ADC12_startConversion(ADC12_0_INST);

因为ADC设置了转换完成中断,为避免ADC转换频率太高影响其它程序执行,故在定时器中以固定时间间隔开启ADC转换。

void TIMER_0_INST_IRQHandler(void)
{
if(gCheckADC == false)
{

DL_ADC12_enableConversions(ADC12_0_INST);
DL_ADC12_startConversion(ADC12_0_INST);
}
}

TIMER_0需要另外使能并开启定时中断。


ADC数值转换,将ADC数据读取后,除于40,再判断是否大于100,如大于100则按100处理。但是有个问题是电路中有个1K上拉电阻,导致ADC数据最大不能达到4000以上(ADC数据范围0-4095),转换出来的后音量数值最大为91,这个数值与电路相符,可以通过调整算法中的除数,使用音量数值达到最大100。

gAdcResult = DL_ADC12_getMemResult(ADC12_0_INST, DL_ADC12_MEM_IDX_0);

playvolue = gAdcResult/40; //因为分压电阻关系导致该转换后最大值为91
if(playvolue > 100)
{
playvolue = 100;
}

3. OLED显示

OLED显示使用硬件SPI驱动 ,PA4引脚设置为CS软件使能引脚,因为SPI连接了多个器件,使用硬件cs不能满足多个器件切换的场景。

OLED显示界面设计如下

>手动弹奏

自动播放

音量100

keyplay-lw

其中 “>”用于指示当前选择功能,默认为手动弹奏,因为自动播放功能未完成,此处不对自动播放功能进行说明。

关于OLED字模的取模,这个与很多LCD显示驱动不同的是需要设置取模方式 为 列行式 ,否则取模出来的数据在显示时乱码,无法正常显示。

4.PWM驱动

音乐的播放其实就是连续播放不同频率的声音,每个声音根据节拍播放相应的时间长度即可。

以下是低中高音对应各个音阶的频率,在实际给到PWM时需要转换成相对应的计数值(4000000/频率)。

#define _1 261    //低音
#define _2 293
#define _3 329
#define _4 349
#define _5 392
#define _6 440
#define _7 494

#define _1d1 523 //中音
#define _2d1 587
#define _3d1 659
#define _4d1 698
#define _5d1 784
#define _6d1 880
#define _7d1 987

#define _1d2 1046 //高音
#define _2d2 1175
#define _3d2 1318
#define _4d2 1397
#define _5d2 1568
#define _6d2 1760
#define _7d2 1976

#define _1d2f 3824 //频率对应计数值
#define _2d2f 3404
#define _3d2f 3034
#define _4d2f 2863
#define _5d2f 2551
#define _6d2f 2272
#define _7d2f 2033

关于驱动引脚的选择,虽然电路中可以使用PA15直接使用短路帽进行连接,但是因为PA15在多个电路中被复用,若用于驱动无源蜂鸣器,则无法驱动LED6。在程序设计中使用PA16进行PWM驱动,避开PA15多次复用,此时需要使用跳线短接J15 的1针脚 和4针脚。

从电学角度来看,压电陶瓷可以简化为一个电感和一个电容的串联模型。因此在电路设计时,需要在压电蜂鸣器并联一个反向二极管用于释放压电蜂鸣器存储电压,不然压电蜂鸣片无法发出声音。另外关于播放音量大小,很多蜂鸣片的频率在4KHz或4.8KHz,若PWM驱动频率无法落在这些频率附近,那么压电蜂鸣片发出的声音将无法达到可达到的最大分贝值并可能相差很远。下面附压电峰鸣片的频响曲线参考(下图非本设计中使用的压电蜂鸣片频响曲线,实际设计中应按照实际元件对应的频响曲线寻找合适的驱动频率以获得更大分贝的声音输出)。

可以看到该蜂鸣器在4K及5.5K有很好的频响特性。

本设计中使用1K~2KHz频率进行驱动以获得比较好的频响特性。

在检测到相应的键值时,使用以下函数对PA16进行PWM输出

DL_TimerG_setCaptureCompareValue(PWM_2_INST,_1d2f*(100-playvolue)/100, DL_TIMERG_CAPTURE_COMPARE_0_INDEX);  //高音哆 对应音量的占空比
DL_Timer_setLoadValue(PWM_2_INST,_1d2f); //高音哆

在需要关闭PWM输出时也可以使用DL_Timer_stopCounter(PWM_2_INST); 函数进行关闭PWM计数,开启时使用以下函数进行开启即可。

if(!DL_Timer_isRunning(PWM_2_INST))
{
DL_Timer_startCounter(PWM_2_INST);
}

5.LED驱动

由于LED驱动引脚与SPI驱动引脚有复用,因为程序使用了硬件SPI,因此程序只使用LED1~LED4进行档位显示,并且使用LED的闪烁扩展了档位显示的数量(此处参考了洗衣机水量档位显示),4个LED灯可以显示8个档位。

6.实物展示

下图为音量大小91,音量档位8


下图为音量大小8 ,音量档位1 (因为LED闪烁,刚好拍到LED熄灭状态)

7.心得体会

设计中使用了sysconfig对引脚和功能模块进行了配置,sysconfig能有效的对各个功能模块进行配置,但是个人认为也有不足,如对各个功能模块的配置不能单独保存在一个独立的.c 和 .h 文件中,全部保存在了ti_msp_dl_config.h 和ti_msp_dl_config.c文件中,如果需要使用多个功能模块,那么config文件里面必然很复杂,不能很好区分各个模块的配置。还有一个就是sysconfig只能打开一个,不能同时打开多个,用于对比两个工程之间的配置差异,这个在除错调试时还是很有用的。

sysconfig可以对时钟清晰地进行配置,如下图,不仅表明了时钟路径,也在下方明确标明了各个时钟的频率,可以非常清楚的各时钟之间的关系。






附件下载
OLED_SPI.rar
固件程序,可直接编译
团队介绍
硬件工程师,平时主要工作为单片机硬件设计和单片机软件功能开发。
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号