• 【STM32 .Net MF开发板学习12】跳动的音符(PWM合成)


    PWM除了可驱动电机外,还可以设置不同频率以模拟不同音阶的音符输出,实际测试发现,声音还是蛮动听的,不过常见的有源蜂鸣器可不行(红牛开发板自带),需要专门采购无源蜂鸣器,这二者的区别是有源蜂鸣器通电就响,而无源蜂鸣器需要输入一定频率的信号才能发声。

    我们采用Timer3作为PWM的输出源,我们计数固定为为36,占空比也固定为1/2,通过分频系数来设定相对应的PWM输出频率。

    底层代码如下,由于官方无PWM驱动模板,如下函数由我自行定义。

     //采用Timer3 36M PB0输出

     CPU_TIMER_Initialize(timer,36,PSC,Music_ISR,(void *)timer);

     CPU_TIMER_SetCCR(timer,2,param0==0 ? 0:18);

     UINT32 m_Count= param0*param1/1000;

     CPU_TIMER_SetCCM(timer,2,6); //PWM1模式

     CPU_TIMER_PWM_Start(timer,2);

     CPU_TIMER_Start(timer);

    音符频率对应表如下,根据这个,我们通过PWM就可以输出不同音阶的音符:

    音符

    频率/HZ

    半周期/us

    音符

    频率/HZ

    半周期/us

    音符

    频率/HZ

    半周期/us

    1

    262

    1908

    1

    523

    0956

    1

    1046

    0478

    1#

    277

    1805

    1#

    554

    0903

    1#

    1109

    0451

    2

    294

    1700

    2

    578

    0842

    2

    1175

    0426

    2#

    311

    1608

    2#

    622

    0804

    2#

    1245

    0402

    3

    330

    1516

    3

    659

    0759

    3

    1318

    0372

    4

    349

    1433

    4

    698

    0716

    4

    1397

    0358

    4#

    370

    1350

    4#

    740

    0676

    4#

    1480

    0338

    5

    392

    1276

    5

    784

    0638

    5

    1568

    0319

    5#

    415

    1205

    5#

    831

    0602

    5#

    1661

    0292

    6

    440

    1136

    6

    880

    0568

    6

    1760

    0284

    6#

    466

    1072

    6#

    932

    0536

    6#

    1865

    0268

    7

    494

    1012

    7

    988

    0506

    7

    1976

    0253

    "#"表示半音,用于上升或下降半个音,乘以二就提升该声音一个八度音阶,减半则降一个八度。

    考虑到IO的驱动能力,所以添加一个NPN三极管作为放大输出(实际测试,效果不太明显,和直接驱动差别不大),原理图如下:

    相关的实际器件有如下几种:

    实际的物理接线图如下:

    (直接连接和三极管放大连接)

    为了便于应用程序访问,我封装了一个Music库,相关声明如下:

    namespace YFSoft.Hardware

    {

        public sealed class Music

        {

            public static ushort DO1;

            public static ushort DO1x;

            public static ushort DO2;

            

            public static ushort SO3;

            public static ushort SO3x;

     

            public static int Play(ushort[] buff);

            public static int Play(uint addr, uint size);

            public static int Sound(ushort freq, ushort duration);

        }

    }

    Play(uint addr, uint size)函数是播放WAV文件用的,不过目前我还没有调试成功,等成功了在进行相关说明。

    我们以实际的例子,来说明Play(ushort[] buff)和Sound的使用,我们编写一个最简单的曲子,就是两只老虎,其简谱如下:

    对应的编码数据如下:

    //两只老虎

        UInt16[] lzlh = new UInt16[]

        {

            Music.DO2,Music.S1_4,

            Music.RE2,Music.S1_4,

            Music.MI2,Music.S1_4,

            Music.DO2,Music.S1_4,

            Music.P,Music.S1_16,

     

            Music.DO2,Music.S1_4,

            Music.RE2,Music.S1_4,

            Music.MI2,Music.S1_4,

            Music.DO2,Music.S1_4,

            Music.P,Music.S1_16,

           

            Music.MI2,Music.S1_4,

            Music.FA2,Music.S1_4,

            Music.SO2,Music.S1_2,

            Music.P,Music.S1_16,

     

            Music.MI2,Music.S1_4,

            Music.FA2,Music.S1_4,

            Music.SO2,Music.S1_2,

            Music.P,Music.S1_16,

     

            Music.SO2,Music.S1_8,

            Music.LA2,Music.S1_8,

            Music.SO2,Music.S1_8,

            Music.FA2,Music.S1_8,

            Music.MI2,Music.S1_4,

            Music.DO2,Music.S1_4,

            Music.P,Music.S1_16,

           

            Music.SO2,Music.S1_8,

            Music.LA2,Music.S1_8,

            Music.SO2,Music.S1_8,

            Music.FA2,Music.S1_8,

            Music.MI2,Music.S1_4,

            Music.DO2,Music.S1_4,

            Music.P,Music.S1_16,

     

            Music.DO2,Music.S1_4,

            Music.SO1,Music.S1_4,

            Music.DO2,Music.S1_2,

            Music.P,Music.S1_16,

     

            Music.DO2,Music.S1_4,

            Music.SO1,Music.S1_4,

            Music.DO2,Music.S1_2,

            Music.P,Music.S1_16,

        };

    数据成对出现,第一个是音符,第二是节拍的长度。

    好了,让我们播放一下,播放代码如下,很简单,就一句。

     Music.Play(lzlh);   //音乐播放

    再来看看Sound函数的使用,参数很简单,第一个是发声频率,第二个是持续时间,示例如下:

            //播放单个音符

            Music.Sound(Music.DO1, 1000);

            Music.Sound(Music.RE1, 1000);

            Music.Sound(Music.MI1, 1000);

            Music.Sound(Music.FA1, 1000);

            Music.Sound(Music.SO1, 1000);

            Music.Sound(Music.LA1, 1000);

         Music.Sound(Music.SI1, 1000);

     OK,有兴趣,并且对谱子有研究的网友,可以多编码一些好听的曲子,记得到时候一定与我们分享一下。

       注:该示例程序,红牛开发板需要部署最新的V0.9.8固件。

        文章相关器件:http://item.taobao.com/auction/item_detail.htm?item_num_id=7135239572

     

    【低价开发板】http://item.taobao.com/item.htm?id=7117999726

    源码下载:http://www.sky-walker.com.cn/yefan/MFV40/SourceCode/SoundTest.rar

    文章参考: .Net Micro Framework 快速入门

    中文讨论组:http://space.cnblogs.com/group/MFSoft/
  • 相关阅读:
    使用protobuf生成代码import包找不到
    SQL 对邮箱数据的处理(分类统计)
    Hive 集合函数 collect_set() collect_list()
    菜谱分享网站微信小程序开发说明(1)-介绍与运行
    windows 下查看端口占用
    Windows下安装Maven自定义仓库配置阿里下载源,配置Ecplise、IDEA
    Windows下安装Node.js完整详细教程
    开启Centos8的SSH服务
    Openwrt与IPTV之二----udpxy
    Openwrt与IPTV之一----igmpproxy
  • 原文地址:https://www.cnblogs.com/yefanqiu/p/1802929.html
Copyright © 2020-2023  润新知