找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1334|回复: 0
打印 上一主题 下一主题
收起左侧

单片机八音盒例程分享-基于stc32g12k128的硬件spwm乐音产生应用实例

[复制链接]
跳转到指定楼层
楼主
   在调试装置时需要一个稳定的声音源,想到之前买的有不少stc的MCU芯片,可以用它来产生几个声音信号。于是写了这个程序。
   八音盒能产生七个不同的乐音,而音乐就是由这些基本乐音组合构成(有点脸红)。所以本例程就是个基于MCU的乐音产生程序。
   用MCU产生一个乐音本身很简单,比如要产生一个110HZ的乐音,只要用MCU生成一个频率为110HZ的PWM方波,然后输出电路上加个一阶低通滤波器,驱动喇叭就听到声音了。
   但当我们需要产生多个乐音时,就遇到一个问题,不同乐音的频率不同,需要的滤波器的参数就不一样,只用一个滤波器时,频率高的乐音会受到较大的衰减。结果低音很强,高音听不见了。
   当然可以用七个不同的低通滤波器,应对七个频率,用一个cd4051进行选择,mcu输出不同频度时,控制cd4051接通不同的滤波器。不过这样硬件就多了几样。而且无法适应更多的频率。
   常用解决办法是采用一个高频率的载波,然后把需要产生的声音频率信号调制到载波上。这样就节省了滤波器。这就是spwm波。它是一个脉冲宽度按正弦规律变化的PWM波。下面给出一个实现方法。
        stc32g12k128具有硬件pwm功能。只要做好设置,它能自动产生符合设置频率和脉宽的PWM波,不需要占用MCU时间。我们只要合理控制它的脉宽变化,就能得到需要的SPWM波了。所以程序简单稳定。精度也很高。
   我选择系统主频用24MHZ,载波频率为55*512=28160HZ。55为参考频率,512为对应该频率时正弦波表的点数。因为人耳可闻声频率上限20KHZ,所以这个频率不会对乐音产生干扰,同时它又能保证每个周期对应一个波点数据。最大限度的保证产生的声音的精度。对其它频率的乐音,载波频率不变,只改变正弦波表的点数。始终保证系统在最大精度上运行。该载波频率对应的周期设置值为:24000000/28161=852=0x0354
         STC官方技术手册上有现成的产生spwm波的例程。就直接套用了,包括pwm设置和pwm中断服务。本例程主要是解决正统波表的生成,管理,使用。乐谱表的建立和使用。乐曲的播放管理。
   对spwm波来讲,每个频率的正弦波都需要一组正统波表数据,建立正统波表时,我使用了软件
          Spwm_calc.exe
   它的界面如图所示。中值采用420,幅值415,调制度0.98,在55HZ时的点数512.其它频率的点数值通过计算获得。产生了七组数据存放在头文件sin_table1.h里,每组数据的第一个数放的是本组数据的个数(也就是使用的点数)。第二个开始才是正弦波表的数据。也就是说。读波表数据要从第二个开始读。这是为了编程序简单方便。
   系统设置了三个数组,一个是正弦波表,放在头文件里。第二个是波表索引数组u16 *sin_table_index[],存放正弦波表的数据的地址,它是乐谱与正弦波表的过渡。第三个是乐谱
u8 music_score[33][3]。
   乐谱表中一组数据有三个,第一个是音符名,程序根据它通过索引数组读取对应正弦波表。第二个是音组名。1是最低音,2是低音,3是中音4是高音,5是最高音。这个数据决定从波表中读取数据的数量,数据越少音频越高。比如读512个是最低音的6la),那么读256个就是低音的6la,高了八度。频率高一倍。以此类推。这样七组波表数据可用以播放几十个乐音。第三个是音长(乐音的持续时间)。本例程只设置了三个数值,1是全音,2是半音,4 4分音。仅用来展示一下音长管理的方法。想多加几个音长设置很容易。
   例程使用了四个中断服务:
         PWMA中断,基本照抄官方例程,用来产生spwm波。不同的是这里输出的正弦波频率不是固定的。所以读波表时不能用固定首地址。而是用了一个变量*p存放正弦波表首地址值,方便切换频率。
   外中断int0控制程序运行,主要是把等待切换为运行。如果不用这个中断。可以让程序开机后就自动循环播放。在中断服务程序中。控制变量CC的值,从而影响主程序里语句
While(cc);的运行。
   在调试时发现中断服务里改变cc值后,主程序里的while语句没有响应。接上stc-link1d仿真器后观察到,中断发生后cc值确实发生了变化,但while语句不理会,没有如预期的那样跳出死循环。把这个现象放到群里咨询时,有高人指出。这是由于keil编译不合理所致,解决的办法是声名变量CC时加一个限制符volatile。试了一下,果然解决了问题。
   中断T1是避免按键振动产生干扰的延时。这两个都不重要,可以不用。
   中断T0是核心,它控制一个乐音的播放时间,同时设定播放所需要的所有参数。各语句的作用在程序里做了注明。
void t0_sever() interrupt 1//确定一个音符的输出参数,包括乐音的持续时间,音高数据的地址,数据量,读取参数
{
read_music_long(cnt);//读当前音符的播放时间,并设定对应的延时
        pp2=music_score[cnt][1];//读取本音符的音组值,以确定读波表数据时的偏移量
        pp3=pow(2,pp2);//计算本音符数据偏移量,在式中给pp2加整数能成倍提高输出频率
pp0=*sin_table_index[music_score[cnt][0]-1];///pp2;//读取本音符的数据量
pp1=(sin_table_index[music_score[cnt][0]-1]+1);//取本音符数据指针初值
        p=pp1;//赋正弦数据指针初值
        cnt++;//准备读下一个数据
        if(cnt>33)//乐谱播放完成,这里的33是根据乐谱数据的参数设定的。如果改变乐谱数据量,这里要做对应变化,用小了不能完整播放,用大了会出错
        {
        cc=0;//播放结束
        ET0=0;//关中断
        PWMA_IER = 0x00; //关中断
            PWMA_ENO = 0x00;//关闭PWM输出

        }
}
   音长子程序里有三个软件定时程序,是直接使用stc官方的软件延时工具产生的。全音用了一秒,半音0.5秒,四分音用0.25秒。
乐音播放所需要的控制参数都是在这个中断服务里确定的。PWM中断服务则负责按参数进行输出。
   本例程的主程序很简单,包括系统设置和播放管理两项。直接列出来吧:
void main(void)
{
        mcu_initial();//mcu设置程序
        //打开播放程序,播放完成后重新进入等待
    while(1)//这个是重入语句
    {

                cc=1;//等待状态,由中断int0改变,如果屏蔽这个语句则程序自动重复播放乐曲
                while(cc);
                                //初始化播放指针并开始播放
                                cnt=0;//把播放计数复位到开始位置
                                ET0=1;
                TR0 = 1;                                //定时器0开始计时
PWMA_IER = 0x01; //使能中断
    PWMA_ENO |= 0x01; //使能输出
    PWMA_ENO |= 0x02; //使能输出

                        cc=1;
                                while(cc);//等待播放完成,由T0中断服务程序控制这里的CC值
    }
}
  为听到产生的声音,我使用了唯创的PWM功率放大模块WT1312,它能把spwm信号变成推动喇叭的正弦信号并直接推动喇叭发声。其电路如图所示:把mcu的spwm输出端直接连上功放芯片的PWM输入端就行了。因电流较大。芯片电源单独接了一个4.2/3.7V锂电池。二者不需要共地。功放的输入阻抗是100K,对MCU输出要求很低。它的体积很小,又只用了一个电容,所以我直接用sop23-10/dip10转接板当功放板了。接好的板子如图。MCU部分电路没有特殊要求,使用最小系统板就行,我在实验中用了stc32g12k128的降龙棍系统板。音频测试视频体积太大没法传上来。因为测试电路和这个八音盒程序都没使用晶振,所以会有些误差。效果整体还是很不错的。完整的程序见附件,欢迎大家批评指正。



spwm_1.zip

98.54 KB, 下载次数: 21, 下载积分: 黑币 -5

Keil代码下载

评分

参与人数 2黑币 +65 收起 理由
lkc8210 + 15 绝世好帖!
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶1 踩
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表