“无线杯”一等奖作品《钢琴游戏机》(《Piano game machine》)介绍
in 机械/电子/内核
原 创 性 声 明 本团队郑重声明:所呈交的作品及论文,是本团队在指导老师的指导下,独立进行研究所取得的成果。除文中已经注明引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写过的科研成果。对本文的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。本声明的法律责任由本人承担。
快速目录
功能介绍
表情功能:无操作状态下,显示屏显示眨眼表情,显示正常。
游戏模式功能:按下按键即选择乐曲,显示屏先显示曲名,随后将屏幕竖起,屏幕开始掉落“音乐块”,屏幕底部有一条“基准线”,当音乐块的中心落到基准线时,按下对应按键,发出相应声音,同时计分器分数增加。经过多次测试,计分并不完全准确,有时出现分数激增的情况,但总体上不影响使用。
自由弹奏模式:7个按键分别对应Do-Xi的7个声音,另有一个高音键和一个低音键,按下其中一个后再按7个音键能够弹出高音或低音。这部分功能可以完美实现。
系统方案
点阵显示 应用4块8*8 led点阵作为显示屏。
led点阵原理图
按键模块
采用74ls138芯片将8个按键转换成3位输入,以3口接入arduino。
芯片真值表
四位数码管 1至8口接到74hc138转3口输入arduino,9至12口直接接入arduino
数码管图
74hc138原理图和真值表
蜂鸣器 蜂鸣器一段通过电容接地,另一端接arduino端口
arduino 源代码(详细注释)
注意其中的一段while(1)语句,我在里面使用了帧数的概念从而绕过写中断,其中屏幕上其实每一条只会向下五格,然后显示队列出队进队一次,相当于每次屏幕只是显示当前队列 piano.cpp
#include <HT1632.h>
#include <stdlib.h>
HT1632Class LEDmatrix;
#define FAST 30
int RCK=1; //74hc595的11脚
int RCLK=2; //74hc595的12脚
int DS=0; //74hc595的14脚
int L1=3; //数码管的12脚
int L2=4; //数码管的9脚
int L3=5; //数码管的8脚
int L4=6; //数码管的6脚
const unsigned char num[]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
}; //数码管字符表
volatile int key; //可不能优化它
int wm = 0; //那一曲
void keymake() //读取琴键
{
key = ((digitalRead(A3) << 3) + (digitalRead(A2) << 2)) + ((digitalRead(A1) << 1) + digitalRead(A0));
switch (key)
{
case 7:key=0;break;
case 15:key=1;break;
case 14:key=2;break;
case 13:key=3;break;
case 12:key=4;break;
case 11:key=5;break;
case 10:key=6;break;
case 9:key=7;break;
case 8:key=8;break;
}
}
int mn[8] = { 14,49,43,47,49,59,28,1}; // 音乐长度
char music[8][60] = {
{1,2,3,3,2, 1,1,3,2,1, 2 }, //开场
{ 8,8,8,8,8, 8,8, 1,2,3,1,1, 2,3,1,3,4, 5,3,4,5,5, 6,5,4,3,1, 5,6,5,4,3, 1,2,5,1,2, 5,1 ,8,8,8,8,8, 8,8,8,8,8 }, //两只老虎
{ 8,8,8,8,8, 8,8, 5,6,5,4,3, 4,5,2,3,4, 3,4,5,5,6, 5,4,3,4,4, 5,2,5,3,1 ,8,8,8,8,8, 8,8,8,8,8 }, //不知名广东小曲
{ 8,8,8,8,8, 8,8, 3,3,4,5,5, 4,3,2,1,1, 2,3,3,2,2, 3,3,4,5,5, 4,3,2,1,1, 2,3,2,1,1 ,8,8,8,8,8, 8,8,8,8,8 }, //欢乐颂
{ 8,8,8,8,8, 8,8, 5,8,7,0,0, 5,3,6,6,4, 6,0,0,7,6, 5,4,3,3,5, 8,7,0,0,5, 3,6,6,4,6, 0,0 ,8,8,8,8,8, 8,8,8,8,8 }, //国际歌
{ 8,8,8,8,8, 8,8, 1,1,5,5,6, 6,5,4,4,3, 3,2,2,1,5, 5,4,4,3,3, 2,5,5,4,4, 3,3,2,1,1, 5,5,6,6,5, 4,4,3,3,2, 2,1 ,8,8,8,8,8, 8,8,8,8,8 }, //小星星
{8,8,8,8,8, 8,8,1,2,3,3,2, 1,1,3,2,1, 2,8,8,8,8,8, 8,8 }, //开场
{1}
};
char change(char x) //切换数字
{
x--;
if(x == 7)
x = -1;
else
if(x == -1)
x = 7;
return x;
}
char mylist[8][30] = {
" start ",
" Two tigers ",
" Unnamed ",
" The Ode of Joy ",
" The Internationale ",
" Little Star ",
" start ",
" Play little Star "
};
void bibi() //钢琴
{
int d,b;
b = digitalRead(A4)^1;
d = digitalRead(A5)^1;
//读取键盘
if (b == 1&&d == 0) { //B大调
switch (key) {
case 1:
tone(8,131);
break;
case 2:
tone(8,147);
break;
case 3:
tone(8,165);
break;
case 4:
tone(8,175);
break;
case 5:
tone(8,196);
break;
case 6:
tone(8,220);
break;
case 7:
tone(8,247);
break;
case 8:
tone(8,262);
break;
default:
noTone(8);
break;
}
delay(1);
}
if (b == 0 && d == 0) { //C大调
switch (key) {
case 1:
tone(8,262);
break;
case 2:
tone(8,294);
break;
case 3:
tone(8,330);
break;
case 4:
tone(8,349);
break;
case 5:
tone(8,392);
break;
case 6:
tone(8,440);
break;
case 7:
tone(8,494);
break;
case 8:
tone(8,532);
break;
default:
noTone(8);
break;
}
delay(1);
}
if (b == 0 && d == 1) { //D大调
switch (key) {
case 1:
tone(8,532);
break;
case 2:
tone(8,587);
break;
case 3:
tone(8,659);
break;
case 4:
tone(8,698);
break;
case 5:
tone(8,784);
break;
case 6:
tone(8,880);
break;
case 7:
tone(8,988);
break;
case 8:
tone(8,1088);
break;
default:
noTone(8);
break;
}
delay(1);
}
}
void eyes(int wh, char c, int t) //卖萌
{
while (--t) {
//显示分数,音阶
int d,b,score;
score = 0;
b = digitalRead(A4);
d = digitalRead(A5);
if(!b)
shownum(11,score);
else
if(!d)
shownum(13,score);
else
shownum(12,score);
///////显示数码///////
keymake(); bibi();
if(digitalRead(7) == 0) game();
LEDmatrix.clear();
LEDmatrix.writeChar(wh, c, 7);
LEDmatrix.writeChar(wh + 2 * 8, c , 7);
LEDmatrix.render();
}
return;
}
void which() //选曲
{
noTone(8);
LEDmatrix.clear();
LEDmatrix.writeChar(4, '?', 7);
LEDmatrix.writeChar(4 + 2 * 8, '?', 7);
LEDmatrix.render();
while (key > 7 || key < 1)keymake();
wm = key;
return;
}
void always()//音杠
{
for (int i = 0; i< 8; i++) LEDmatrix.writePixel(2, i, 1);
LEDmatrix.render();
}
void play(int x) //播放音乐
{
for (int i = 0; i < mn[x]; i++)
{
key = music[x][i];
bibi();
delay(200);
noTone(8);
delay(300);
}
}
void game()
{
//开场音乐
play(0);
key = 8; noTone(8);
//选曲
which();
if(wm == 7)
{
for (int j = (1); j <= (sizeof(mylist[wm]) / sizeof(mylist[wm][0]) - 4); j = j + (1)) {
for (int i = 0; i <= 3; i = i + (1)) {
LEDmatrix.printChar(i, mylist[wm][(int)((i + j) - 1)]);
LEDmatrix.render();
}delay(200);}
play(5);
key = 8;
return ;
}
//开始提示音
key = 1; bibi(); delay(100); key = 2; bibi(); delay(100); key = 3; bibi(); delay(100); noTone(8);
key = 8;
//报幕
for (int j = (1); j <= (sizeof(mylist[wm]) / sizeof(mylist[wm][0]) - 4); j = j + (1)) {
for (int i = 0; i <= 3; i = i + (1)) {
LEDmatrix.printChar(i, mylist[wm][(int)((i + j) - 1)]);
LEDmatrix.render();
}
delay(200);
}
//进入游戏
volatile int f,p,flag,now,head,tail,score;
score = 0;
// 分数
//显示分数
shownum(wm,score);
f = 0; //计数器
flag = 0; now = 8; //一帧flag
head = 0; tail = 9;
while (1)
{
//显示分数,音阶
int d,b;
b = digitalRead(A4);
d = digitalRead(A5);
if(!b)
shownum(11,score);
else
if(!d)
shownum(13,score);
else
shownum(12,score);
//音杠
always();
//第几帧
p = (f / FAST);
p %= 5;
//每一次都要读取键盘
key = 8;
keymake();
bibi();
//记录按键
if (key != 8)
{
if (now != 8 && now != key)
flag = 1;
if (now == 8)
now = key;
}
//一帧结束
if ((f+1) % FAST == 0)
{
//输出这一帧
LEDmatrix.clear();
for (int i = head,j,mm; i <= tail; i++)
{
if(change(music[wm][i]) == -1)
continue;
j = (i - head) * 5 + 2;
mm = change(music[wm][i]);
if ((j + 0 - p) >= 0 || (j + 0 - p) <= 31)LEDmatrix.writePixel(j+0-p, mm, 1);
if ((j + 1 - p) >= 0 || (j + 1 - p) <= 31)LEDmatrix.writePixel(j+1-p, mm, 1);
if ((j + 3 - p) >= 0 || (j + 3 - p) <= 31)LEDmatrix.writePixel(j+3-p, mm, 1);
if ((j + 4 - p) >= 0 || (j + 4 - p) <= 31)LEDmatrix.writePixel(j+4-p, mm, 1);
}
LEDmatrix.render();
//总结这一帧,并初始化
if (!flag && now == music[wm][head])
{
switch (p)
{
case 0: score += 1; break;
case 1: score += 2; break;
case 2: score += 3; break;
case 3: score += 2; break;
case 4: score += 1; break;
}
}
flag = 0; now = 8;
//一条结束
if (p == 4)
{
head++; tail++;
if (tail == mn[wm])
return ;
}
}
//计数器+1 防溢出
f++;
f %= 1000;
}
}
void shownum(int a,int b) //数码管编程
{
int i,j,k,n1,n2,n3,n4;
n1=a;n2=(b/100)%10;n3=(b/10)%10;n4=b%10;
for(k=100;k>0;k--)
{
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(num[n1],7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
digitalWrite(L1,LOW);
digitalWrite(L2,HIGH);
digitalWrite(L3,HIGH);
digitalWrite(L4,HIGH);
digitalWrite(RCLK,HIGH);
k=200;while(k--);
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(0x00,7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
j--;j++;
digitalWrite(RCLK,HIGH);
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(num[n2],7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
digitalWrite(L1,HIGH);
digitalWrite(L2,LOW);
digitalWrite(L3,HIGH);
digitalWrite(L4,HIGH);
digitalWrite(RCLK,HIGH);
k=200;while(k--);
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(0x00,7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
j--;j++;
digitalWrite(RCLK,HIGH);
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(num[n3],7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
digitalWrite(L1,HIGH);
digitalWrite(L2,HIGH);
digitalWrite(L3,LOW);
digitalWrite(L4,HIGH);
digitalWrite(RCLK,HIGH);
k=200;while(k--);
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(0x00,7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
j--;j++;
digitalWrite(RCLK,HIGH);
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(num[n4],7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
digitalWrite(L1,HIGH);
digitalWrite(L2,HIGH);
digitalWrite(L3,HIGH);
digitalWrite(L4,LOW);
digitalWrite(RCLK,HIGH);
k=200;while(k--);
for(i=0;i<8;i++)
{
digitalWrite(DS,bitRead(0x00,7-i));
digitalWrite(RCK,LOW);
j--;
j++;
digitalWrite(RCK,HIGH);
}
digitalWrite(RCLK,LOW);
j--;j++;
digitalWrite(RCLK,HIGH);
} return;
}
void setup()
{
/////////////LED/////////////
LEDmatrix.begin(10, 13, 11);
LEDmatrix.setBrightness(10);
LEDmatrix.clear();
///////////开关//////////////
pinMode(7, INPUT_PULLUP);
///////////键盘//////////////
key = 0;
pinMode(A5, INPUT_PULLUP);
pinMode(A4, INPUT_PULLUP);
pinMode(A3, INPUT);
pinMode(A2, INPUT);
pinMode(A1, INPUT);
pinMode(A0, INPUT);
////////////数码管////////////
pinMode(RCK,OUTPUT);
pinMode(RCLK,OUTPUT);
pinMode(DS,OUTPUT);
pinMode(L1,OUTPUT);
pinMode(L2,OUTPUT);
pinMode(L3,OUTPUT);
pinMode(L4,OUTPUT);
digitalWrite(RCK,HIGH);
digitalWrite(RCLK,HIGH);
digitalWrite(L1,LOW);
digitalWrite(L2,LOW);
digitalWrite(L3,LOW);
digitalWrite(L4,LOW);
///////////蜂鸣器/////////////
pinMode(8, OUTPUT);
}
void loop()
{
key = 8;
int r;
r = rand() % 1000;
eyes(4, 'O', r);
eyes(5, '=', 20);
}