STC learning: ABC English songs with synchronized lyrics

Description of program design objectives and program operation effects
Program design goal: by pressing the key key1 to control the music playback and the lyrics display of the nixie tube.
Description of program operation effect: press the key key1 to play the music I can say ABC and display the lyrics; Press key1 again to pause playing music.

Program related circuit and principle description
1. Principle description
This experimental board adopts a passive buzzer. Compared with the active buzzer, the advantage of the passive buzzer is that it is cheap and can change the sound by controlling its vibration frequency. Therefore, the passive buzzer can be used for music playing. The advantage of active buzzer is that it is simple to use and does not need to write "music score". The passive buzzer used in this experimental board is an electromagnetic buzzer, which is composed of oscillator, electromagnetic coil, magnet, vibrating diaphragm and shell. After the power is turned on, the received audio signal current passes through the solenoid to generate a magnetic field. The vibrating diaphragm vibrates and sounds periodically under the interaction of electromagnetic coil and magnet.

In this program, the array music [] is the music to be played. The format is note, beat, note, beat, and so on. The note is the tone to be emitted, and the beat is the duration of the sound. As shown in the figure, in the array music [], the format of note representation is: ten bits represent low octave, medium octave or high octave, 1 represents high octave, 2 represents medium octave, 3 represents high octave, and one bit represents simple music notes. For example, 0x15 represents S0 of low octave, 5S0 of low octave as shown in the figure, and 0x21 represents DO of medium octave, d0 of medium octave as shown in the figure. Among the notes, 0x00 represents the ending symbol, which means that the whole song has been sung, while 0xff represents the stop symbol, which means to stop for 100ms. In both cases, you should re execute the first step in the loop. The rest is played normally. After the program is burned into the MCU, you need to press the key key1 to play. Compared with the basic article, the lyrics nixie tube synchronous display function is added.

Note: because the use of nixie tube to display lyrics is really reluctant, some letters are difficult to display on the nixie tube, such as "M", The main learning focus of this experiment is on the synchronous display of lyrics and the digital arrangement of songs (i.e. from simplified music to music code). The corresponding symbol table (A-Z) of ABC English song letter nixie tube display has been made into another document. See the document "ABC English song letter nixie tube display corresponding symbol table (A-Z)".

2. Program related circuits
(1) Circuit schematic diagram of passive buzzer

(2) Key control circuit

Chip related pins: Beep -- P3^4;

The code is as follows:

#include "STC15F2K60S2.H"
#define uint unsigned int 				  // Macro definition
#define uchar unsigned char
sbit led_sel=P2^3;						 //Nixie tube and led strobe pin
sbit sel0=P2^0;							 //SEL0, SEL1 and SEL2 are combined as bit selection information, 0-7
sbit sel1=P2^1;
sbit sel2=P2^2;
sbit beep=P3^4;			 				 //Buzzer pin
sbit key1=P3^2;						     //Define key 1
sbit key2=P3^3;							 //Define key 2
uchar timeh,timel;		  //Defines the reload value of the timer
uchar flag;				  //Selected lit nixie tube 0-7 flag bits	
bit zanting;		  	  //Play or pause flag bit
uchar jindu=0;    	 	  //The position pointed to in the music array
uchar geci[]={0x77,0x7f,0x39,0x00,0x6f,0x7b};					 //Display the nixie tube segment code of the startup screen
uchar geci1[]={0x77,0x7f,0x39,0x3f,0x79,0x71,0x3d,0x40};    	 //Display the digital segment code ABCDEFG of A-G-
uchar geci2[]={0x76,0x06,0x1e,0xf6,0x38,0x4f,0x37,0x40};    	//Display H-N nixie tube segment code HIJKLMN-
uchar geci3[]={0x3f,0x73,0xbf,0x40,0xf7,0x6d,0x07,0x40};		//Display the digital segment code OPQ-RST of O-T-
uchar geci4[]={0x62,0x3e,0xf9,0x40,0xf6,0xe6,0xdb,0x40};		//Displays the U-Z segment code UVW-XYZ-
uchar geci5[]={0xf6,0xe6,0xdb,0x80,0x37,0x3f,0xf9,0x00}; 		 //XYZ,Now 	
uchar geci51[]={0xe6,0x3f,0x62,0x00,0x6d,0x79,0x79,0x00}; 	  	//you see
uchar geci6[]={0x0f,0x39,0x77,0x37,0x00,0x6d,0x77,0xe6}; 		 //I can say  
uchar geci61[]={0x77,0x7f,0x39,0x00,0x00,0x00,0x00,0x00};		 // ABC
uchar weixuan[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};		//Bit selection code
uchar code music[] ={    //Music code, the song is "I can say ABC", the format is: note, beat, note, beat,    
0x11,0x10,0x21,0x10,	 //The ten digits of notes represent low octave, medium octave or high octave, 1 represents low octave, 2 represents medium octave and 3 represents high octave
0x25,0x10,0x25,0x10,	 //A bit represents a note of simplified music. For example, 0x15 represents S0 of low octave and 0x21 represents DO of medium octave.
0x26,0x10,0x26,0x10,	 //The beat represents the sound length, for example, 0x10 represents one beat, 0x20 represents two beats, and 0x05 represents 1 / 2 beat
0x25,0x10,0x25,0x10,  //16
0x24,0x10,0x14,0x10,
0x23,0x10,0x13,0x10,
0x22,0x10,0x22,0x10,
0x21,0x10,0x21,0x10,  //32
0x25,0x10,0x25,0x10,
0x24,0x10,0x24,0x20,
0x23,0x10,0x23,0x10,
0x22,0x10,0x22,0x10,  //48
0x25,0x10,0x25,0x10,
0x24,0x10,0x24,0x20,
0x23,0x10,0x23,0x10,  
0x22,0x10,0x22,0x10,  //64
0x21,0x10,0x21,0x10,
0x25,0x10,0x25,0x10,  //72
0x26,0x10,0x26,0x10,
0x25,0x10,0x25,0x10,  //80
0x24,0x10,0x24,0x10,
0x23,0x10,0x23,0x10,  //88
0x22,0x10,0x22,0x10,
0x21,0x10,0x21,0x20,  //96
0x00,0x00
};
uchar code quzi[] ={	  //This array data is the reload value of each note in the timer. The first column is high and the second column is low
0xf8,0x8c,	  //Low octave, low 1
0xf9,0x5b,	  
0xfa,0x15,	  //Low 3
0xfa,0x67,
0xfb,0x04,	  //Low 5
0xfb,0x90,
0xfc,0x0c,	  //Low 7	
0xfc,0x44,	  //Central C key
0xfc,0xac,	  //Medium 2
0xfd,0x09,
0xfd,0x34,	  //Medium 4
0xfd,0x82,					   
0xfd,0xc8,	  //Medium 6
0xfe,0x06,
0xfe,0x22,	  //High octave, high 1	
0xfe,0x56,
0xfe,0x6e,	  //High 3
0xfe,0x9a,
0xfe,0xc1,	  //High 5
0xfe,0xe4,
0xff,0x03	  //High 7
};
void delay(unsigned int xms)
{
	uint i,j;						   
	 for(i=xms;i>0;i--)
	 	for(j=124;j>0;j--);
}
//Function Description: in the quzi array, find the reload value of the simplified musical note defined by the music array, and return its position in the quzi array
//Entry parameter: simplified musical notes defined in tem: music array
//Exit parameter: returns the position value of tem note in quzi array
uchar quyin(uchar tem)
{
	uchar qudiao,jp,weizhi;		  //Define tunes, notes and positions
	qudiao=tem/16;				  //The upper 4 digits are the tune value
	jp=tem%16;					  //The lower four are notes
	if(qudiao==1)				  //When the tune value is 1, it is the low octave, and the base address of the low octave in the quzi array is 0
		qudiao=0;
	else if(qudiao==2)			  //When the tune value is 2, it is the middle octave, and the base address of the middle octave in the quzi array is 14
		qudiao=14;
	else if(qudiao==3)			  //When the tune value is 3, it is the high octave. The high octave is in the quzi array, and the base address is 28
		qudiao=28;
	weizhi=qudiao+(jp-1)*2;		  //By adding a note to the base address as an offset, the position of the note in the quzi array can be located
	return weizhi;				  //Returns this location value
}
void playmusic()//Play music
{
	uchar p,m,tem;   //m is the beat   
	while(1)   
	{   
		if(zanting==1)			//Play or pause control
		{
			p=music[jindu];
			if(p==0x00)			//If you encounter an end character, delay 1 second, return to the beginning and do it again 
			{
				jindu=0;
				delay(1000);
				break;
			}        
			else if(p==0xff)   //If you encounter a pause, delay 100ms and continue to take the next note
			{
				jindu++;			
				delay(100);
				TR0=0;			//Off timer 0
				break;
			}      
			else			   //Normally take notes and beats 
			{
				tem=quyin(music[jindu]);		//Gets the position value of the current note in the quzi array
				timeh=quzi[tem];			//Reload the timer corresponding to the note to timeh and timel
				timel=quzi[tem+1];
				jindu++;
				TH0=timeh;					//Assign timeh and timer to the timer
				TL0=timel;
				m=music[jindu];					 //Get beat
				jindu++;
			}  		   
	        TR0=1;                    //On timer 0    
			delay(m*180);             //Wait for the beat to complete and output audio through port P3^4    
			TR0=0;                    //Off timer 0   
			beep=0;	 					 //Set beep to 0 to protect the buzzer		
		  }
	}
}
//The function of system initialization is to configure the IO port
void init_sys()
{
	P0M0=0xff;			 		//Set push-pull mode
	P0M1=0x00;
	P2M0=0x08;
	P2M1=0x00;
	P3M0=0x10;
	P3M1=0x00;
}
//timer initiated 
void init()						  
{
	TMOD=0x01;					 //Set timer 0, working mode 1, 16 bit manual reset initial value; Set timer 1, working mode 0, 16 bit automatic reset initial value
	TH0=0xD8;					 //Set initial value of timer 0
	TL0=0xEF;
	TH1=(65536-1000)/256;		 //Set initial value of timer 1
	TL1=(65536-1000)%256;
	EA=1;						 //Open total interrupt
	ET0=1;						 //Open timer 0 interrupt
	ET1=1;						 //Open timer 1 interrupt
	TR0=0;						 //Timer 0 is not started temporarily
	TR1=1;						 //Start timer 1	
	EX0=1;						 //Start external interrupt 0						 
	zanting=0;					 //Initial value of play or pause flag bit
	beep=0;	 					 //Set beep to 0 to protect the buzzer
}
void main()
{
	init_sys();							  //System initialization
	init();
	P0=0x00;							  
	key1=1;
	flag=0;
	while(1)
		playmusic();			 //Enter play music function
}
//Timer 0 interrupts processing, reloads the value, reverses the beep value, and generates a square wave
void tim1()interrupt 1						//Timer control frequency
{
	TH0=timeh;								//Reset initial value after interruption
	TL0=timel;
	beep=~beep;							//Interrupt beep flip to generate square wave, making the buzzer sound
}
//Press the external interrupt of key 1, reverse the flag bit, and the function is to pause and play music
void exint0()interrupt 0
{
	if(key1==0)
	{		
		delay(10);
		if(key1==0)
			zanting=~zanting;
	}
}				
//Timer 1 interrupt processing, used as nixie tube to display lyrics.
void timer1()interrupt 3				   //Refer the display program to timer 1 interrupt service program
{
	flag++;
	if(flag==8)
		flag=0;
	P0=0;
	P2=weixuan[flag];
	if(jindu==0)						 //By judging the jindu during playback, the lyrics display at this time can be controlled
	{									 //When this is zero, "ABC ge" is displayed
		switch(flag)
		{
			case 0:P0=geci[0];break;
			case 1:P0=geci[1];break;
			case 2:P0=geci[2];break;
			case 4:P0=geci[4];break;
			case 5:P0=geci[5];break;
			default:P0=geci[3];break;
		}
	}
	else if(jindu<16)
	{					 //At this time, the progress is between 0-15, and "ABCDEFG -" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci1[0];break;
	       case 1:P0=geci1[1];break;
		   case 2:P0=geci1[2];break;
		   case 3:P0=geci1[3];break;
		   case 4:P0=geci1[4];break;
		   case 5:P0=geci1[5];break;
		   case 6:P0=geci1[6];break;
		   default:P0=geci1[7];break;
	   }
	}
	else if(jindu<32)
	{					  //At this time, the progress is between 16-31, and "HIJKLMN -" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci2[0];break; 
	       case 1:P0=geci2[1];break; 
		   case 2:P0=geci2[2];break; 
		   case 3:P0=geci2[3];break; 
		   case 4:P0=geci2[4];break; 
		   case 5:P0=geci2[5];break; 
		   case 6:P0=geci2[6];break; 
		   default:P0=geci2[7];break; 
	   }
	}
	else if(jindu<48)
	{					  //At this time, the progress is between 32-47, and "OPQ- RST -" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci3[0];break; 
	       case 1:P0=geci3[1];break; 
		   case 2:P0=geci3[2];break;
		   case 3:P0=geci3[3];break;
		   case 4:P0=geci3[4];break;
		   case 5:P0=geci3[5];break;
		   case 6:P0=geci3[6];break;
		   default:P0=geci3[7];break;
	   }
	}
	else if(jindu<64)
	{					  //At this time, the progress is between 48-63, and "UVW- XYZ -" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci4[0];break; 
	       case 1:P0=geci4[1];break; 
		   case 2:P0=geci4[2];break; 
		   case 3:P0=geci4[3];break; 
		   case 4:P0=geci4[4];break; 
		   case 5:P0=geci4[5];break; 
		   case 6:P0=geci4[6];break; 
		   default:P0=geci4[7];break; 
	   }
	}
	else if(jindu<72)
	{					 //At this time, the progress is between 64-71, and "XYZ- NOW" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci5[0];break;
	       case 1:P0=geci5[1];break;
		   case 2:P0=geci5[2];break;
		   case 3:P0=geci5[3];break;
		   case 4:P0=geci5[4];break;
		   case 5:P0=geci5[5];break;
		   case 6:P0=geci5[6];break;
		   default:P0=geci5[7];break;
	   }
	}
	else if(jindu<80)
	{					//At this time, the progress is between 72-79, and "YOU SEE" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci51[0];break; 
	       case 1:P0=geci51[1];break; 
		   case 2:P0=geci51[2];break; 
		   case 3:P0=geci51[3];break; 
		   case 4:P0=geci51[4];break; 
		   case 5:P0=geci51[5];break; 
		   case 6:P0=geci51[6];break; 
		   default:P0=geci51[7];break; 
	   }
	}
	else if(jindu<88)
	{					//At this time, the progress is between 80-87, and "ICAN SAY" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci6[0];break;
	       case 1:P0=geci6[1];break;
		   case 2:P0=geci6[2];break;
		   case 3:P0=geci6[3];break;
		   case 4:P0=geci6[4];break;
		   case 5:P0=geci6[5];break;
		   case 6:P0=geci6[6];break;
		   default:P0=geci6[7];break;
	   }
	}
	else if(jindu<96)
	{					//At this time, the progress is between 88-95, and "ABC" is displayed
	   switch(flag)
	   {
		   case 0:P0=geci61[0];break; 
	       case 1:P0=geci61[1];break; 
		   case 2:P0=geci61[2];break; 
		   case 3:P0=geci61[3];break; 
		   case 4:P0=geci61[4];break; 
		   case 5:P0=geci61[5];break; 
		   case 6:P0=geci61[6];break; 
		   default:P0=geci61[7];break; 
	   }
	}
}

Keywords: Single-Chip Microcomputer IoT STC

Added by ki on Tue, 21 Dec 2021 00:51:32 +0200