基于STM32的电子琴音乐播放器设计 您所在的位置:网站首页 单片机电子琴的原理 基于STM32的电子琴音乐播放器设计

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

2024-06-06 19:54| 来源: 网络整理| 查看: 265

基于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 系统功能

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

共有三个基本模式:电子琴模式、录音模式、播放器模式电子琴模式下,7个基本按键控制产生7种音调,功能键实现调节音阶和音量录音模式可分为录音和放音两个模块,录音状态下会记录弹奏的音调以及时间;放音模式调用音乐播放器某些模块,实现相同的功能。音乐播放器模块下,可以实现音乐的播放、暂停、切歌、调速、顺序播放、单曲循环、随机播放、以及进度条显示。有两个全局按键中断,可控制模式切换和全局静音/暂停。 1.2 主要技术性能指标 基本按键:7个;功能按键:6个;全局中断按键:2个;扬声器:1个;扬声器功率:1w;LCD1602:1块;主要模式:3个;曲库:8首;音域范围:262Hz~2217Hz;音量阶数:3阶;速度阶数:4阶;循环模式: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 显示模块

LCD模块

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

2.2.5 主控模块

STM32f103rbt6芯片

2.3 软件设计 2.3.1 主要工作原理

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

​ 相关流程图如下:

Created with Raphaël 2.3.0 开始 各模块初始化 模式选择输入 模式=1? 钢琴模式 模式=2? 录音模式 模式=3? 播放器模式 等待模式选择 yes no yes no yes no 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; //定时器1 TIM3_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); //初始化PWM TIM3_CH2Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1 TIM3_CH2Handler.Pulse=arr/2; //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50% TIM3_CH2Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低 HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH2Handler,TIM_CHANNEL_2);//配置TIM3通道2 HAL_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; //PC6 GPIO_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((usFraq20000)) { 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、PC9 GPIO_Initure.Mode=GPIO_MODE_IT_FALLING; //下降沿触发 GPIO_Initure.Pull=GPIO_PULLUP; HAL_GPIO_Init(GPIOC,&GPIO_Initure); //中断线8、9-PC8、9 HAL_NVIC_SetPriority(EXTI9_5_IRQn,2,1); //抢占优先级为2,子优先级为1 HAL_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的显示函数,通过tab0和tab1的锁存,实现更丰富需求。

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); //设置时钟,72M delay_init(72); //初始化延时函数 uart_init(115200); //初始化串口115200 LCD1602_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 实际电路调试

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

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

屏幕截图 2021-07-16 105801

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

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

3.5 过程中遇到的问题

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

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

第四章 总结

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

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

3.2 仿真结果

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

3.3 实际电路调试

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

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

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

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

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

3.5 过程中遇到的问题

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

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

第四章 总结

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



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有