(Study Diary) 2023.4.22

Written in front:
Due to the lack of time and the fragmentation of learning, blogging has become a bit of a luxury.
But the desire to record learning (forgetting to be able to quickly review it later) grows stronger by the day.
In this case
, it is better to take the day as the unit and the time as the order, just use the blog as a catalog of knowledge learning, record the most popular and helpful information that the author thinks, and try to summarize a few sentences to indicate the essence, so that it will be easier to search in the future easy.


The structure of the title is as follows: "Type": "Knowledge Points" - "Short Explanation"
part of the content cannot be uploaded due to non-disclosure agreement.


点击此处进入学习日记的总目录

1. 51: Buzzer

  1. Buzzer introduction
    insert image description here

  2. Drive circuit
    insert image description here

  3. ULN2003
    insert image description here
    insert image description here
    insert image description here

  4. note vs. frequency
    insert image description here
    insert image description here

  5. common sheet music
    insert image description here
    insert image description here

2. 51: Press the button to control the sounding time of the buzzer

  1. looking for pins, apparentlyP25
    insert image description here
    insert image description here
  2. Write a delay function
    In order to achieve oscillation, first write a delay function to ensure timing oscillation
/**
  * @brief  蜂鸣器私有延时函数,延时500us
  * @param  无
  * @retval 无
  */
void Buzzer_Delay500us()		//@12.000MHz
{
    
    
	unsigned char i;

	_nop_();
	i = 247;
	while (--i);
}
  1. Write a sound function
    to make the buzzer sound within the specified time
//蜂鸣器端口:
sbit Buzzer=P2^5;

/**
  * @brief  蜂鸣器发声
  * @param  ms 发声的时长,范围:0~32767
  * @retval 无
  */
void Buzzer_Time(unsigned int ms)
{
    
    
	unsigned int i;
	for(i=0;i<ms*2;i++)
	{
    
    
		Buzzer=!Buzzer;
		Buzzer_Delay500us();
	}
}

In Buzzer_Timethe function , there is a loop statement for(i=0;i<ms*2;i++). The purpose of this loop is to have the buzzer generate a series of beeps for a specified duration 脉冲.
When Buzzer_Time(1000)calling , msthe value of the parameter 1000indicates that the buzzer should sound for 1000milliseconds (1 second).
In a loop, i the initial value of is incremented0 each time the loop ends . Since the loop condition is , that is , this loop will execute times . Inside the loop body, the buzzer state is first inverted, and then the function is called with a delay of about 500 microseconds. Therefore, each loop produces a state change of the buzzer and a delay lasting about microseconds . There are total cycles, so the total delay time is .i 1i<ms*2i<20002000
Buzzer_Delay500us()500
20002000 * 500 微秒 = 1000 毫秒(1秒)

3. 51: The Buzzer Sings——Castle in the Sky

  1. Automatic reloading value ( TH0, TL0) calculation
    In 8051 series microcontrollers, the automatic reloading value ( Auto-Reload Value) of timer 0 is used to set the timing initial value of the timer. Timer 0 is an 8-bit timer with a timing range of 0 to 255. When the timer 0 counter reaches 255, it will automatically reset the counter to the auto-reload value and trigger the timer 0 overflow interrupt.
计算自动重装载值(TH0,TL0)的方法取决于所需的定时周期和时钟频率。下面是一个示例计算步骤:

- 确定所需的定时周期。假设我们希望定时器01毫秒触发一次中断。
- 确定系统的时钟频率。假设系统的时钟频率为12.000MHz。
- 计算定时器的计数周期。由于定时器0是一个8位定时器,它可以计数的最大值为255。因此,定时器的计数周期为256- 计算所需的计数值。要实现1毫秒的定时周期,需要确定每个计数周期的时间。根据时钟频率和计数周期,可以计算出每个计数周期的时间(以秒为单位)。
- 计数周期时间 = 1 / (时钟频率 / 计数周期) = 1 / (12.000MHz / 256)21.33纳秒
注意:以上计算假设时钟频率和计数周期的单位相同,如均为Hz或均为MHz。
- 计算自动重装载值。根据所需的定时周期,可以计算出需要多少个计数周期才能达到该定时周期。然后,将计数周期数减去1,得到自动重装载值。根据上面的例子,每毫秒需要多少个计数周期:
计数周期数 = (1毫秒 / 计数周期时间) = (1毫秒 / 21.33纳秒)46882个计数周期
自动重装载值 = 计数周期数 - 146882 - 1 = 46881
- 因为定时器0是一个8位定时器,所以自动重装载值需要分为高8位(TH0)和低8位(TL0)。
TH0 = 自动重装载值 / 256 = 46881 / 256183
TL0 = 自动重装载值 % 256 = 46881 % 256 = 105

In this way, TH0set to 183, TL0set to 105, timer 0 will trigger an interrupt every 1 millisecond.

  1. Calculate the reload value for each frequency
    insert image description here
//音符与索引对应表,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#define P	0
#define L1	1
#define L1_	2
#define L2	3
#define L2_	4
#define L3	5
#define L4	6
#define L4_	7
#define L5	8
#define L5_	9
#define L6	10
#define L6_	11
#define L7	12
#define M1	13
#define M1_	14
#define M2	15
#define M2_	16
#define M3	17
#define M4	18
#define M4_	19
#define M5	20
#define M5_	21
#define M6	22
#define M6_	23
#define M7	24
#define H1	25
#define H1_	26
#define H2	27
#define H2_	28
#define H3	29
#define H4	30
#define H4_	31
#define H5	32
#define H5_	33
#define H6	34
#define H6_	35
#define H7	36

//索引与频率对照表
unsigned int FreqTable[]={
    
    
	0,
	63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,	//低频
	64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,	//中频
	65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,	//高频
};
  1. Write timer 0 initialization functionTimer0Init()
/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
    
    
    TMOD &= 0xF0;       // 设置定时器模式
    TMOD |= 0x01;       // 设置定时器模式
    TL0 = 0x18;         // 设置定时初值
    TH0 = 0xFC;         // 设置定时初值
    TF0 = 0;            // 清除TF0标志
    TR0 = 1;            // 定时器0开始计时
    ET0 = 1;            // 允许定时器0中断
    EA = 1;             // 允许总中断
    PT0 = 0;            // 设置定时器0中断优先级
}
  • TMOD &= 0xF0;And TMOD |= 0x01;: set the timer mode register TMOD, keep the original value of the upper 4 bits, and set the lower 4 bits to 0x01, which means that timer 0 is set to 16-bit working mode.
  • TL0 = 0x18;and TH0 = 0xFC;: Set the initial value of the low byte and high byte of Timer0 respectively, which are used for timer timing. These values ​​are set according to the specific clock frequency and desired timing period. (Because it will be set later, initialization here has no effect)
  • TF0 = 0;: Clear the Timer0 overflow flag to ensure that the Timer0 interrupt does not trigger immediately when it starts.
  • TR0 = 1;: Start timer 0 and start timing.
  • ET0 = 1;: Enable timer 0 interrupt, so that the interrupt service function can be triggered when timer 0 overflows.
  • EA = 1;: Enable total interrupt, so that the system can respond to all interrupt requests.
  • PT0 = 0;: Set the priority of Timer 0 interrupt to the lowest priority.

The purpose of this function is to set up Timer 0 as a 1 ms timer operating at a clock frequency of 12.000MHz. By setting the corresponding register value and enabling the interrupt, the timer 0 can trigger an interrupt every 1 millisecond to execute the corresponding interrupt service function.

  1. Write the processing function of Timer0 interrupt
void Timer0_Routine() interrupt 1
{
    
    
    if (FreqTable[FreqSelect])    // 如果不是休止符
    {
    
    
        /* 取对应频率值的重装载值到定时器 */
        TL0 = FreqTable[FreqSelect] % 256;    // 设置定时初值
        TH0 = FreqTable[FreqSelect] / 256;    // 设置定时初值
        Buzzer = !Buzzer;    // 翻转蜂鸣器IO口
    }
}
  • void Timer0_Routine() interrupt 1: Defines an interrupt service function Timer0_Routine(), where interrupt 1indicates that this function is the processing function for interrupt number 1.
  • if (FreqTable[FreqSelect]): Check whether the value FreqTable[FreqSelect]of is non-zero, and judge whether it is a rest (stop the buzzer).
  • TL0 = FreqTable[FreqSelect] % 256;And TH0 = FreqTable[FreqSelect] / 256;: Assign the value FreqTable[FreqSelect]of to the TL0 and TH0 registers respectively to set the initial value of the timer. where %represents the remainder operation and /represents integer division.
  • Buzzer = !Buzzer;: Invert the status of the I/O port of the buzzer by performing logic inversion operation on Buzzerthe variable . In this way, the switch of the buzzer can be controlled in the timer interrupt to realize the sound effect.

The interrupt service function controls the frequency and sound of the buzzer according FreqTable[FreqSelect]to the value FreqTable[FreqSelect]of . When is not zero, the initial value of the timer is set to the corresponding frequency value, and the state of the I/O port of the buzzer is reversed, so that Control the sound and stop of the buzzer. The definition and assignment of the specific frequency and frequency table are not given in the code, you can add or modify the corresponding code according to your specific needs.

  1. write mainfunction
//播放速度,值为四分音符的时长(ms)
#define SPEED	500

unsigned char FreqSelect,MusicSelect;

void main()
{
    
    
	Timer0Init();
	while(1)
	{
    
    
		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);
		}
	}
}

In this code, main()the function is the main entry point of the program. Here is main()the explanation of the function:

  • First call Timer0Init()the function to initialize timer 0, this function will set the mode and initial value of timer 0 and enable the interrupt of timer 0.
  • Enter an infinite loop ( while(1)), which is used to continuously process the playback of music.
  • In the loop, first judge whether the current score position is the end mark ( Music[MusicSelect] != 0xFF). If it is not a stop sign, there are still notes to be played.
  • Get the frequency value corresponding to the current note by reading Musicthe value in the array ( FreqSelect = Music[MusicSelect]). Then the incremented MusicSelectvalue is used to point to the duration of this one note.
  • Use the delay function ( Delay(SPEED/4*Music[MusicSelect])) to delay for a period of time, the duration of the current note multiplied by the playback speed. This delay function controls the duration of notes based on their duration in the score.
  • Before playing a note, timer 0 is stopped ( TR0 = 0), followed by a short pause ( Delay(5)), and timer 0 is restarted ( TR0 = 1). This creates a short pause between notes to differentiate between notes.
  • If the current score position is the end mark, it means that the music is finished playing, then stop the timer 0 ( TR0 = 0), and then enter an infinite loop ( while(1)), the program will always stop in this loop.

Through the above steps, main()the function controls the playback of the buzzer according to the notes and time values ​​in the score array. Continuously loop through the notes in the score until a stop marker is encountered.

  1. Just define the score,
    put a piece of Sky City here

//乐谱
unsigned char code Music[]={
    
    
	//音符,时值,
	
	//1
	P,	4,
	P,	4,
	P,	4,
	M6,	2,
	M7,	2,
	
	H1,	4+2,
	M7,	2,
	H1,	4,
	H3,	4,
	
	M7,	4+4+4,
	M3,	2,
	M3,	2,
	
	//2
	M6,	4+2,
	M5,	2,
	M6, 4,
	H1,	4,
	
	M5,	4+4+4,
	M3,	4,
	
	M4,	4+2,
	M3,	2,
	M4,	4,
	H1,	4,
	
	//3
	M3,	4+4,
	P,	2,
	H1,	2,
	H1,	2,
	H1,	2,
	
	M7,	4+2,
	M4_,2,
	M4_,4,
	M7,	4,
	
	M7,	8,
	P,	4,
	M6,	2,
	M7,	2,
	
	//4
	H1,	4+2,
	M7,	2,
	H1,	4,
	H3,	4,
	
	M7,	4+4+4,
	M3,	2,
	M3,	2,
	
	M6,	4+2,
	M5,	2,
	M6, 4,
	H1,	4,
	
	//5
	M5,	4+4+4,
	M2,	2,
	M3,	2,
	
	M4,	4,
	H1,	2,
	M7,	2+2,
	H1,	2+4,
	
	H2,	2,
	H2,	2,
	H3,	2,
	H1,	2+4+4,
	
	//6
	H1,	2,
	M7,	2,
	M6,	2,
	M6,	2,
	M7,	4,
	M5_,4,
	
	
	M6,	4+4+4,
	H1,	2,
	H2,	2,
	
	H3,	4+2,
	H2,	2,
	H3,	4,
	H5,	4,
	
	//7
	H2,	4+4+4,
	M5,	2,
	M5,	2,
	
	H1,	4+2,
	M7,	2,
	H1,	4,
	H3,	4,
	
	H3,	4+4+4+4,
	
	//8
	M6,	2,
	M7,	2,
	H1,	4,
	M7,	4,
	H2,	2,
	H2,	2,
	
	H1,	4+2,
	M5,	2+4+4,
	
	H4,	4,
	H3,	4,
	H3,	4,
	H1,	4,
	
	//9
	H3,	4+4+4,
	H3,	4,
	
	H6,	4+4,
	H5,	4,
	H5,	4,
	
	H3,	2,
	H2,	2,
	H1,	4+4,
	P,	2,
	H1,	2,
	
	//10
	H2,	4,
	H1,	2,
	H2,	2,
	H2,	4,
	H5,	4,
	
	H3,	4+4+4,
	H3,	4,
	
	H6,	4+4,
	H5,	4+4,
	
	//11
	H3,	2,
	H2,	2,
	H1,	4+4,
	P,	2,
	H1,	2,
	
	H2,	4,
	H1,	2,
	H2,	2+4,
	M7,	4,
	
	M6,	4+4+4,
	P,	4,
	
	0xFF	//终止标志
};

Guess you like

Origin blog.csdn.net/qq_36769966/article/details/130308517