摘要: 本次設計是課程設計,利用單片機設計簡易電子琴。 其主要功能為:按下不同按鍵,發出不同1 、2 、3、4 、5 、6 、7 七個音符并且用LED 或LCD顯示當前按鍵。選用stm32f103C8T6,它有8個定時器,部分定時器有多達4個用于輸入捕獲/輸出比較/PWM或脈沖計數的通道和增量編碼器輸入。利用芯片內部相關定時器來輸出PWM,從而來驅動蜂鳴器。通過讀取外部按鍵輸入的值來相應改變定時器相關寄存器的值,從而來改變PWM的輸出頻率來達到發出不同音調。
一、設計目的和意義
本綜合設計是為本科生開設的必修課,是對學生運用所學知識的一次綜合訓練。其目的是讓學生得到一次進行獨立設計的工程實踐鍛煉,不僅培養嚴謹的科學態度和扎實的實踐技能、良好的工程意識,并在設計中學會如何發現、分析和解決工程實踐問題的技能和方法,將所學知識綜合應用于工程實踐中,為后續的畢業設計做好準備。
二、控制要求
利用單片機設計簡易電子琴。
功能要求:
(1) 按下不同按鍵,發出不同1 、2 、3、4 、5 、6 、7 七個音符;
(2) 用LED 或LCD顯示當前按鍵。
總體要求:給出電路原理圖、電路調試結果、程序源代碼;提交設計報告。
三、設計方案論證
3.1 設計方案:
方案一:采用MCS-51系列單片機來實現設計要求的功能。 MCS-51系列單片機中的基本型產品是8051,8031和8751,這三個產品只是片內程序存儲器制造工藝不同。8051的片內程序存儲器ROM為掩膜型的在制造芯片時已將應用程序固化進去,使它具有了某種專用功能。8位CPU擁有片內震蕩器及時鐘電路;32根IO線;外部存儲器ROM和RAM尋址范圍各64KB;2個16位的定時器/計數器;5個中斷源,2個中斷優先級;全雙工串行口;8051的中央處理器CPU由運算器和控制邏輯構成51單片機是一款比較基礎的單片機。I/O(輸入/輸出)引腳系統結構緊湊,功能簡單,低成本。可以實現各種豐富的應用。通過控制I/O口的輸出電平的翻轉頻率來實現對蜂鳴器發音音調的控制。
方案二:采用STM32f03C8T6來實現此次設計,最高72MHz工作頻率。它有多個外部中斷,八個定時器,有PWM輸出模式,其中2個高級定時器,兩個基本定時器,其他的是通用定時器,共48個引腳,除基本的I/O功能之外還包含有復用功能,其外設功能強大,是一款能夠很方便使用的功能強大的芯片,同時可以直接對相關寄存器進行操作,。
3.2 方案選擇
上述兩種方案相比,51單片機雖然價格便宜,但是其功能簡單,I/O口少,并且僅僅只有5個中斷源,而STM32f03C8T6共48個引腳,并且其定時器有PWM輸出模式,可以更加方便的控制蜂鳴器的發音。本次設計包括了七個按鍵,數碼管,蜂鳴器,因此至少需要17個I/O口。因此先比較而言選用I/O口較多的STM32f03C8T6來作為控制芯片。
四、系統設計
4.1 硬件結構設計
如圖4-1所示,硬件系統主要由數碼管顯示電路、蜂鳴器驅動電路、按鍵電路、晶振、復位、電源指示、轉壓電路、控制芯片等組成。
圖4-1 硬件系統圖
4.1.1 核心控制器硬件電路
核心控制芯片的各個輸出引腳如圖4-2所示:
圖4-2 STM32f103C8T6引腳圖
核心控制器是由核心控制芯片以及相關的外圍電路組成,包括了專業電路、外部晶振、濾波電路、按鍵復位電路、電源指示電路等,如圖4-3所示。
圖4-3核心控制器外圍電路
4.1.2 蜂鳴器驅動電路
此次設計選用有源蜂鳴器。有源蜂鳴器的發聲原理是電流通過電磁線圈,使電磁線圈產生磁場來驅動振動膜發音,因此需要一定的電流才能驅動它。單片機的I/O引腳的輸出電流比較小輸出的TTL電平基本上驅動不了蜂鳴器,因此需要增加一個電流放大的電路,如圖4-4所示,選用NPN的三極管來達到電流放大的作用。
圖4-4 蜂鳴器驅動電路
4.1.3 數碼管電路:
設計中需要使用一位數碼管,如圖4-5所示,為四位數碼管的驅動電路,在實際的運用中僅僅選用了com4位選端口以及5、6、7、8、9、10、11、接口作為段選。
圖4-5 數碼管顯示電路
4.1.4按鍵電路:
按鍵都采用了上拉電阻,當按鍵處于不被按下的狀態時,連接到單片機的一端的輸入信號為高電平,當按鍵按下時,輸入為低電平,如圖4-6所示。
圖4-6 按鍵電路
4.2 軟件系統設計
4.2.1 軟件系統框圖
設計選用STM32F103C8T6芯片,相關的配置主要包括:,時鐘配置、I/O口配置、定時器配置。主函數中進行顯示參數以及PWM輸出頻率的改變,具體流程圖如圖4-7所示。
圖4-7 軟件流程圖
4.2.2 數碼管顯示相關段選計算:
在此次設計中選用的是共陰極的數碼管,段選為高電平有效,位選為低電平有效。選用STM32f103C8T6的PB0、1、2、.10、11、12、13、14作為段選位,分別對應數碼管的h、g、f、e、d、c、b、a段,PB15對應數碼管的位選。
圖4-8 一位數碼管
當數碼管顯示0時,選用a、b、c、d、e、f、.段,對應的十六進制為:0x7c04;
當數碼管顯示1時,選用b.、c.段,對應的十六進制為:0x7c04;
當數碼管顯示2時,選用a、b、g、e、d.段,對應的十六進制為:0x7c04;
當數碼管顯示3時,選用a、b、g、c、d.段,對應的十六進制為:0x7c04;
當數碼管顯示4時,選用f、g、b、c.段,對應的十六進制為:0x7c04;
當數碼管顯示5時,選用a、f、g、c、d段,對應的十六進制為:0x7c04;
當數碼管顯示6時,選a、f、e、g、d、c.段,對應的十六進制為:0x7c04;
當數碼管顯示7時,選用a、b、c.段,對應的十六進制為:0x7c04;
4.2.3 蜂鳴器發音音調改變原理
蜂鳴器分為有源蜂鳴器合無源蜂鳴器。有源蜂鳴器內部帶震蕩源,所以只要一通電就會叫,價格比無源貴。無源蜂鳴器必須用2K-5K的方波去驅動它。此次設計選用有源蜂鳴器。有源蜂鳴器的發聲原理是電流通過電磁線圈,使電磁線圈產生磁場來驅動振動膜發音,因此需要一定的電流才能驅動它。單片機的I/O引腳的輸出電流比較小輸出的TTL電平基本上驅動不了蜂鳴器,因此需要增加一個電流放大的電路。如圖4-4所示蜂鳴器的正極接到VCC(+5V)電源上面,蜂鳴器的負極接到三極管的發射極E,三極管的基級B經過限流電阻R1后由單片機引腳控制,當單片機引腳輸出高電平時,三極管T1截止,沒有電流流過線圈,蜂鳴器不發聲;當單片機引腳輸出低電平時,三極管導通,這樣蜂鳴器的電流形成回路,發出聲音。因此,我們可以通過程序控制引腳的電平來使蜂鳴器發出聲音和關閉。
蜂鳴器是的音調改變實際上是通過改變驅動蜂鳴的高低電平的翻轉頻率來決定,高低電平的變化的頻率不同,音調不同,在此次設計中采用TIM1的PWM的頻率變化來控制。
4.2.4 PWM輸出頻率計算:
TIM定時器相關配置:
void TIM_yingyue(unsigned int NoteSet)
{
static unsigned char IfIsInit=0;
if(IfIsInit==0)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseStructure.TIM_Period = NoteSet;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = NoteSet/2;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High ;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_Cmd(TIM1,ENABLE);
IfIsInit=1;
}
else
{
TIM1- >ARR=NoteSet;
TIM1- >CCR1=NoteSet/2;
}
}
TIM_Period 設置了在下一個更新事件裝入活動的自動重裝載寄存器周期的值。
TIM_Prescaler:設置了用來作為TIM1時鐘頻率除數的預分頻值。
TIM_CounterMode 選擇了計數器模式為向上計數模式。
TIM_OCMode選擇定時器模式為TIM 脈沖寬度調制模式 1。
.TIM_OutputState = TIM_OutputState_Enable定時器輸出比較狀態使能。
TIM_Pulse 設置了待裝入捕獲比較寄存器的脈沖值和TIM_Period的值一起決定占空比。
TIM_OCPolarity 設置了輸出比較極性為高。
根據以上設置
(4-1)
(4-2)
在主函數中,通過掃描按鍵的狀態來執行相關操作:
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)==0)
{
display(1); //數碼管顯示函數
TIM_yingyue(D1); //調用定時器函數
}
注: 每次調用TIM_yingyue()函數,通過判斷IfIsInit的狀態,直接通過修改ARR(自動重裝載寄存器),CCR1(TIM1捕獲/比較寄存器1)來修改頻率,提高了程序的效率,避免其他相關值重復定義。
五、設計結果及分析
5.1設計結果:
實現了簡易電子琴功能。 按下不同按鍵,發出不同1 、2 、3、4 、5 、6 、7 七個音符并用LED顯示當前的鍵值。每個音符發音的長短由按鍵按下的時間長短來控制,能夠更好的完成一首歌曲。
PWM輸出波形下列各圖所示:
DO:
圖5-1 Do PWM輸出波形
Rai:
圖5-2 Rai PWM輸出波形
Mi:
圖5-3 Mi PWM輸出波形
Fa:
圖5-4 Fa PWM輸出波形
So:
圖5-5 So PWM輸出波形
La:
圖5-6 La PWM輸出波形
Xi:
圖5-7 Xi PWM輸出波形
5.2結果分析:
初次軟硬件聯調的時候,蜂鳴器發出的音符雖然也是七個調,但是聲音明顯不清脆。結合軟件分析,當時的TIM_yingyue()函數里面有很多關于定時器和PWM的參數的定義,改變頻率只與其中兩個寄存器有關系,而每次調用這個函數的時候會把整個函數中德參數全部重新賦值,導致了執行效率不高,對TIM_yingyue()函數進行修改,通過判斷IfIsInit的狀態,直接修改ARR(自動重裝載寄存器),CCR1(TIM1捕獲/比較寄存器1)來到到改變頻率的效果,提高了程序的效率,避免其他相關值重復定義。再次進行聯調時,整個聲音也就清楚了很多。在按鍵的掃描方面放棄最初開始想要使用的外部中斷觸發的方式,一方面是為了能夠更加簡單的完成此次設計,另一方面是為了實現發音的長短可以用按鍵按下的時間長短來決定,使之更加具備電子琴的功能,能夠很好的完成一首曲子。
結束語
通過本次專業方向設計,我不僅加深了對單片機理論的理解,將理論很好地應用到實際當中去,而且我還學會了如何去培養我們的創新精神,從而不斷地戰勝自己,超越自己。創新可以是在原有的基礎上進行改進,使之功能不斷完善,成為真己的東西。 這個設計過程中,通過在原有的按鍵中斷的基礎上進行了改進,使之具備了電子琴的基本功能。設計結果能夠符合題意,成功完成了此次實習要求,我不只在乎這一結果,更加在乎的,是這個過程。這個過程中,自己更加注重了一些基礎的理知識的學習,很好的把平時課堂上的知識運用到了實際的操作中。同時,軟硬件的結合調試也讓自己明白了理論上的很多東西也是需要實際實驗的驗證的。本綜合設計是讓得到一次進行獨立設計的工程實踐鍛煉,不僅培養嚴謹的科學態度和扎實的實踐技能、良好的工程意識,并在設計中學會如何發現、分析和解決工程實踐問題的技能和方法,為后續的畢業設計做好準備。同時在這里也感謝在整個設計中幫助過我的老師和同學們。
附錄1:程序代碼
#include"stm32f10x.h"
unsigned int i=0;
unsigned int j=0;
unsigned int mykey=0;
unsignedlong code[10]={0x7c04,0x3000,0x6c02,0x7802,0x3006,0x5806,0x5c06,0x7000,0x7c06
,0x7806};
//數組里面的16進制正好對應著顯示0-9的二進制碼(數碼管的位選,選擇哪一位就讓相關位為1,來表示選擇了它)
#define D1 55042
#define D2 49037
#define D3 43687
#define D4 41235
#define D5 36735
#define D6 32728
#define D7 29157
void RCC_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO
|RCC_APB2Periph_TIM1|RCC_APB2Periph_GPIOB,ENABLE); //APB2時鐘是72MHz的,APB1的時鐘是36MHz的
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure ; //蜂鳴器
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8; //選擇PA8
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //復用功能,PA8作為復用是TIM1的PWM1的輸出端口,不再作為一個普通的I/O口使用
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_5|GPIO_Pin_4|GPIO_Pin_15;
//按鍵的幾個輸入引腳
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉輸入
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin =0x7C07; //數碼管段選and位選
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_10MHz; //
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP; //推挽輸出
GPIO_Init(GPIOB,&GPIO_InitStructure); //表示選擇的是PB的引腳
}
void TIM_yingyue(unsigned int NoteSet)
{
static unsigned char IfIsInit=0;
if(IfIsInit==0)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = NoteSet; //設置了在下一個更新事件裝入活動的自動重裝載// 寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler = 0; //設置了用來作為TIM1時鐘頻率除數的預分頻值
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//選擇了計數器模式為向上計數模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //選擇定時器模式為TIM 脈沖寬度調制模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //定時器輸出比較狀態使能
TIM_OCInitStructure.TIM_Pulse = NoteSet/2; //設置了待裝入捕獲比較寄存器的脈沖值和TIM_Period的值一起決定占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High ; //設置了輸出比較極性為高
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM1,ENABLE); //TIM1的PWM輸出使能
TIM_Cmd(TIM1,ENABLE); //Tim1定時器使能
IfIsInit=1;
}
else
{
TIM1- >ARR=NoteSet; //改變輸出的頻率
TIM1- >CCR1=NoteSet/2;
}
}
void delay(unsigned int i) //延時函數
{
unsigned int j,k;
for(j=0;j < i;j++)< span > < /i;j++)< >
for(k=0;k< 100;k++);
}
void display(unsigned int j) //數碼管顯示函數
{
GPIO_SetBits(GPIOB,code[j]);
GPIO_ResetBits(GPIOB,0x001); //共陰極數碼管,段選為高電平有效,位選為低電平有效
}
int main()
{
RCC_Configuration();
GPIO_Configuration() ;
while(1) //按鍵掃描
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)==0)
{
display(1); //修改顯示的數據
TIM_yingyue(D1); //修改輸出的頻率
}
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)==0)
{
display(2);
TIM_yingyue(D2);
}
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0)
{
display(3);
TIM_yingyue(D3);
}
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0)
{
display(4);
TIM_yingyue(D4);
}
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0)
{
display(5);
TIM_yingyue(D5);
}
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8)==0)
{
display(6);
TIM_yingyue(D6);
}
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==0)
{
display(7);
TIM_yingyue(D7);
}
else
{
TIM_yingyue(0); //無按鍵按下的時候不顯示,不發音
GPIO_SetBits(GPIOB,0x0001);
GPIO_ResetBits(GPIOB,0x7C06);
}
}
}
附錄2:核心版原理圖及PCB
小系統原理圖:
核心版原理圖:
-
單片機
+關注
關注
6043文章
44617瀏覽量
638257 -
lcd
+關注
關注
34文章
4438瀏覽量
168325 -
STM32
+關注
關注
2272文章
10923瀏覽量
357427 -
蜂鳴器
+關注
關注
12文章
893瀏覽量
46085 -
電子琴
+關注
關注
4文章
153瀏覽量
30634
發布評論請先 登錄
相關推薦
評論