Music player based on STM32, using PWM to control the buzzer

Table of contents

Show results

Preface

1. Design background

1.1. Knowledge reserve

2. System design plan

2.1. Implement functions

2.2. Hardware part

2.3. Software part

3. Software design

3.1. Design flow chart

3.2. Setting of music frequency

3.3. Main ideas of programming

4. Programming


Show results

 

Using PWM to control the buzzer based on STM32


Preface

        For the music player project, I use PWM output capture to control the passive buzzer sound, which frees up the space of the main function to control other peripherals.(I have given a detailed introduction and application examples of PWM in the STM32 study notes)

1. Design background

1.1. Knowledge reserve

        Used knowledge about buzzers, independent buttons, LEDs, PWM output capture, pin remapping, timer interrupts, etc.. at the same timeAlso understand the STM32 internal clock tree, the development tools I use are:STM32 CubeMX and MDK kile5, andIThe HAL library is usedProgramming performed. The main reason why the standard library is not used is that the HAL library is a library that ST has been maintaining and supporting updates. It has better support. The standard library has stopped maintaining it in 2011, but the calls to the HAL library are more abstract, so I The standard library is used when studying, which is more vivid and concrete, and can quickly lay the foundation. When doing projects, the HAL library is used, and cubeMX can be used for graphical programming, which is more efficient. Both libraries have their pros and cons, and no one is better or worse. Moreover, the HAL library only supports ST’s microcontrollers, which in disguise limits development portability.

2. System design plan

2.1. Implement functions

        1. When the development board is powered on, the buzzer can play music normally;

2. You can switch songs forward\backward by pressing the keys;

3. The LED indicator light flips as the button is pressed;

2.2. Hardware part

        The punctual atomic elite development board is used, the chip is STM32F103ZET6, and the internal clock is 72M. The buzzer is a passive buzzer with no internal oscillation circuit, and its frequency can be changed to make it play music. Independent buttons control music playback and can switch songs. The LED is used as an indicator light to determine whether the independent button is pressed.

2.3. Software part

        PE5 and PB5 are LED pins, PB7 is PWM output capture pin (TIM4, CH2), PE3 and PE4 are independent button control pins (turn on interrupt), turn on timer TIM2;

Clock tree settings

3. Software design

3.1. Design flow chart

3.2. Setting of music frequency

The difficulty of this project is to set the music frequency. According to my previous experience of using a 51 microcontroller to make a music player, the music frequency is mainly the relationship between the notes, pitch and beat of the music.

The note determines the pronunciation unit, the pitch determines the volume, and the beat determines the length of time the note is pronounced.

3.3. Main ideas of programming

Because I use PWM and timer to control the buzzer, the main relationship is as follows:The timer grasps the beat of the music, and the PWM grasps the pitch and notes.

I still have to talk about PWM.The PWM period is determined by the timer division coefficient and the reload value. The main frequency of STM32F103ZET6 is 72MHZ, and the frequency division is set to 9, so the maximum is 8MHZ. The minimum frequency we need is 262HZ, so we only need to calculate the reload value not greater than the timer’s maximum reload value (65535).

        Therefore, every time the note is converted, the reload value can be dynamically modified to change the PWM output frequency, thereby controlling the passive buzzer to sound. The timer will perform ms interrupt to determine whether the time of each beat is reached, and when it reaches the next beat, the next beat will be played.

4. Programming


The space is limited and only part of the code can be shown. If you need all the code, please send a private message to the blogger, thank you.

The music.c program is as follows:

#include "music.h"

uint16_t C_FREQ[]={0,262,294,330,349,392,440,
								494,523,587,659,698,784,880,988,
						 1046,1175,1318,1397,1568,1760,1976};

/*-------------------Two tigers--------------------*/

/*frequency*/
uint8_t music_two_tiger_f[]={
		1,2,3,1,
		1,2,3,1,
		3,4,5,
		3,4,5,
		5,6,5,6,3,1,
		5,6,5,4,3,1,
		1,5,1,
		1,5,1,
};

/*1/4 beat length*/
u16 music_two_tiger_t_echo=150;

/*length*/
u16 music_two_tiger_len=(sizeof(music_two_tiger_f)/sizeof(uint8_t));

/*beat length*/
uint8_t music_two_tiger_t[]={
		P_1,P_1,P_1,P_1,
		P_1,P_1,P_1,P_1,
		P_1,P_1,P_2,
		P_1,P_1,P_2,
		P_4_3,P_4_1,P_4_3,P_4_1,P_1,P_1,
		P_4_3,P_4_1,P_4_3,P_4_1,P_1,P_1,
		P_1,P_1,P_2,
		P_1,P_1,P_2,
};

/*-------------------Spring Festival Overture--------------------*/

/*frequency*/
uint8_t music_happy_newyear_f[]={
		3,2,3,5,5,6,
		7,6,7,7,
		3,7,6,5,3,5,
		6,5,6,5,
		5,6,1,6,1,2,
		1,6,5,3,
		5,6,1,2,1,7,
		6,5,6,5,
		3,2,3,5,5,6,
		1,6,3,1,
};

/*1/4 beat length*/
u16 music_happy_newyear_t_echo=200;

/*length*/
u16 music_happy_newyear_len=(sizeof(music_happy_newyear_f)/sizeof(uint8_t));

/*beat length*/
uint8_t music_happy_newyear_t[]={
		P_2_1,P_1,P_2_1,P_2_1,P_1,P_2_1,
		P_1,P_2_1,P_2_1,P_2,
		P_2_1,P_1,P_2_1,P_2_1,P_1,P_2_1,
		P_4_3,P_4_1,P_1,P_2,
		P_4_3,P_4_1,P_1,P_2_1,P_1,P_2_1,
		P_1,P_2_1,P_2_1,P_2,
		P_4_3,P_4_1,P_1,P_2_1,P_1,P_2_1,
		P_4_3,P_4_1,P_1,P_2,
		P_2_1,P_1,P_2_1,P_2_1,P_1,P_2_1,
		P_1,P_2_1,P_2_1,P_2,
};

/*-------------------Unforgettable Tonight--------------------*/

/*frequency*/
uint8_t music_bitter_unforget_f[]={
  2,3,2,1,2,3,2,5,
	5,5,5,2,4,3,2,
	7,1,2,3,1,7,1,2,3,5,
	5,4,3,4,3,2,1,
	
	5,6,5,4,1,3,4,6,5,5,
	2,6,5,6,4,6,5,
	3,4,3,2,5,3,4,3,2,1,
	
	5,4,3,4,3,2,1,
	6,5,4,1,4,6,5,5,
	6,5,4,1,4,6,5,5,

	3,2,1,5,1,3,2,2,
	3,2,1,5,1,3,5,5,
	3,2,1,5,1,3,1,1,
};

/*1/4 beat length*/
u16 music_bitter_unforget_t_echo=300;

/*length*/
u16 music_bitter_unforget_len=(sizeof(music_bitter_unforget_f)/sizeof(uint8_t));

/*beat length*/
uint8_t music_bitter_unforget_t[]={
  P_2_1,P_4_1,P_4_1,P_1,P_2_1,P_4_1,P_4_1,P_1,
	P_2_1,P_2_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2,
	P_4_1,P_4_1,P_4_1,P_4_1,P_1,P_4_1,P_4_1,P_4_1,P_4_1,P_1,
	P_2_1,P_2_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2,
	
  P_2_1,P_4_1,P_4_1,P_2_1,P_2_1,P_4_1,P_4_1,P_4_1,P_4_1,P_1,
	P_2_1,P_2_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2,
	P_4_1,P_4_1,P_4_1,P_4_1,P_1,P_4_1,P_4_1,P_4_1,P_4_1,P_1,
	
	P_2_1,P_2_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2,
	P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2_1,P_2,
	P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2_1,P_2,
	
	P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2_1,P_2,
	P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2_1,P_2,
	P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_4_1,P_2_1,P_2,
};

struct MUSIC_T music_t;

u8 B0[]="stop";
u8 B1[]="two tigers";
u8 B2[]="happy newyear";
u8 B3[]="bitter_unforget";

void music_tea_seeds(u8 n){
		switch(n){
				case 0:{
						music_t.f=NULL;
						music_t.t=NULL;
						music_t.len=0;
						music_t.t_each=0;
						music_t.name=B0;
								};break;
				case 1:{
						music_t.f=music_two_tiger_f;
						music_t.t=music_two_tiger_t;
						music_t.len=music_two_tiger_len;
						music_t.t_each=music_two_tiger_t_echo;
						music_t.name=B1;
							}; break;
				case 2:{
						music_t.f=music_happy_newyear_f;
						music_t.t=music_happy_newyear_t;
						music_t.len=music_happy_newyear_len;
						music_t.t_each=music_happy_newyear_t_echo;
						music_t.name=B2;
							};break;
				case 3:{
						music_t.f=music_bitter_unforget_f;
						music_t.t=music_bitter_unforget_t;
						music_t.len=music_bitter_unforget_len;
						music_t.t_each=music_bitter_unforget_t_echo;
						music_t.name=B3;
							};break;
				case 4:{

								}; break;
				case 5:{

								};break;
						}
}

beep.c

#include "beep.h"
#include "music.h"
#include "tim.h"

#define TEA_VOL 99

/*
The buzzer sounds according to the frequency
note_f: frequency, the value comes from the array
vol [0,100]
*/

void my_passive_buzzer_set(uint16_t note_f)
{
		/*Calculate the automatic reload value and calculate the new frequency*/
		uint16_t Autoreload=(80000.0/(float)C_FREQ[note_f])-1;	
		/*Calculate volume*/
    uint16_t volume=(((float)Autoreload)/100.0)*TEA_VOL;
	  /*Set the auto-reload value*/
		__HAL_TIM_SET_AUTORELOAD(&htim4,Autoreload);	
	  /*Set volume*/
		__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,volume);
	  /*Situation calculation value*/
		__HAL_TIM_SET_COUNTER(&htim4,0);
}

u32 paly_delay_ms=0;
void my_buzzer_play()
{
    static u8 last_flg=255;//Record the previous song
	
	  /*Song switching*/
	  if(last_flg!=music_t.now_flg)
			{
				music_t.now_len=0;
				music_code_get(music_t.now_flg);
				last_flg=mymusic_t.now_flg;
		  }
		if(music_t.now_flg==0)
			{
				passive_buzzer_set(0);
				return;
		  }
		if(paly_delay_ms==0)
			{
					paly_delay_ms=music_t.t_each*music_t.t[music_t.now_len];
					passive_buzzer_set(music_t.f[music_t.now_len]);
				
			  if(music_t.now_len>=(music_t.len-1))
					{
							music_t.now_len=0;
					}else
					{
							music_t.now_len++;
					}
			}else
			{
				 paly_delay_ms--;
			}
}

/*Timer 1ms interrupt*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
   if(htim->Instance == TIM2)
		 {
					buzzer_play();
     }
}

tim.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim4;

/* TIM2 init function */
void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 7200-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 9;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}
/* TIM4 init function */
void MX_TIM4_Init(void)
{

  /* USER CODE BEGIN TIM4_Init 0 */

  /* USER CODE END TIM4_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM4_Init 1 */

  /* USER CODE END TIM4_Init 1 */
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 9-1;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 65535-1;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */

  /* USER CODE END TIM4_Init 2 */
  HAL_TIM_MspPostInit(&htim4);

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

  /* USER CODE END TIM2_MspInit 0 */
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    /* TIM2 interrupt Init */
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspInit 1 */

  /* USER CODE END TIM2_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspInit 0 */

  /* USER CODE END TIM4_MspInit 0 */
    /* TIM4 clock enable */
    __HAL_RCC_TIM4_CLK_ENABLE();

    /* TIM4 interrupt Init */
    HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspInit 1 */

  /* USER CODE END TIM4_MspInit 1 */
  }
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(timHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspPostInit 0 */

  /* USER CODE END TIM4_MspPostInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**TIM4 GPIO Configuration
    PB7     ------> TIM4_CH2
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM4_MspPostInit 1 */

  /* USER CODE END TIM4_MspPostInit 1 */
  }

}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();

    /* TIM2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspDeInit 1 */

  /* USER CODE END TIM2_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspDeInit 0 */

  /* USER CODE END TIM4_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM4_CLK_DISABLE();

    /* TIM4 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspDeInit 1 */

  /* USER CODE END TIM4_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

Thank you for your support~

Related Posts

About the pitfalls of ARM development (AI)

GD32F4xx serial port transceiver, DMA+idle interrupt

Nanny-level official yolov7’s training of own data sets and project deployment

The relationship between FLOPs, MACs, and MAdds of deep learning model calculation load evaluation indicators

Teach you step by step how to use it – commonly used modules – HC05 Bluetooth module, wireless Bluetooth serial port transparent transmission module, (example: mobile phone Bluetooth controls STM32 microcontroller to light up the LED light)

Using USB to TTL serial port burning program STM32F103C8T6 core board (CH340)

TI millimeter wave cascade radar evaluation boards MMWCAS-DSP-EVM and MMWCAS-RF-EVM

Fundamentals of Deep Learning: Survey on Compressed Video Enhancement

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*