PIC で MIDI の送受信 - 3. MIDI の受信

[前回](https://qiita.com/qtsoundlab/items/806db89b2039d6cf1d3e#_reference-e48ef88874c2f1fce6fe) は PIC の EUSART モジュールのデータ送受信に関連するレジスタの設定をし、実際に MIDI 信号を送信してみました。
今回は同じく PIC16F1827 を使って受信に挑戦です。

# EUSART の受信割り込み

MIDI の受信には、PIC の EUSART モジュールの受信割り込みを利用することにします。

## 割り込みの有効化

受信割り込みを有効にするため、`main` 関数内に以下のコードを追加します。

```c
PIE1bits.RCIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
```

- PIE1 レジスタの RCIE ビットをセットし、EUSART モジュールの受信割り込みを有効にする
- INTCON レジスタの PEIE ビットをセットし、周辺機能割り込みを有効にする
- INTCON レジスタの GIE ビットをセットし、グローバル割り込みを有効にする

これで EUSART モジュールがデータを受信したときに割り込みが発生するようになります。

## 割り込みハンドラ

XC8 コンパイラでは、`interrupt` 修飾子をつけた関数が割り込み発生時に呼ばれる関数として認識されます。
EUSART モジュールの受信以外の割り込み発生時にもこの関数が呼ばれるので、関数内で PIR1 レジスタの RCIF ビットの状態を見て、セットされている場合は EUSART モジュールがデータを受信した、と判断し、RCREG レジスタからデータを読み出します。


# サンプルプログラム

というわけで、実際に MIDI 信号を受信するコードです。


動作環境 : MPLAB X IDE v4.10 / Microchip MPLAB XC8 C Compiler (v1.45)

```c
#include <xc.h>

#pragma config FOSC = INTOSC    // Oscillator Selection : Internal
#pragma config WDTE = OFF       // Watchdog Timer Enable : Off
#pragma config PWRTE = ON       // Power-up Timer Enable : On
#pragma config MCLRE = OFF      // MCLR Pin Function Select : Off
#pragma config CP = OFF         // Flash Program Memory Code Protection : Off
#pragma config CPD = OFF        // Data Memory Code Protection : Off
#pragma config BOREN = ON       // Brownout Reset Enable : On
#pragma config CLKOUTEN = OFF   // Clock Out Enable : Off
#pragma config IESO = OFF       // Internal/External Switchover : Off
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable : Off
#pragma config WRT = OFF        // Flash Memory Self-Write Protection : Off
#pragma config PLLEN = OFF      // PLL Enable : Off
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable : On
#pragma config BORV = LO        // Brown-out Reset Voltage Selection : Low
#pragma config LVP = OFF        // Low-Voltage Programming Enable : Off

#define _XTAL_FREQ 4000000


void interrupt isr(void)
{
    if (RCIF)
    {
        char rxData = RCREG;
        
        switch (rxData & 0xF0)
        {
            case 0x90: // Note On (Status Byte)
                RA0 = 1;
                break;
                
            case 0x80: // Note Off (Status Byte)
                RA0 = 0;
                break;
        }
    }
}


void main(void) {

    // Internal Clock (4 MHz)
    OSCCON = 0b01101010;

    // I/O : Digital Mode
    ANSELA = 0b00000000;
    ANSELB = 0b00000000;

    // Configure Input / Output
    TRISA = 0b00100000; // RA5: Input
    TRISB = 0b00000010; // RB1: Input

    // Configure TX / RX Pins
    APFCON1bits.TXCKSEL = 0; // TX : RB2 (Pin 8)
    APFCON0bits.RXDTSEL = 0; // RX : RB1 (Pin 7)

    // Setup EUSART
    TXSTA = 0b00100100;
    RCSTA = 0b10010000;
    BAUDCON = 0b00000000;
    SPBRGL = 0x07;

    // Setup Interrupt for EUSART
    PIE1bits.RCIE = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;

    while(1);

    return;
}
```

割り込みハンドラ（`isr` 関数）では、RCREG レジスタから受信データを取得し、ノートオンメッセージのステータスバイトであれば RA0 ビットをセット、ノートオフメッセージのステータスバイトであれば RA0 ビットをクリアしています。
RA0 のピンに LED を繋いでおけば、ノートオン、ノートオフに応じて LED が点灯、消灯するのがわかると思います。

ただし、MIDI 信号を送出する機器、ソフトウェアによっては、ノートオフをベロシティ 0 のノートオンで代用していることがあります。
この場合、上の簡易的な例では LED が点灯したままとなってしまうため、別途対応が必要です。

また、本来であれば受信の際にエラーが発生した場合にそれに対応する処理を書くべきですが、今回は省略しています。


# おわりに

PIC を使って、基本的な MIDI 信号のやりとりができました。
各種センサーや通信用モジュールと、電子楽器、さらには MIDI で制御できる照明機器などを PIC を介して繋ぐことで、アイデア次第ではとても面白いものができると思います。


# 参考資料

PIC16(L)F1826/27 Data Sheets
http://ww1.microchip.com/downloads/en/DeviceDoc/41391D.pdf