zl程序教程

您现在的位置是:首页 >  大数据

当前栏目

51单片机升国旗项目的简单分析,以及涉及到的模块配置与使用

配置项目模块单片机 分析 简单 以及 51
2023-09-11 14:19:59 时间

前言:

这几天我在研究在单片机进行其他工作的时候去播放一些音乐,比如在步进电机转动的时候去播放蜂鸣器的电子音乐,这样岂不是一举两得。但是,后来时间我发现一个问题。就是无源蜂鸣器对时序的要求是比较严格的。或者说蜂鸣器就是根据发音频率的不同,来区别不同的音色。

​ 在设计函数的时候中断函数的任务就是要使某一个特定的音色延时一段时间后再进行改变(取决于乐谱)在这个过程中,你可以认为蜂鸣器是一直保持在上一个音的频率震动的。所以,如果想将主函数中调节音色与时长的函数放到中断函数中去,那么导致的结果是,蜂鸣器从原来的在延时时间内一直震动,到现在延时过后震动一次。或者说翻转一次电平口。

​ 所以说,如果要混合进入一些占用时序比较长的子涵数,难免会使这个延时的时间增大。作为补偿的方法,很简单的一种就是减小延时,即将调用子涵数所用的时间补偿给蜂鸣器。但是这种方法的缺点也会很明显。就是你不能够对子涵数进行控制,子涵数必须是在while循环中一直执行的。因为如果我们加以控制的话,那么会出现在调用函数的时候,蜂鸣器的延时有补偿。经过不断调节,计算可以和之前一样,如果不调用子涵数的话,蜂鸣器就没有延时补偿,相当于放音速度加快。不过对于要求不高的应用这种方式还是比较高效的。

​ 运用这种补偿延时方法还有一种问题,就是子涵数用的时间太长怎么办,这里仅拿我们之前的步进电机的顺时针函数为例,很显然这个函数的本质就是switch——case里面的所有语句按照一定的速度不断循环。所以你不妨将引入的参数nangle设置小一点,然后在主函数中whiile循环调用MotorRun(,,,),这样是不是也是起到了连续调用的目的。

/*
angle:转动角度(nangle为4096时为转动一圈)
drct:逆时针:1、顺时针:0
speed:速度
*/
void MotorRun(unsigned int nangle, drct, speed)             
{
    uint step;
    step=0;
    if(drct==0)
    {
        while(nangle--)
        {
            switch(step)//
            {
                case 0:MA=1;MB=0;MC=0;MD=0;break;
                case 1:MA=1;MB=1;MC=0;MD=0;break;
                case 2:MA=0;MB=1;MC=0;MD=0;break;
                case 3:MA=0;MB=1;MC=1;MD=0;break;
                case 4:MA=0;MB=0;MC=1;MD=0;break;
                case 5:MA=0;MB=0;MC=1;MD=1;break;
                case 6:MA=0;MB=0;MC=0;MD=1;break;
                case 7:MA=1;MB=0;MC=0;MD=1;break;
            }
            if(step==7)step=0;
            else step++;
            delay(speed);       
        }
    }

直接写在蜂鸣器那个project的while里面,实验的时候如果SPEED不设置为0的话,那么就会延时是吧,在延时的时候,MotorRun(50,0,50); 是不会被调用的。所以现象就是电机一卡一卡的,每次转动的就是50/4096度。

如果你有强迫症,希望电机丝滑运转,那么你可以将SPEED设置为0,然后MotorRun中的nangle设置大一点,这需要你的不断调试,将MotorRun的调用时间全部补偿为延时。每一首歌曲的节拍都不一样,需要的延时时间也不同。自己多调试几遍就好。

但是用步进电机做的项目,不仅仅要让电机转动,还需要计算时间与步进电机的转速,达到规定时间转动指定圈数的目的。所以这里MotorRun的speed参数是用来控制步进电机的速度的,然后调节nangle来实现一定的延时,确保音乐的时序正确。

while(1)
	{	
	    MotorRun(50,0,50); 
		if(Music[MusicSelect]!=0xFF)	//如果不是停止标志位
		{
			FreqSelect=Music[MusicSelect];	//选择音符对应的频率
			MusicSelect++;

			Delay(SPEED/4*Music[MusicSelect]);	//选择音符对应的时长
			MusicSelect++;

			TR0=0;//不同音符间短暂停顿,利用延时开关定时器实现
			Delay(5);	
			TR0=1;
		}
		else	//如果是停止标志位
		{
			TR0=0;  //关闭定时器
			while(1);
		}

其次:

然后简单说一下吧,如果最求上手简单,那么上面这个方案应该是我能想到板载最好的一边播放音乐,一边控制步进电机的方法。

但是其实最开始我想的没有这个好,我想的是既然蜂鸣器的中断比较频繁,那么能不能将

MotorRun函数也封装到定时器中断服务函数呢, delay(speed); 就是每次中断触发的间隔。然后配置好后的问题也就是MotorRun的这个中断也比较频繁,所以两者一起工作的时候,可能会出现蜂鸣器拖音的情况,这也是因为步进电机的中断加长了延时,同样的可以通过减少延时来减弱这种情况,但是加速的音乐可能会听着怪怪的。

不过这套方案也不是一无是处,在满足基本的要求的情况下优点可能就是可以控制定时器的开关来控制两者的工作开始与否。

最后:

我想到的是外接喇叭,将音乐播放模块与单片机的工作独立开来,不占用单片机进程。这样之前单片机上面的LCD显示屏,红外遥控(对时序要求更加严格),蓝牙模块,就有机会延伸上去。

简单的检索了一些资料以后,大概有两类模块是符合我们这个项目的要求的:

1,就是那种录音模块

2,其次是MP3文件的解码模块(亦可以叫做语音模块)

录音模块我入手的是ISD1820,优点就是操作十分简单,IO口触发也比较好理解,缺点可能是录音的质量不高,其次录音的时长不够(10s)。所以这个还是比较适合接一个功放在菜市场循环播放录音

对于语音模块的话,我选的是JQ8900-16P,也是看了很多,最主要的是对新手而言功能丰富,然后操作比较简单吧。

项目可能用到的模块文章:
当然你也可以加上红外遥控与LCD液晶屏来显示,查阅我的往期文章有相关资料,这里就不给出链接了

语音识别模块的使用
蜂鸣器的使用
步进电机的使用