基于STM32的电子琴/音乐播放器设计

文章目录

  • 基于STM32的电子琴/音乐播放器设计
    • @[toc]
    • 引言
    • 第一章 总体设计
      • 1.1 系统功能
      • 1.2 主要技术性能指标
    • 第二章 系统设计
      • 2.1 系统设计
      • 2.2 硬件设计
        • 2.2.1 整体仿真图
        • 2.2.2 按键模块
        • 2.2.3 扬声器模块
        • 2.2.4 显示模块
        • 2.2.5 主控模块
      • 2.3 软件设计
        • 2.3.1 主要工作原理
        • 2.3.2 PWM发生器
        • 2.3.3 music播放器模块
        • 2.3.4 exti外部中断
        • 2.3.5 按键相关驱动
        • 2.3.6 LCD1602驱动
        • 2.3.7 主函数相关设计
    • 第三章 系统调试
      • 3.1 仿真调试
      • 3.2 仿真结果
      • 3.3 实际电路调试
      • 3.4 功能测试
      • 3.5 过程中遇到的问题
    • 第四章 总结
      • 3.2 仿真结果
      • 3.3 实际电路调试
      • 3.4 功能测试
      • 3.5 过程中遇到的问题
    • 第四章 总结

引言

​ 单片微型计算机室大规模集成电路技术发展的产物,属于第四代电子计算机它具有高性能、高速度、体积小、价格低廉、稳定可靠、应用广泛的特点。他的应用必定导致传统的控制技术从根本上发生变革。因此,单片机的开发应用已成为高科技和工程领域的一项重大课题。

​ 电子琴是现代电子科技与音乐结合的产物,是一种新型的键盘乐器。它在现代音乐扮演重要的角色,单片机具有强大的控制功能和灵活的编程实现特性,它已经溶入现代人们的生活中,成为不可替代的一部分。本文的主要内容是用STM32f103rbt6单片机为核心控制元件,设计一个电子琴。

​ 设计核心在于使用STM32单片机内置的

第一章 总体设计

1.1 系统功能

按照设计要求,本系统具有以下功能:

  1. 共有三个基本模式:电子琴模式、录音模式、播放器模式
  2. 电子琴模式下,7个基本按键控制产生7种音调,功能键实现调节音阶和音量
  3. 录音模式可分为录音和放音两个模块,录音状态下会记录弹奏的音调以及时间;放音模式调用音乐播放器某些模块,实现相同的功能。
  4. 音乐播放器模块下,可以实现音乐的播放、暂停、切歌、调速、顺序播放、单曲循环、随机播放、以及进度条显示。
  5. 有两个全局按键中断,可控制模式切换和全局静音/暂停。

1.2 主要技术性能指标

  1. 基本按键:7个;
  2. 功能按键:6个;
  3. 全局中断按键:2个;
  4. 扬声器:1个;
  5. 扬声器功率:1w;
  6. LCD1602:1块;
  7. 主要模式:3个;
  8. 曲库:8首;
  9. 音域范围:262Hz~2217Hz;
  10. 音量阶数:3阶;
  11. 速度阶数:4阶;
  12. 循环模式:3种;

第二章 系统设计

2.1 系统设计

​ 总体系统设计上在硬件上共分为3个区域:基本按键区、功能按键区、LCD显示区。在软件的设计上共分为3个主要模式:电子琴模式、录音模式、播放器模式。主控模块选择使用STM32f103rbt6芯片,进行编程、控制、实现电子琴以及播放器功能。

2.2 硬件设计

2.2.1 整体仿真图

2.2.2 按键模块

​ 按键模块分为两部分:基本按键和功能按键

俩个部分按键分别接在单片机的PC0-PC6以及PC8-PC13接口上。

2.2.3 扬声器模块

扬声器模块接在单片机的PC07接口上。

2.2.4 显示模块

​ 将LCD1602的D0~D7分别连接到单片机的 PA0~7,使能端 E、 RW、 RS分别连接到单片机的 PA8、 PA11、 PA12。

2.2.5 主控模块

2.3 软件设计

2.3.1 主要工作原理

​ 设计的主要工作原理是利用STM32所内置的定时器TIM3产生一个PWM信号驱动扬声器产生特定频率的声音。通过改变定时器TIM3的分频预置数改变PWM信号的频率从而产生不同音调的声音。通过改变占空比,从而产生不同音量的声音。

​ 相关流程图如下:

Created with Raphaël 2.3.0开始各模块初始化模式选择输入模式=1?钢琴模式模式=2?录音模式模式=3?播放器模式等待模式选择yesnoyesnoyesno

2.3.2 PWM发生器

#include "pwm.h"TIM_HandleTypeDef  TIM3_Handler;       //定时器句柄
TIM_OC_InitTypeDef  TIM3_CH2Handler;    //定时器3通道1句柄//TIM1 PWM部分初始化
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
void TIM3_PWM_Init(u16 arr,u16 psc)
{  TIM3_Handler.Instance=TIM3;             //定时器1TIM3_Handler.Init.Prescaler=psc;         //定时器分频TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式TIM3_Handler.Init.Period=arr;             //自动重装载值TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//分频因子TIM3_Handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;//使能自动重载HAL_TIM_PWM_Init(&TIM3_Handler);         //初始化PWMTIM3_CH2Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1TIM3_CH2Handler.Pulse=arr/2;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%TIM3_CH2Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低 HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH2Handler,TIM_CHANNEL_2);//配置TIM3通道2HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_2);//开启PWM通道2}//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{GPIO_InitTypeDef GPIO_Initure;if(htim->Instance==TIM3){__HAL_RCC_TIM3_CLK_ENABLE();           //使能定时器3__HAL_AFIO_REMAP_TIM3_ENABLE();         //TIM3通道引脚完全重映射使能__HAL_RCC_GPIOC_CLK_ENABLE();          //开启GPIOC时钟GPIO_Initure.Pin=GPIO_PIN_7;            //PC6GPIO_Initure.Mode=GPIO_MODE_AF_PP;    //复用推挽输出GPIO_Initure.Pull=GPIO_PULLUP;          //上拉GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速HAL_GPIO_Init(GPIOC,&GPIO_Initure);   }
}//设置TIM3通道2的占空比
//compare:比较值
void TIM_SetTIM3Compare2(u32 compare)
{TIM3->CCR2=compare;
}//设置TIM3通道2的arr
void TIM_SetTIM3Autoreload(u32 Autoreload)
{TIM3->ARR=Autoreload;
}
//定时器3中断服务函数
void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&TIM3_Handler);
}

2.3.3 music播放器模块

​ music模块包含了产生声音,静音,音乐播放,音乐切换,进度条展示等相关函数,全都由本人编写

静音模块:通过调用TIM_SetTIM3Compare2()函数让占空比为0,进而达到静音效果。

void buzzerQuiet(void)//停止发声
{TIM_SetTIM3Compare2(0);
}

发声函数:通过调用TIM_SetTIM3Autoreload设置TIM3的自动装载值实现产生特定频率PWM信号,传入的参数为声音频率和音量参数。

void buzzerSound(unsigned short usFraq,unsigned char volume_level)//发声模块
{unsigned long Autoreload;if((usFraq<=122)||(usFraq>20000)){buzzerQuiet();}else{Autoreload=(8000000/usFraq)-1; TIM_SetTIM3Autoreload(Autoreload);TIM_SetTIM3Compare2(Autoreload>>volume_level); }
}

进度条显示函数:可以显示播放进度以及全局状态,如当前曲目、暂停状态、音量、播放速度等。

void playstate(int a,char n)
{switch(a){case 0:sprintf((char *)tab1,"%c%c-           %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 1:sprintf((char *)tab1,"%c%c--          %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 2:sprintf((char *)tab1,"%c%c---         %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 3:sprintf((char *)tab1,"%c%c----        %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 4:sprintf((char *)tab1,"%c%c-----       %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 5:sprintf((char *)tab1,"%c%c------      %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 6:sprintf((char *)tab1,"%c%c-------     %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 7:sprintf((char *)tab1,"%c%c--------    %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 8:sprintf((char *)tab1,"%c%c---------   %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 9:sprintf((char *)tab1,"%c%c----------  %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 10:sprintf((char *)tab1,"%c%c----------- %c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 11:sprintf((char *)tab1,"%c%c------------%c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;case 12:sprintf((char *)tab1,"%c%c------------%c%d",n,pausename[pauseflag],speedname[speed],vol+1);break;}
}

下一首函数:根据传入nextmode参数不同进行顺序,单曲,随机下一首。

void nextsong(int nextmode,int i)
{int h;
//  tNote *p;if(nextmode==1)next=(next+1)%8;else if(nextmode==2)next=next;else if(nextmode==0){h=i%6+1;next = (next+h)%8;}
}

音乐播放函数:传入乐谱(由结构体数组实现),调用弹奏音符函数,实现音乐自动播放。

void play_node(int tone,int time)//弹奏音符
{buzzerSound(tone,volume);delay_ms(time/((speed+1)*0.5));buzzerQuiet();delay_ms(10);
}
void musicPlay(tNote song[],int n)//音乐播放
{void play_node(int tone,int time);u8 i=1;int playflag=1;int len = song[0].mName;while((song[i].mName||song[i].mTime)&&playflag&&mode==2){key1 = KEY_Scan(0);switch(key1){case KEY13_PRES:playflag=0;break;case KEY12_PRES:vol=(vol+1)%3;//0~2循环break;case KEY11_PRES:speed=(speed+1)%4;break;case KEY10_PRES:nextmode=(nextmode+1)%3;switch(nextmode){case 0:sprintf((char *)tab0,"  SHUFFLE PLAY  ");LCD_SHOW(tab0,0);break;case 1:sprintf((char *)tab0,"   ORDER PLAY   ");LCD_SHOW(tab0,0);break;case 2:sprintf((char *)tab0,"  SINGLE CYCLE  ");LCD_SHOW(tab0,0);}break;        }if(pauseflag){play_node(song[i].mName,song[i].mTime);i++;}playstate(12*i/len,n+48);LCD_SHOW(0,tab1);}nextsong(nextmode,i);
}

2.3.4 exti外部中断

​ 本设计使用了PC8,PC9口的按键作为两个外部中断,控制全局切换模式,以及全局暂停/静音

#include "exti.h"
#include "delay.h"
#include "key.h"
#include "music.h"#define NEXT_MODE() (mode=(mode+1)%3)
#define PAUSE() (pauseflag=!pauseflag)extern int mode;
extern int pauseflag;//外部中断初始化
void EXTI_Init(void)
{GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOC_CLK_ENABLE();               //开启GPIOC时钟GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_9;  //PC8、PC9GPIO_Initure.Mode=GPIO_MODE_IT_FALLING;     //下降沿触发GPIO_Initure.Pull=GPIO_PULLUP;HAL_GPIO_Init(GPIOC,&GPIO_Initure);//中断线8、9-PC8、9HAL_NVIC_SetPriority(EXTI9_5_IRQn,2,1);    //抢占优先级为2,子优先级为1HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); }
void EXTI9_5_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8);      //调用中断处理公用函数HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);       //调用中断处理公用函数
}
//中断服务程序中需要做的事情
//在HAL库中所有的外部中断服务函数都会调用此函数
//GPIO_Pin:中断引脚号
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{delay_ms(10);          //消抖switch(GPIO_Pin){case GPIO_PIN_8:if(KEY8==0)      {buzzerSound(FM2,1);delay_ms(200);buzzerQuiet();NEXT_MODE();//切换模式}break;case GPIO_PIN_9:if(KEY9==0)  {PAUSE();//暂停}break;}
}

2.3.5 按键相关驱动

​ 按键初始化相关代码采用例程,在此不列出,只列出关键代码:

 static u8 key_up=1;//按键按松开标志
u8 KEY_Scan(u8 mode)
{    if(mode)key_up=1;  //支持连按       if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==0||KEY4==0||KEY5==0||KEY6==0||KEY8==0||KEY9==0||KEY10==0||KEY11==0||KEY12==0||KEY13==0)){delay_ms(10);//去抖动 key_up=0;if(KEY0==0)return KEY0_PRES;else if(KEY1==0)return KEY1_PRES;else if(KEY2==0)return KEY2_PRES;else if(KEY3==0)return KEY3_PRES;else if(KEY4==0)return KEY4_PRES;else if(KEY5==0)return KEY5_PRES;else if(KEY6==0)return KEY6_PRES;else if(KEY8==0)return KEY8_PRES;else if(KEY9==0)return KEY9_PRES;else if(KEY10==0)return KEY10_PRES;else if(KEY11==0)return KEY11_PRES;else if(KEY12==0)return KEY12_PRES;else if(KEY13==0)return KEY13_PRES;}else if(KEY0==1&&KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1&&KEY5==1&&KEY6==1&&KEY8==1&&KEY9==1&&KEY10==1&&KEY11==1&&KEY12==1&&KEY13==1)key_up=1;       return 0;// 无按键按下
}

​ 通过函数判断按键值,mode参数可调节是否支持连按。

2.3.6 LCD1602驱动

​ LCD初始化相关代码采用例程,在此不列出,只列出关键代码:

void LCD_SHOW(u8* tab0,u8* tab1)
{if(tab0)LCD1602_Show_Str(0, 0, tab0);if(tab1)LCD1602_Show_Str(0, 1, tab1);
}

​ 定义函数LCD_SHOW,传入字符串显示,在避免直接调用LCD的显示函数,通过tab0tab1的锁存,实现更丰富需求。

2.3.7 主函数相关设计

#include "sys.h"
#include "main.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "lcd1602.h"
#include "music.h"
#include "pwm.h"
#include "exti.h"#define MENU 8
#define PIANO 0
#define RECORD 1
#define PLAYER 2#define volume (7-3*vol)void LCD_SHOW(u8* tab0,u8* tab1);int nextmode=1;
int mode = 8;
int vol = 2;
int tone =1;
u8 tab0[16];
u8 tab1[16];
int startflag=0;
int finishflag=0;
int psite=0;
int pauseflag=1;vu8 key=0;
int speed=1;
int relen=0;
char pausename[2]={'P','S'};
char speedname[4]={'L','N','M','H'};extern tNote Score1[];
extern tNote Score2[];
extern tNote Score3[];
extern tNote Score4[];
extern tNote Score5[];
extern tNote Score6[];
extern tNote Score7[];
extern tNote Score8[];
//extern tNote Score1[];
//extern tNote Score1[];//int next =1;int ToneList[3][7]=
{{262,294,330,349,392,440,494},{523,587,659,698,784,880,988},{1047,1175,1319,1397,1568,1760,1976}
};
char ToneName[3]=
{'L','M','H'
};
tNote RecordScord[100];int main(void)
{//    u8 len;
//  u16 times=0;  int reflag=0;HAL_Init();                        //初始化HAL库    Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72Mdelay_init(72);                 //初始化延时函数uart_init(115200);              //初始化串口115200LCD1602_Init();TIM3_PWM_Init(0xfffe,8);KEY_Init();EXTI_Init();printf("1231");delay_ms(5);void musicPlayRE(int len);/*0123456789ABCDEF*/sprintf((char *)tab0," Mode Selection ");sprintf((char *)tab1,"Please Press 1~3");LCD_SHOW(tab0,tab1);buzzerSound(FM1,1);delay_ms(100);buzzerQuiet();//musicPlay();while(1){while(mode == MENU){key = KEY_Scan(0);switch(key){case KEY0_PRES:mode =PIANO;
//                                      /*0123456789ABCDEF*/
//                  sprintf((char *)tab0,"   PIANO MODE   ");
//                  sprintf((char *)tab1," Tone=%c   Vol=%d ",(tone+67),vol);
//                  LCD_SHOW(tab0,tab1);break;case KEY1_PRES:mode = RECORD;break;case KEY2_PRES:mode = PLAYER;break;default:delay_ms(10);}}while(mode == PIANO){sprintf((char *)tab0,"   PIANO MODE   ");sprintf((char *)tab1," Tone=C%c  Vol=%d ",ToneName[tone],vol+1);LCD_SHOW(tab0,tab1);key = KEY_Scan(0);switch(key){case KEY13_PRES:vol=(vol+1)%3;//0~2循环break;case KEY12_PRES:tone = (tone+1)%3;break;}while(!KEY0){buzzerSound(ToneList[tone][0],7-3*vol);//音量用函数转成分频值012---741}while(!KEY1){buzzerSound(ToneList[tone][1],7-3*vol);}while(!KEY2){buzzerSound(ToneList[tone][2],7-3*vol);}while(!KEY3){buzzerSound(ToneList[tone][3],7-3*vol);}while(!KEY4){buzzerSound(ToneList[tone][4],7-3*vol);}while(!KEY5){buzzerSound(ToneList[tone][5],7-3*vol);}while(!KEY6){buzzerSound(ToneList[tone][6],7-3*vol);}buzzerQuiet();}while(mode == RECORD){LCD_SHOW(tab0,tab1);if(!startflag){finishflag=0;psite=0;key = KEY_Scan(0);sprintf((char *)tab0,"   RECORD MODE  ");sprintf((char *)tab1,"  Key0 to Start ");LCD_SHOW(tab0,tab1);if(key == KEY0_PRES){startflag=1;sprintf((char *)tab1,"  Come On! GO!  ");}if(key == KEY13_PRES){if(relen)musicPlayRE(relen);else{sprintf((char *)tab1,"  NO RECORDED  ");LCD_SHOW(tab0,tab1);delay_ms(1000);}}delay_ms(5);break;}if(finishflag)startflag=0;key = KEY_Scan(0);switch(key){case KEY13_PRES:finishflag=1;sprintf((char *)tab1,"  RECORD FINISH ");RecordScord[psite+1].mName=0;RecordScord[psite+1].mTime=0;LCD_SHOW(0,tab1);delay_ms(1000);break;case KEY12_PRES:tone = (tone+1)%3;break;}RecordScord[psite].mName=0;RecordScord[psite].mTime=0;reflag=0;while(!KEY0){buzzerSound(ToneList[tone][0],1);reflag=1;RecordScord[psite].mName=ToneList[tone][0];RecordScord[psite].mTime++;delay_ms(1);}while(!KEY1){buzzerSound(ToneList[tone][1],1);reflag=1;RecordScord[psite].mName=ToneList[tone][1];RecordScord[psite].mTime++;delay_ms(1);}while(!KEY2){buzzerSound(ToneList[tone][2],1);reflag=1;RecordScord[psite].mName=ToneList[tone][2];RecordScord[psite].mTime++;delay_ms(1);}while(!KEY3){buzzerSound(ToneList[tone][3],1);reflag=1;RecordScord[psite].mName=ToneList[tone][3];RecordScord[psite].mTime++;delay_ms(1);}while(!KEY4){buzzerSound(ToneList[tone][4],1);reflag=1;RecordScord[psite].mName=ToneList[tone][4];RecordScord[psite].mTime++;delay_ms(1);}while(!KEY5){buzzerSound(ToneList[tone][4],1);reflag=1;RecordScord[psite].mName=ToneList[tone][4];RecordScord[psite].mTime++;delay_ms(1);}while(!KEY6){buzzerSound(ToneList[tone][6],1);reflag=1;RecordScord[psite].mName=ToneList[tone][6];RecordScord[psite].mTime++;delay_ms(1);}buzzerQuiet();if(reflag){psite++;relen=psite+1;sprintf((char *)tab1,"P=%d key13 over  %c",psite,ToneName[tone]);if(psite>98){finishflag=1;sprintf((char *)tab1,"   SCORD FULL  ");RecordScord[psite+1].mName=0;RecordScord[psite+1].mTime=0;LCD_SHOW(0,tab1);delay_ms(1000);}}}while(mode == PLAYER){sprintf((char *)tab0,"   PLAYER MODE   ");sprintf((char *)tab1,"  Key13 to start ");LCD_SHOW(tab0,tab1);key = KEY_Scan(0);switch(key){case KEY13_PRES:nextsong(1,0);break;case 0://  musicPlay(Score1,0);break;case 1:musicPlay(Score2,1);break;case 2:musicPlay(Score3,2);break;case 3:musicPlay(Score4,3);break;case 4:musicPlay(Score5,4);break;case 5:musicPlay(Score6,5);break;case 6:musicPlay(Score7,6);break;case 7:musicPlay(Score8,7);break;}}}}
void LCD_SHOW(u8* tab0,u8* tab1)
{if(tab0)LCD1602_Show_Str(0, 0, tab0);if(tab1)LCD1602_Show_Str(0, 1, tab1);
}void musicPlayRE(int len)
{void play_node(int tone,int time);u8 i=0;int playflag=1;while((RecordScord[i].mName||RecordScord[i].mTime)&&playflag&&mode==1){key = KEY_Scan(0);switch(key){case KEY13_PRES:playflag=0;break;case KEY12_PRES:vol=(vol+1)%3;//0~2循环break;case KEY11_PRES:speed=(speed+1)%4;break;}if(pauseflag){play_node(RecordScord[i].mName,RecordScord[i].mTime);i++;}playstate(12*i/len,'R');LCD_SHOW(0,tab1);}
}

第三章 系统调试

3.1 仿真调试

​ 本设计利用 Keil uVsion5进行程序编写,编译,调试,生成 .hex文件,在Proteus中进行原理图绘制,然后把 .hex文件下载到STM32F103RBT6中 进行仿真。 由于网络上 下载的 Proteus中 没有 STM32F103RBT6这个芯片型号,我们又从网上 下载芯片 进行仿真。

3.2 仿真结果

​ 仿真并没有取得预期结果,分析原因可能是因为仿真所使用的系统频率过低,没法实现正常的要求,所以未达到预期效果。

3.3 实际电路调试

​ 在搭建好实际电路后,各项功能均可正常工作。

​ 同时,根据需要用孔板焊接了一套按键键盘。

3.4 功能测试

  1. 单片机下载完成后,显示Mode Selection Please Press 1-3表示初始化完成等待选择模式
  2. 按下key1,进入Piano模式,可以开始弹奏。
  3. 按下key13可进行音量调节,key12可以调节音调
  4. 按下key8切换模式,进入录音模式
  5. 录音模式下,按key0进行开始录音
  6. 录音会记录音调以及持续时间,按下key13停止录音
  7. 录音完成后按下key13放音,可以听到记录的曲子
  8. 按下key13切换模式进入播放器模式
  9. 可以通过key0-key7选择曲目,也可以直接按key13开始播放
  10. 播放时,按下key13下一首,key12调音量,key11调速度,key10调节下一首模式,key9可暂停
  11. 播放时有进度条显示

至此,所有功能均无错误。

3.5 过程中遇到的问题

​ 在设计时,一开始选择使用面包板搭建外围电路,但是发现过于臃肿,所以自己焊接了一块按键键盘,便于操作。

​ 在软件设计时,各种全局变量在不同函数之间的传递,导致逻辑十分混乱,通过画图,慢慢的理清逻辑修改bug

第四章 总结

​ 本设计以实际电路为最后的结果,实现了所有与其功能,具有重要的现实意义。

件,在Proteus中进行原理图绘制,然后把 .hex文件下载到STM32F103RBT6中 进行仿真。 由于网络上 下载的 Proteus中 没有 STM32F103RBT6这个芯片型号,我们又从网上 下载芯片 进行仿真。

3.2 仿真结果

​ 仿真并没有取得预期结果,分析原因可能是因为仿真所使用的系统频率过低,没法实现正常的要求,所以未达到预期效果。

3.3 实际电路调试

​ 在搭建好实际电路后,各项功能均可正常工作。

​ 同时,根据需要用孔板焊接了一套按键键盘。

[外链图片转存中…(img-mnecOLco-1632967473029)]

3.4 功能测试

  1. 单片机下载完成后,显示Mode Selection Please Press 1-3表示初始化完成等待选择模式
  2. 按下key1,进入Piano模式,可以开始弹奏。
  3. 按下key13可进行音量调节,key12可以调节音调
  4. 按下key8切换模式,进入录音模式
  5. 录音模式下,按key0进行开始录音
  6. 录音会记录音调以及持续时间,按下key13停止录音
  7. 录音完成后按下key13放音,可以听到记录的曲子
  8. 按下key13切换模式进入播放器模式
  9. 可以通过key0-key7选择曲目,也可以直接按key13开始播放
  10. 播放时,按下key13下一首,key12调音量,key11调速度,key10调节下一首模式,key9可暂停
  11. 播放时有进度条显示

至此,所有功能均无错误。

3.5 过程中遇到的问题

​ 在设计时,一开始选择使用面包板搭建外围电路,但是发现过于臃肿,所以自己焊接了一块按键键盘,便于操作。

​ 在软件设计时,各种全局变量在不同函数之间的传递,导致逻辑十分混乱,通过画图,慢慢的理清逻辑修改bug

第四章 总结

​ 本设计以实际电路为最后的结果,实现了所有与其功能,具有重要的现实意义。

基于STM32的电子琴音乐播放器设计相关推荐

  1. 【毕业设计】基于单片机的MP3音乐播放器设计与实现 - stm32 物联网 c51

    文章目录 1 简介 2 绪论 2.1 课题背景与目的 3 系统设计 3.1 系统架构 3.2 软件部分设计 3.3 实现效果 3.4 部分相关代码 4 最后 1 简介 Hi,大家好,这里是丹成学长,今 ...

  2. 【毕业设计_课程设计】基于安卓APP的音乐播放器设计

    文章目录 0 项目说明 1 模块设计架构 2 界面效果 3 项目源码 0 项目说明 基于安卓APP的音乐播放器设计 提示:适合用于课程设计或毕业设计,工作量达标,源码开放 1 模块设计架构 1.音乐播 ...

  3. 基于STM32制作的音乐播放器,用PWM控制蜂鸣器

    目录 效果展示 前言 一.设计背景 1.1.知识储备 二.系统设计方案 2.1.实现功能 2.2.硬件部分 2.3.软件部分 三.软件设计 3.1.设计流程图 3.2.音乐频率的设置 3.3.编程主要 ...

  4. 基于android平台多媒体播放器的设计与实现,基于Android的多媒体音乐播放器设计论文...

    中图分类号:TP317 文献标识码:A 文章编号:1009-3044(2016)03-0240-02 随着计算机网络与手机的迅速发展,各种音乐资源成为人们生活中必不可少的一部分,音乐播放软件成了手机必 ...

  5. 基于嵌入式linux的音乐播放器设计,基于嵌入式Linux的多媒体音乐播放器的设计与实现...

    中图分类号:TP316.5 文献标识码:A 文章编号:1009-2552(2009)06-0102-03 基于嵌入式Linux的多媒体音乐播放器的设计与实现 王 奇 (黑龙江八一农垦大学信息技术学院, ...

  6. 【毕业设计】Stm32单片机的音乐播放器设计 - 物联网 嵌入式

    文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 设计原理 5 部分核心代码 6 最后 0 前言

  7. android音乐播放器课程设计报告,基于AS3.0的音乐播放器设计课程设计报告.doc

    paraB.timer) { return 1; } if (paraA.timerplayList.song.length() - 1) { currentSound = 1; } playList ...

  8. android 音乐播放器设计,基于Android音乐播放器设计的实现毕业论文.pdf

    摘要 随着手机的智能化以及网络的普及和应用,人类将进入移动互联 网的新时代.在国内,随着4G牌照的下发,三大运行商也在加紧抢 占移动互联网领域的制高点.在此过程中,人们对新一代移动互联终 端设备的功能 ...

  9. 毕业设计 嵌入式 MP3音乐播放器设计与实现

    文章目录 1 简介 2 绪论 2.1 课题背景与目的 3 系统设计 3.1 系统架构 3.2 软件部分设计 3.3 实现效果 3.4 部分相关代码 4 最后 1 简介 Hi,大家好,学长今天向大家介绍 ...

最新文章

  1. 象 DEV-Club 那样的彩色校验码
  2. mysql数据导入导出方法总结
  3. .git文件夹_将Git存储库中的文件夹转换为全新的存储库
  4. 华为ac控制器web配置手册_家庭WIFI网络规划设计与配置实战,一文教会你
  5. 搭建分布式 ASP.NET Core Web
  6. [转载] Java对返回值的封装
  7. C++函数的分文件编写
  8. 安装配置管理 之 JRE 安装和配置,以适合JAVA程序运行所具备的环境
  9. 毕设题目:Matlab肌电信号
  10. vi中跳到首行或尾行
  11. Python3网络爬虫之requests静态爬虫:链家深圳二手房
  12. Oracle Class6-1. PL/SQL 简介(数据类型,逻辑比较,控制结构,错误处理)
  13. neko虚拟机对象文档与扩充
  14. python unicode转换
  15. OC 主线程刷新UI
  16. 万年历C语言程序可参考的文献,万年历的c语言程序
  17. 2022年全球及中国公务汽车轮胎行业头部企业市场占有率及排名调研报告
  18. 数理统计笔记7:分类数据分析-拟合优度检验和列联分析
  19. IOS SDK详解之拍照/相册(默认+自定义拍照界面)
  20. 深入理解Linux内核 学习Linux内核的一些建议及书记推荐

热门文章

  1. 0xfffffff1 lr_CortexM处理器的一些特性记录
  2. java五子棋聊天功能_Java基于享元模式实现五子棋游戏功能实例详解
  3. 新鲜出炉 日常家用电器电磁辐射危险排行榜(iPad3 iMac)
  4. 爬虫_西电研究生教务系统_技术文档
  5. 科技公司的域名大战!
  6. Canonical Juju 使用笔记
  7. I - Por Costel and the Pairs Gym - 100923I _思维啊——可惜我现在还没
  8. 黑洞猝灭剂BHQ-2 acid,1214891-99-2,BHQ-2 Carboxylic Acid用作各种荧光共振能量转移,这种探针主要用于分析。
  9. Python数据分析示例(2)Day3
  10. 【怀旧】80后,难忘童年----100部最经典的电视连续剧