欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
注釋詳細的51單片機電子琴的仿真和程序 內含多種音樂,可以自己調節
[打印本頁]
作者:
張小巖zz
時間:
2023-4-29 14:47
標題:
注釋詳細的51單片機電子琴的仿真和程序 內含多種音樂,可以自己調節
51電子琴的設計 內含多種音樂,可以自己調節
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei瀏覽器截圖20230429144554.png
(85.91 KB, 下載次數: 57)
下載附件
2023-4-29 14:46 上傳
帶注釋的單片機源程序如下:
#include <reg52.h>
#define SONG 4 // 歌曲的數量
#define uchar unsigned char // 以后unsigned char就可以用uchar代替
#define uint unsigned int // 以后unsigned int 就可以用uint 代替
#define ulong unsigned long // 以后unsigned long就可以用ulong代替
sbit Key1_P = P1^3; // 彈奏鍵1的管腳
sbit Key2_P = P1^7; // 彈奏鍵2的管腳
sbit Key3_P = P3^2; // 彈奏鍵3的管腳
sbit Key4_P = P3^3; // 彈奏鍵4的管腳
sbit Key5_P = P1^2; // 彈奏鍵5的管腳
sbit Key6_P = P1^6; // 彈奏鍵6的管腳
sbit Key7_P = P3^1; // 彈奏鍵7的管腳
sbit Key8_P = P3^5; // 彈奏鍵8的管腳
sbit Key9_P = P1^4; // 播放內置歌曲的按鍵管腳
sbit Beep_P = P2^7; // 揚聲器管腳
uchar gTone=0; // gTone代表當前要播放的音調
uchar gPlayStatus; // gPlayStatus代表當前的播放狀態,0是停止,1是播放
uchar gSong; // gSong代表當前播放到第幾首歌
/* 定時器初值 低1 低2 低3 低4 低5 低6 低7 中1 中2 中3 中4 中5 中6 中7 高1 高2 高3 高4 高5 高6 高7 */
uchar code ArrTL0[]={ 140, 91, 21, 103, 4, 144, 12, 68, 121, 220, 52, 130, 200, 6, 34, 86, 133, 154, 193, 228, 3 };
uchar code ArrTH0[]={ 248, 249, 250, 250, 251, 251, 252, 252, 252, 252, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 255 };
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* 數碼管的顯示值 1 2 3 4 5 6 7 */
uchar code ArrDig[]={ 0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};
/* 《水手》的樂譜 */
uchar code Music1[]={
8,3, 7,1, 7,4
} ;
/********************************************************************
* 名稱 : uchar ChangeFor(uchar dat)
* 功能 : 交換一個字節位的位置,用于數碼管顯示
* 輸入 : 需要改變的數
* 輸出 : 改變后的數
***********************************************************************/
#define LED_a 6 //數碼管段選的a段接在段選IO口的第0位
#define LED_b 7
#define LED_c 5
#define LED_d 3
#define LED_e 2
#define LED_f 1
#define LED_g 0
#define LED_dp 4
uchar ChangeFor(uchar dat)
{
uchar temp=0;
if(dat&0x01) //判斷數據的第一位是否為1
temp|=0x01<<LED_a;//如果為1,放到控制數碼管a段的位置
if(dat&0x02)
temp|=0x01<<LED_b;
if(dat&0x04)
temp|=0x01<<LED_c;
if(dat&0x08)
temp|=0x01<<LED_d;
if(dat&0x10)
temp|=0x01<<LED_e;
if(dat&0x20)
temp|=0x01<<LED_f;
if(dat&0x40)
temp|=0x01<<LED_g;
if(dat&0x80)
temp|=0x01<<LED_dp;
return temp;
}
/*********************************************************/
// 毫秒級的延時函數,time是要延時的毫秒數
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=time;i>0;i--)
for(j=110;j>0;j--);
}
/*********************************************************/
// 發出指定音調及其節拍的聲音,tone代表音調,beat代表節拍
/*********************************************************/
void PlayTone(uchar tone,float beat)
{
int i;
P0=ChangeFor(ArrDig[tone%7]); // 數碼管顯示當前音調值
gTone=tone; // 將音調值賦給全局變量gTone
TH0 = ArrTH0[tone]; // 裝入定時器TH0的初值
TL0 = ArrTL0[tone]; // 裝入定時器TL0的初值
TR0=1; // 啟動定時器
for(i=0;i<beat;i++)
{
DelayMs(200);
}
TR0=0; // 停止定時器
P0=0xff; // 關閉數碼管顯示
}
/*********************************************************/
// 播放內置的音樂
// arr[]是要播放的樂譜數組,num是數組里面的元素個數
/*********************************************************/
void PlayMusic(uchar music[],uint num)
{
uint i=0;
while(i<num)
{
if(gPlayStatus==1) // 判斷播放狀態是否為播放還是暫停
{
PlayTone(music[i],music[i+1]); // 開始演奏一個節拍
i+=2; // 進入下一個節拍,因為每2個數為1組,所以每次要加2
if(i==num) // 判斷歌曲是否播放完了
{
gPlayStatus=0; // 播放完了的話,則把播放狀態改為暫停,否則會循環播放
}
}
if(Key9_P==0) // 下一曲
{
DelayMs(10); // 消除按鍵按下的抖動
while(!Key9_P); // 等待按鍵釋放
DelayMs(10); // 消除按鍵松開的抖動
gSong++; // 把當前播放到第幾首歌的變量gSong加1,即切到下一曲
if(gSong>SONG) // 如果gSong為SONG,說明到后面的盡頭了,則轉為第一首
gSong=1;
break;
}
}
}
/*********************************************************/
// 定時器初始化函數
/*********************************************************/
void TimerInit()
{
TMOD=1; // 定時器0,工作方式1
TH0=0; // 裝定時器TH0的初值
TL0=0; // 裝定時器TL0的初值
ET0=1; // 開啟定時器0中斷
EA=1; // 開啟總中斷
}
/*********************************************************/
// 彈奏鍵掃描函數
/*********************************************************/
uchar KeyScanf()
{
if(Key1_P==0) // 按鍵1被按下,返回1
return 1;
if(Key2_P==0) // 按鍵2被按下,返回2
return 2;
if(Key3_P==0) // 按鍵3被按下,返回3
return 3;
if(Key4_P==0) // 按鍵4被按下,返回4
return 4;
if(Key5_P==0) // 按鍵5被按下,返回5
return 5;
if(Key6_P==0) // 按鍵6被按下,返回6
return 6;
if(Key7_P==0) // 按鍵7被按下,返回7
return 7;
if(Key8_P==0) // 按鍵8被按下,返回8
return 8;
return 0; // 8個按鍵都沒被按下,返回0
}
/*********************************************************/
// 主函數,程序從這里開始執行
/*********************************************************/
void main()
{
uchar ret; // 用于保存音調鍵函數的返回值
TimerInit();
gSong=0; // 上電默認第一首歌
gPlayStatus=0; // 上電默認是0停止狀態(1為播放狀態)
while(1)
{
if(gPlayStatus==1) // 如果處于播放狀態,則判斷是哪一首歌曲需要播放
{
switch(gSong)
{
case 1 : PlayMusic(Music1,sizeof(Music1)); break;
case 2 : PlayMusic(Music2,sizeof(Music2)); break;
case 3 : PlayMusic(Music3,sizeof(Music3)); break;
case 4 : PlayMusic(Music4,sizeof(Music4)); break;
default: break;
}
}
if(Key9_P==0) // 開始播放
{
DelayMs(10); // 消除按鍵按下的抖動
while(!Key9_P); // 等待按鍵釋放
DelayMs(10); // 消除按鍵松開的抖動
gSong++; // 把當前播放到第幾首歌的變量gSong加1,即切到下一曲
if(gSong>SONG) // 如果gSong為SONG,說明到后面的盡頭了,則轉為第一首
gSong=1;
gPlayStatus=1; // 播放狀態改為1,即播放
}
ret=KeyScanf();
if(ret!=0)
{
P0=ChangeFor(ArrDig[(ret-1)%7]); // 數碼管顯示當前音調值
TH0 = ArrTH0[ret+6]; // 裝入定時器TH0的初值
TL0 = ArrTL0[ret+6]; // 裝入定時器TL0的初值
gTone=ret+6;
TR0=1;
while(KeyScanf()); // 等待按鍵釋放
DelayMs(70); // 按鍵釋放之后,再播放70毫秒,達到余音的效果
TR0=0; // 停止定時器
P0=0xff; // 關閉數碼管顯示
}
}
}
/*********************************************************/
// 功能:定時器0中斷處理函數
/*********************************************************/
void time0() interrupt 1
{
Beep_P=!Beep_P; // 將控制揚聲器的管腳取反
TH0=ArrTH0[gTone]; // 重裝定時器TH0的初值
TL0=ArrTL0[gTone]; // 重裝定時器TL0的初值
}
復制代碼
Keil代碼與Proteus仿真下載:
01__c程序 注釋.zip
(128.94 KB, 下載次數: 32)
2023-4-29 14:46 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1