AVR MIDI

お約束ですが、このページのいかなる記載においても著者は一切の責任をおいません。

MIDIのテスト用に作ったArduino互換ボード

IMGP0248 IMGP0250 IMGP0253

MIDI INの回路はPC900を乗せるスペースがなかった事もあり pcm1723さんのページを参考にさせてもらいました。

MIDI INから入ってきたデータをMIDI OUTに送るスケッチ
void setup() {
  Serial.begin(31250);
}

void loop() {
  int readdata = Serial.read();
  if(readdata != -1) {
    Serial.write(readdata);
  }
}
Copy_88

四分音符をならすスケッチ其の壱
#include <TimerOne.h>

int ledPin = 13;                 // LED connected to digital pin 13

char laststat = 0;
int tempo = 100;
int curclock;
int timebase = 120;

void setup() {
  long oneclock;
  Serial.begin(31250);
  sendMidi(0xb0, 0x78, 0); // all sound off
  Timer1.initialize();
  oneclock = 60 * 1000L * 1000L / (tempo * timebase);
  curclock = 0;
  Timer1.attachInterrupt(timertask, oneclock);
}

void loop() {
  digitalWrite(ledPin, HIGH);   // sets the LED on
  delay(1000);                  // waits for a second
  digitalWrite(ledPin, LOW);    // sets the LED off
  delay(1000);                  // waits for a second
}

void sendMidi(char stat, char data1, char data2) {
  // running status
  if(laststat != stat) {
    Serial.print(stat, BYTE);
    laststat = stat;
  }  
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}

void timertask () {
  if(curclock == 0) {
    sendMidi(0x99, 60, 100); // note on
  } 
  else if(curclock == 110) {
    sendMidi(0x99, 60, 0); // note off
  }
  ++curclock;
  if(curclock == timebase)
    curclock = 0;
}
四分音符をならすスケッチ其の弐
#include <TimerOne.h>

int ledPin = 13;                 // LED connected to digital pin 13

char laststat = 0;
int tempo = 100;
int curclock;
int timebase = 120;
long clocktime;

void setup() {
  long oneclock;
  Serial.begin(31250);
  sendMidi(0xb0, 0x78, 0); // all sound off
  Timer1.initialize();
  oneclock = 400L;
  curclock = 0;
  clocktime = (1000000L * 60 / (timebase * tempo)) / oneclock;
  Timer1.attachInterrupt(timertask, oneclock);
}

void loop() {
  digitalWrite(ledPin, HIGH);   // sets the LED on
  delay(1000);                  // waits for a second
  digitalWrite(ledPin, LOW);    // sets the LED off
  delay(1000);                  // waits for a second
}

void sendMidi(char stat, char data1, char data2) {
  Serial.print(stat, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}

void timertask () {
  if(curclock == 0) {
    Serial.print(0x99, BYTE);
  } else if(curclock == 1) {
    Serial.print(60, BYTE);
  } else if(curclock == 2) {
    Serial.print(100, BYTE);
  } else if(curclock == clocktime * 110) {
    Serial.print(60, BYTE);
  } else if(curclock == clocktime * 110 + 1) {
    Serial.print(0, BYTE);
  }
  ++curclock;
  if(curclock == timebase * clocktime)
    curclock = 0;
}
四分音符をならすスケッチ其の参

Serialライブラリを使わず自前でUSARTに送信するスケッチです。 gyokimaeさんのライブラリ コードを参考にさせてもらいました。
#include <TimerOne.h>

#define MIDI_BAUD_RATE 31250

int ledPin = 13;                 // LED connected to digital pin 13

int tempo = 100;
int curclock;
int timebase = 120;

int txremain;
int txcurrent;
unsigned char txqueue[8];

ISR(USART_TX_vect)
{
  if(txcurrent < txremain) {
    UDR0 = txqueue[txcurrent];
    ++txcurrent;
   }
}

void setup() {
  long oneclock;
  Timer1.initialize();
  oneclock = 60 * 1000L * 1000L / (tempo * timebase);
  curclock = 0;
  Timer1.attachInterrupt(timertask, oneclock);
  txcurrent = 0;
  txremain = 0;
  UBRR0H = ((F_CPU / 16 + MIDI_BAUD_RATE / 2) / MIDI_BAUD_RATE - 1) >> 8;
  UBRR0L = ((F_CPU / 16 + MIDI_BAUD_RATE / 2) / MIDI_BAUD_RATE - 1);
  UCSR0B |= _BV(TXEN0);
  UCSR0B |= _BV(TXCIE0);
}

void loop() {
  digitalWrite(ledPin, HIGH);   // sets the LED on
  delay(1000);                  // waits for a second
  digitalWrite(ledPin, LOW);    // sets the LED off
  delay(1000);                  // waits for a second
}

void sentnoteon()
{
  txqueue[0] = 60;
  txqueue[1] = 100;
  txcurrent = 0;
  txremain = 2;
  UDR0 = 0x99;
}

void sentnoteoff()
{
  txqueue[0] = 60;
  txqueue[1] = 0;
  txcurrent = 0;
  txremain = 2;
  UDR0 = 0x99;
}

void timertask () {
  if(curclock == 0) {
    sentnoteon();
  } else if(curclock == 110) {
    sentnoteoff();
  }
  ++curclock;
  if(curclock == timebase)
    curclock = 0;
}

30年前にPC98用に作ったMIDI/FM音源ボードにATMEGA328Pをのっけて使えるように しました。SSG/OPN/OPL/MIDI OUTは確認しました。MIDI INは割り込みが無いと 厳しいので確認していません。PC98用なのにユニバーサル基板な訳は、当時PC98用の 専用基板は高かったので、専用基板にユニバーサル基板のっけて使っていたためです。

IMGP0060

もともとあったデータバスとWR,RD,A0はそのままつなぎ、CSはアドレスデコーダーを バラして74LS138だけにしてA0,A1,A2をつなぎ、E3をRESETにしてみた。通常はA0,A1,A2 をHとしてO6がLになっているが、使わないので問題ない。

当初はISPの5Vで駆動していたが、オペアンプの電源が必要なため昇圧も考えたが、 ノイズが心配なので、12-15Vのアダプタを使う事にして5V/500mAのレギュレータを 裏面に貼付けてみた。

ATMEGA328Pは外部水晶の16MHz駆動とした。この基板は発振回路が3つもある。ちゃんと 設計したら、一つでどうにかなりそうなのだが。

デバッグに利用するためにI2Cを出してATtiny2313を使ったLCD表示モジュールを つないでみた。

フルの電流を計ってみたら200mAくらいのようだ。




Copyright (C) 2011 Hiroki Mori All Rights Reserved.