“无线杯”一等奖作品《钢琴游戏机》(《Piano game machine》)介绍

本设计是以8*32点阵作为显示屏,以微动按键作为键盘,蜂鸣器发声,配有数码管计分器的钢琴游戏机。其既有游戏模式,让玩家根据屏幕的显示把握时机按下按键,获得分数;又有自由弹奏模式,玩家可以自由弹奏乐曲。该设计可用于日常娱乐。本文大部分取自何思源同学的设计报告,innovation队员有周家成(本人),何思源和刘振鑫。赛后采访点链接

原 创 性 声 明 本团队郑重声明:所呈交的作品及论文,是本团队在指导老师的指导下,独立进行研究所取得的成果。除文中已经注明引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写过的科研成果。对本文的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。本声明的法律责任由本人承担。


快速目录

  1. 功能介绍
  2. 系统方案
  3. arduino 源代码(详细注释)

功能介绍

  1. 表情功能:无操作状态下,显示屏显示眨眼表情,显示正常。 gif1

  2. 游戏模式功能:按下按键即选择乐曲,显示屏先显示曲名,随后将屏幕竖起,屏幕开始掉落“音乐块”,屏幕底部有一条“基准线”,当音乐块的中心落到基准线时,按下对应按键,发出相应声音,同时计分器分数增加。经过多次测试,计分并不完全准确,有时出现分数激增的情况,但总体上不影响使用。 jpg1

  3. 自由弹奏模式:7个按键分别对应Do-Xi的7个声音,另有一个高音键和一个低音键,按下其中一个后再按7个音键能够弹出高音或低音。这部分功能可以完美实现。 gif2


系统方案

点阵显示 应用4块8*8 led点阵作为显示屏。

led

led点阵原理图

按键模块
采用74ls138芯片将8个按键转换成3位输入,以3口接入arduino。

74ls138 芯片真值表

四位数码管 1至8口接到74hc138转3口输入arduino,9至12口直接接入arduino

tube

数码管图

74HC138

74hc138原理图和真值表

蜂鸣器 蜂鸣器一段通过电容接地,另一端接arduino端口

buzzer


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);
}



本站总访问量

BUFF © 2018. All rights reserved.

Powered by Hydejack v8.1.1