Создаем простое звуковое сопровождение на микроконтроллере STM32f103.

Страница на этапе разработки

В данном уроке мы с Вами напишем не большой код, который в «фоновом» режиме будет воиспроизводить простенькую мелодию. Данная мелодию можно сравнить с игрой гитары на одной струне. Мы будем по очереди воиспроизводить ноты определенной длительностью. Вывод мелодии у нас будет с помощью аппаратного ШИМ, который мы настроим на Timer4.
Выводить звук мы будем на обычный динамик:

Значения резисторов:
R3 — 1кОм
R2 — 10кОм
R1 — зависит от сопротивления динамика и максимально допустимого тока через транзистор: Imaxtr> Upw/(R1+Rls1).

Для начала нам нужно настроить наш ШИМ:

 

 

#include «stm32f10x.h»
#include «stm32f10x_rcc.h»
#include «stm32f10x_gpio.h»
#include «stm32f10x_tim.h»

#define SYSCLK 72000000
#define PRESCALER 72

#define C 261 //Do
#define C_ 277 //Do#
#define D 293 //Re
#define D_ 311 //Re#
#define E 239 //Mi
#define F 349 //Fa
#define F_ 370 //Fa#
#define G 392 //Sol
#define G_ 415 //Sol#
#define A 440 //La
#define A_ 466 //La#
#define H 494 //Si

#define t1 2000
#define t2 1000
#define t4 500
#define t8 250
#define t16 125

typedef struct
{
uint16_t freq;
uint16_t time;
}SoundTypeDef;

#define MUSICSIZE 48

const SoundTypeDef Music[MUSICSIZE] ={
{C*2, t4},
{G, t4},
{A_, t8},
{F, t8},
{D_, t8},
{F, t8},
{G, t4},
{C, t2},
{C*2, t4},
{G, t4},
{A_, t8},
{F, t8},
{D_, t8},
{F, t8},
{G, t4},
{C*2, t4},
{0, t8},
{D_, t8},
{D_, t8},
{D_, t8},
{G, t8},
{A_, t4},
{D_*2, t8},
{C_*2, t8},
{C*2, t8},
{C*2, t8},
{C*2, t8},
{C*2, t8},
{A_, t8},
{F, t8},
{D_, t8},
{F, t8},
{G, t4},
{C*2, t2},
{C*2, t2},
{A_, t8},
{G_, t8},
{G, t8},
{G_, t8},
{A_, t2},
{A_, t4},
{C*2, t4},
{A_, t8},
{F, t8},
{D_, t8},
{F, t8},
{G, t4},
{C*2, t2}
};

int MusicStep = 0;
char PlayMusic = 0;

void StartMusic(void) {
MusicStep = 0;
PlayMusic = 1;
sound(Music[MusicStep].freq, Music[MusicStep].time);
}

void SetSysClockTo72(void)
{
ErrorStatus HSEStartUpStatus;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ——————————*/
/* RCC system reset(for debug purpose) */
RCC_DeInit();

/* Enable HSE */
RCC_HSEConfig( RCC_HSE_ON);

/* Wait till HSE is ready */
HSEStartUpStatus = RCC_WaitForHSEStartUp();

if (HSEStartUpStatus == SUCCESS)
{
/* Enable Prefetch Buffer */
//FLASH_PrefetchBufferCmd( FLASH_PrefetchBuffer_Enable);

/* Flash 2 wait state */
//FLASH_SetLatency( FLASH_Latency_2);

/* HCLK = SYSCLK */
RCC_HCLKConfig( RCC_SYSCLK_Div1);

/* PCLK2 = HCLK */
RCC_PCLK2Config( RCC_HCLK_Div1);

/* PCLK1 = HCLK/2 */
RCC_PCLK1Config( RCC_HCLK_Div2);

/* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLConfig(0x00010000, RCC_PLLMul_9);

/* Enable PLL */
RCC_PLLCmd( ENABLE);

/* Wait till PLL is ready */
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}

/* Select PLL as system clock source */
RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK);

/* Wait till PLL is used as system clock source */
while (RCC_GetSYSCLKSource() != 0x08)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock configuration.
User can add here some code to deal with this error */

/* Go to infinite loop */
while (1)
{
}
}
}

GPIO_InitTypeDef port;
TIM_TimeBaseInitTypeDef timer;
TIM_OCInitTypeDef timerPWM;

int sound_time;
int sound_counter;

void sound_init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

GPIO_StructInit(&port);
port.GPIO_Mode = GPIO_Mode_AF_PP;
port.GPIO_Pin = GPIO_Pin_6;
port.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &port);

TIM_TimeBaseStructInit(&timer);
timer.TIM_Prescaler = PRESCALER;
timer.TIM_Period = 0xFFFF;
timer.TIM_ClockDivision = 0;
timer.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &timer);

TIM_OCStructInit(&timerPWM);
timerPWM.TIM_Pulse = 0;
timerPWM.TIM_OCMode = TIM_OCMode_PWM1;
timerPWM.TIM_OutputState = TIM_OutputState_Enable;
timerPWM.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM4, &timerPWM);

/* Enable Interrupt by overflow */
TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);

//TIM_Cmd(TIM4, ENABLE);

/* Enable Interrupt of Timer TIM2 */
NVIC_EnableIRQ(TIM4_IRQn);
}

void TIM4_IRQHandler(void){

if (TIM_GetITStatus(TIM4, TIM_IT_CC4) != RESET)
{
/* Reset flag */
TIM_ClearITPendingBit(TIM4, TIM_IT_CC4);

sound_counter++;
if (sound_counter > sound_time) {
if (PlayMusic == 0) {
TIM_Cmd(TIM4, DISABLE);
}
else {
if (MusicStep < MUSICSIZE-1) { if (TIM4->CCR1 == 0){
MusicStep++;
sound(Music[MusicStep].freq, Music[MusicStep].time);
}
else{
sound(0, 30);
}
}
else {
PlayMusic = 0;
TIM_Cmd(TIM4, DISABLE);
}
}
}

/* over-capture */
if (TIM_GetFlagStatus(TIM4, TIM_FLAG_CC4OF) != RESET)
{
TIM_ClearFlag(TIM4, TIM_FLAG_CC4OF);
// …
}
}
}

void sound (int freq, int time_ms) {
if (freq > 0) {
TIM4->ARR = SYSCLK / timer.TIM_Prescaler / freq;
TIM4->CCR1 = TIM4->ARR / 2;
}
else {
TIM4->ARR = 1000;
TIM4->CCR1 = 0;
}
TIM_SetCounter(TIM4, 0);

sound_time = ((SYSCLK / timer.TIM_Prescaler / TIM4->ARR) * time_ms ) / 1000;
sound_counter = 0;
TIM_Cmd(TIM4, ENABLE);
}

int main(void)
{
SetSysClockTo72();
sound_init();

//sound (440, 1000);
StartMusic();

while(1)
{

}

}