使用 PIC 微处理器上的 C 进行 MIDI 输出的二进制输出

Posted

技术标签:

【中文标题】使用 PIC 微处理器上的 C 进行 MIDI 输出的二进制输出【英文标题】:Binary output using C on PIC microprocessor for MIDI output 【发布时间】:2015-04-21 00:40:08 【问题描述】:

所以我正在创建一个需要二进制输出才能运行的项目。我有一系列 IF 语句来确定输出是什么,这里一切正常。问题是我正在使用 PIC 微控制器 16F877 并用 C 语言编程。 我正在使用 RS232 将信息直接发送到具有大约 8 个音符值和 8 个音量值(8x8 选项集)的 midi 控制器。

我也在用proteus和CCS编程。

我的问题是:如何以二进制创建 MIDI 输出? 我知道所有二进制值,但我不确定如何创建“midi 友好”输出。

编辑:根据要求添加示例代码:

#include <16F877.h>
TRISB=1; //sets all tris in portB to 1, to allow as inputs

TRISD=1; //sets all tris in portD to 1, to allow as inputs

TRISC.RC6=0; //sets trisC port 6 to 0, to allow as an output

#use rs232(baud=9600,parity=N,xmit=STDOUT,rcv=None,bits=8,stream=PORT1,float_high)
// initialises RS232 and configures for transmision
#use delay(crystal=4MHz)
// crystal at 4MHz is used (XT MODE)

#define X1  PIN_B0 //names pin B0 as X1
#define X2  PIN_B1 //names pin B1 as X2
#define X3  PIN_B2 //names pin B2 as X3
#define X4  PIN_B3 //names pin B3 as X4
#define X5  PIN_B4 //names pin B4 as X5
#define X6  PIN_B5 //names pin B5 as X6
#define X7  PIN_B6 //names pin B6 as X7
#define X8  PIN_B7 //names pin B7 as X8

#define STDOUT  PIN_C6 // Names pin C6 as STDOUT

#define Y1  PIN_D0 //names pin D0 as Y1
#define Y2  PIN_D1 //names pin D1 as Y2
#define Y3  PIN_D2 //names pin D2 as Y3
#define Y4  PIN_D3 //names pin D3 as Y4
#define Y5  PIN_D4 //names pin D4 as Y5
#define Y6  PIN_D5 //names pin D5 as Y6
#define Y7  PIN_D6 //names pin D6 as Y7
#define Y8  PIN_D7 //names pin D7 as Y8

char xout;
char yout;

int main (void)
  
   if(B0==1) //if B0 is 1, sets xout to "A"
   
      xout='A';
   
   if(B1==1) //if B1 is 1, sets xout to "B"
   
      xout='B';
   
   if(B2==1) //if B2 is 1, sets xout to "C"
   
      xout='C';
   
   if(B3==1) //if B3 is 1, sets xout to "D"
   
      xout="D";
   
   if(B4==1) //if B4 is 1, sets xout to "E"
   
      xout='E';
   
   if(B5==1) //if B5 is 1, sets xout to "F"
   
      xout='F';
   
   if(B6==1) //if B6 is 1, sets xout to "G"
   
      xout='G';
   
   if(B7==1) //if B7 is 1, sets xout to "H"
   
      xout='H';
   
   if(D0==1) //if D0 is 1, sets yout to "A"
   
      yout='A';
   
   if(D1==1) //if D1 is 1, sets yout to "B"
   
      yout='B';
   
   if(D2==1) //if D2 is 1, sets yout to "C"
   
      yout='C';
   
   if(D3=1) //if D3 is 1, sets yout to "D"
   
      yout='D';
   
   if(D4==1) //if D4 is 1, sets yout to "E"
   
      yout='E';
   
   if(D5==1) //if D5 is 1, sets yout to "F"
   
      yout='F';
   
   if(D6==1) //if D6 is 1, sets yout to "G"
   
      yout='G';
   
   if(D7==1) //if D7 is 1, sets yout to "H"
   
      yout='H';
   


   printf("%c,%c", xout yout); //outputs xout and yout for display on a screen

代替字母(它们只是为了演示一个实际的输出,以便我可以进入 midi)将是二进制代码,printf 将改为输出在 IF 语句中确定的 midi 值

编辑 2:进一步了解

我将基本上使用一个 8x8 的“开关”网格(使用可见光作为接口)x 轴控制音符,Y 轴控制音量。我只需要一个输出,它将通过 5 针 DIN 直接进入 midi 控制器

【问题讨论】:

您是要在线上的 midi 协议吗? ccrma.stanford.edu/~craig/articles/linuxmidi/misc/… 这肯定会有所帮助(因为我实际上并不处于那个阶段)但我要问的是我如何实际发送二进制格式的输出 请将实际代码添加到问题中。 “二进制 MIDI 输出”是什么意思?您正在通过端口串行发送字节。一个字节由一系列位组成。根据定义,它是二进制的。 这个网站看起来很有用:music-software-development.com/midi-tutorial.html 【参考方案1】:

我可能一开始只使用 2 个命令(NoteOn、NoteOff),然后根据需要继续操作。

下面是一个示例“架构”,我可能会用它来弄湿我的脚。 由于您需要跟踪“note on”和“note off”操作,我添加了全局“state”数组。第一个索引在当前状态和旧状态之间交替变化。对于初学者来说,这可能就足够了。

为您的 8 个按键提供 8 个插槽。如果按键被按下,该值可以是“音量”代码。如果没有按下该音调的键,则为 KEY_OFF。

#define KEY_OFF 0x80  // command parameters only use lower 7 bits...
static uint8_t state[2][8];

static void Configure()
   // Do what you need to do in terms of initializing pins, serial port, etc...



static void UpdateState(uint8_t index)

    // read pins into the global state variable at first index "index"
    // Not pressed "tones" get value "OFF".
    // TIP: later, you could consider to use PIC 
    // "interrupt on change" features 
    // to save power. 
    // Tip: Depending on the types of your keys and your circuitry,
    // you might run into "bouncing keys" problems.
    // But the fact, that you send your serial messages synchronously
    // gives your keys some time to "settle", which might be enough.


// ROM based lookup table
// TODO: fill in correct values for your note-key to note-to-play mapping.
static const uint8_t notes[8] =
 0x01
, 0x01
, 0x01
, 0x01
, 0x01
, 0x01
, 0x01
, 0x01
;

static const uint8_t velocities[8] =

    // TODO: 8 entries mapping your "volume key" code to a MIDI "velocity" code.
;

#define DEFAULT_CHANNEL 0x00 // 16 channels available in midi... 0x00..0x0F

static void SerialSend(uint8_t count, const uint8_t * message)
  // TODO: Implement sending the message on Rs232...
   // TIP: Use the flag "tx buffer EMPTY" before you write next byte.
   for( uint8_t i = 0; i < count; ++i )
   
       while( !TXEMPTY ); // TODO: look up correct name ...
       TX = message[i]; // TODO: look up correct name...
   


// Assuming to use only channel 0 here...
static void SendNoteOff(uint8_t note)

    // TODO: find out if NoteOff needs a "real" velocity value...
    uint8_t midiCmd[3] =  0x80|DEFAULT_CHANNEL, notes[note], 0x00  ;
    SerialSend(3, midiCmd);


static void SendNoteOn(uint8_t note, uint8_t velocity)

    uint8_t midiCmd[3] =  0x90 | DEFAULT_CHANNEL, notes[note], velocities[velocity] ;
    SerialSend(3, midiCmd);


// Named it emain() as it is in some random file of mine which already has a main ;)
void emain()

    Configure();
    uint8_t current = 0;
    uint8_t old = 1;
    while (1)
    
        UpdateState(current);
        for (uint8_t i = 0; i < 8; ++i)
        
            uint8_t os = state[old][i];
            uint8_t cs = state[current][i];
            if (os != cs )
            
                if (0x00 != (cs & KEY_OFF))
                
                    SendNoteOff(i);
                
                else
                
                    SendNoteOn(i, cs);
                
            
        
        old = current;
        current = (current + 1) % 2;
    

【讨论】:

所以你建议使用十六进制而不是二进制发送?这是一个可以接受的解决方法,我可能会使用谢谢:) 但不是通过十六进制,是否可以发送(对于值为 60 的 C 音符)而不是 0x3C,例如发送:00111100?在这一点上,我问这个主要是出于兴趣,但也是为了将来的参考,以及可能在报告中讨论的另一种方法。我会赞成你的评论,但感谢一些人对我的问题投反对票 - 无论出于何种原因我现在无法理解,我的声誉只有 4 :( 如何写字面值并不重要。十进制或十六进制或二进制或八进制。最后,您描述了变量应具有的值,例如字节。如果你写unsigned char x = 42;或者你写unsigned char x = 0x2A;,x中的值是一样的。因此,请选择您可以轻松阅读的任何内容。如果使用十六进制的 Midi 命令很有用,因为命令在某种程度上受到约定的限制,例如“参数只有 7 位宽。即值 0x80 和更大的值会很糟糕。在十六进制中很容易看到,在十进制中更难看到。嗯,有点难。 感谢用户 2225104 :) 以防万一其他人感兴趣 - 我找到了一个有用的标识符 - 即 int8,它创建一个单字节长的整数,非常适合一段 midi 输出 - 它是我的理解是我可以输出那个值,它会在我想要的位置创建一个输出(即如果 60 是 00111100,int8 60 将输出那个字节)

以上是关于使用 PIC 微处理器上的 C 进行 MIDI 输出的二进制输出的主要内容,如果未能解决你的问题,请参考以下文章

PIC 微控制器:扫描 4x4 键盘上的输入,仅使用 C 中的端口 C RC0-RC3

如何为我的 ADC 输出添加迟滞?

c_cpp 修复PIC上的函数地址

c_cpp PIC16器件上的闪存

使用 C 解析 MIDI 文件 - (分配内存的可能问题)

Unity中的MIDI输出