896|1

504

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

【瑞萨电子200MHz Cortex-M33 RA6E2评估板】PWM播放音频 [复制链接]

WeChat_20231023233924

 

前言

前面我们实现了PWM的输出,可以设置指定的占空比和频率。基于此我们可以实现PWM播放音频。

PWM播放音频有两种方式

一种是PWM输出不同频率对应不同音调,类似于MIDI音。这种相对对于PWM更新频率要求低,一个音在一个演奏时间内不变。

基本原理如下:

频率-对应音调

占空比-对应响度

PWM输出时长-对应演奏时长

另外一种方式即PWM-DAC方式,PWM输出不同占空比表示不同的DAC输出值,这种需要较高的PWM更新频率。

我们现在来使用前者实现音乐播放。

 

准备

我们需要先将乐谱转化为PWM的频率和占空比以及演奏时长的参数。

以国际标准音A-la-440HZ为准:

do的频率为261.6HZ,

re的频率为293.6HZ,

mi的频率为329.6HZ,

fa的频率为349.2HZ,

sol的频率为392HZ,

la的频率为440HZ,

si的频率为493.8HZ。

我们以”两只老虎为例”

 

先看左上角的节拍说明:2/4拍子  4分音符一拍 每小节2拍

一分钟76拍。

 

先定义如下音阶和频率的对应关系

 

#define DO  523
#define RE  587
#define MI  659
#define FA  698
#define _SO 392
#define SO  784
#define LA  880
#define SI  987
#define NO  523
#define DUTY0  0

 

我们可以看到如果主频是100MHz则最大16位65535分频,最低频率只能到

 1525HZ,所以需要降低主时钟源频率,我们改为64分频

相应的如下函数也要修改

 

void pwm_set_frq_period(uint32_t duty, uint32_t frq)
{
	uint32_t period = (uint64_t)(100000000ul/64)/frq;
	duty = ((uint64_t)duty*period*2+100)/200;
	set_intensity(duty, period, TIMER_PIN);
}

 

 

定义节拍时间

#define METERS  76ul             // 拍数76 1分钟76拍 每拍60/76秒 2/4  4分音符一拍 每小节2拍
#define NOTE_4  (60000ul/METERS)  // 先定一拍对应的音符 4分音符  x1000转化为单位mS
#define NOTE_8  (NOTE_4/2ul)     // 8分音符 一个下划线
#define NOTE_16  (NOTE_8/2ul)    // 16分音符 二个下划线

定义音阶表,对应频率

const uint16_t beepfrep[] =
{
	DO,RE,MI,DO,
	DO,RE,MI,DO,
	MI,FA,SO,NO,
	MI,FA,SO,NO,
	SO,LA,SO,FA,MI,DO,
	SO,LA,SO,FA,MI,DO,
	DO,_SO,DO,NO,
	DO,_SO,DO,NO
};

定义声音大小表,对应占空比

const uint16_t beepduty[] =
{
	40,40,40,40,
	40,40,40,40,
	40,40,40,DUTY0,
	40,40,40,DUTY0,
	40,40,40,40,40,40,
	40,40,40,40,40,40,
	40,40,40,DUTY0,
	40,40,40,DUTY0,
};

定义节拍表,对应每个音阶的演奏时间

const uint32_t beeptime[]=

{
	NOTE_8,NOTE_8,NOTE_8,NOTE_8,
	NOTE_8,NOTE_8,NOTE_8,NOTE_8,
	NOTE_8,NOTE_8,NOTE_8,NOTE_8,
	NOTE_8,NOTE_8,NOTE_8,NOTE_8,
	NOTE_16,NOTE_16,NOTE_16,NOTE_16,NOTE_8,NOTE_8,
	NOTE_16,NOTE_16,NOTE_16,NOTE_16,NOTE_8,NOTE_8,
	NOTE_8,NOTE_8,NOTE_8,NOTE_16,
	NOTE_8,NOTE_8,NOTE_8,NOTE_16,
};

 

实现延时函数,单位mS

void mdelay(uint32_t t)
{
	R_BSP_SoftwareDelay(t,BSP_DELAY_UNITS_MILLISECONDS);
}

 

实现演奏函数

 

extern void pwm_set_frq_period(uint32_t duty, uint32_t frq);
void beep_play_music(const uint16_t* freq,const uint16_t* duty, const uint32_t* time, uint16_t len)
{
	uint16_t i = 0;
	for(i=0; i< len; i++)
	{
			pwm_set_frq_period(duty[i],freq[i]);
			mdelay(time[i]);
	}
}

 

测试

添加测试函数

void pwm_audio_test(void)
{
	beep_play_music(beepfrep, beepduty, beeptime, sizeof(beepfrep)/sizeof(beepfrep[0]));
}

 

shell_func.c中添加命令行

  { (const uint8_t*)"pwmaudio",         PwmaudioFun,         "pwmaudio"},

void pwm_audio_test(void);

void PwmaudioFun(unsigned char* param)

{

(void)param;

pwm_audio_test();

}

 

shell_func.h中添加申明

void PwmaudioFun(unsigned char* param);

 

可以看到添加的命令如下

 

 

 

接上蜂鸣器测试效果详见视频

 

 

总结

  1. 可以添加更多的二乐谱实现不同音乐播放。
  2. 还可以将上述阻塞延时改为定时中断处理,这样非阻塞更方便使用。

最新回复

厉害  详情 回复 发表于 2023-11-2 16:58
点赞 关注

回复
举报

3

帖子

0

TA的资源

一粒金砂(初级)

沙发
 

厉害


 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表