使用Arduino的MIDI音序器定时精度


11

我制作这些音序器

在此处输入图片说明

只是它不完全是一个音序器,它是音序器的物理接口。音序器是一种在音序器连接到的便携式计算机上运行的应用程序,它使用户可以快速制作鼓循环。这很有趣,但是它需要一台笔记本电脑,因为音序器不是“板载”的。

我想要在设备上进行测序。

现在让我们假设我知道如何解决USB MIDI连接的类合规性,并且还假设我可以弄清楚如何连接arduino以从5针DIN端口发送MIDI音符。我最担心的是由于事件循环每次运行的分钟量计时不一致,导致速度随时间变化。

我知道一些事情:

  1. 您不应该依赖于delay()控制速度循环。延迟会停止固件的所有操作,并且无法运行,因为我需要在序列运行时轮询物理用户界面以查找更改。

  2. 基于的计算millis()会更好,因为固件可以在经过一定次数后继续运行并起作用。

  3. 即使我的物理控件都没有触发中断例程,但是某些操作可能会延迟主程序loop()的运行。如果我设计了一个等待用户输入的函数,那么很明显,如果millis()计数超出范围,可能会导致缺少“最后期限”来执行的问题。我知道这个问题是我自己设计的。

问题:

A.基于AVR的arduino是否适合用于轮询用户界面并运行关键任务定时循环的微控制器?我知道现在有一个基于ARM的Arduino,速度要快得多。Teensy 3.0会是更好的选择吗?这两个都是3.3V电路板,所以这是另一个需要解决的问题...但是我暂时将其忽略。

B.我应该把任务分成两个微处理器吗?一种用于轮询和更新用户界面,另一种用于关键任务时序循环。

C。还有吗

我的主要目标是根本不必使用计算机。我也想计算挥杆,但在这种情况下,如果我没有锁定且计时准确的速度,挥杆就没有任何意义。谢谢你的建议!


1
Arduino 总是设置一些中断例程,从而引起抖动。在许多情况下,这不是问题,但要意识到这一点是很好的。noInterrupts();停止抖动,但也停止所有想要的中断。
2013年

1
当您说“在板上进行排序”时,是否意味着在板上设置了每小节拍,BPM和刻度线?那么想必您想记住在条中发生的按钮按下操作,以便设备的“大脑”可以将Midi-notes馈送到笔记本电脑吗?然后,如果您再次敲击之前录制的音符,是否要删除某些打击乐器的声音?等...你想走多远?存储您的节拍?创建一系列与完整曲目相对应的小节?编辑特定的酒吧?特定小节的节奏改变?这一切都会吃掉CPU,因此最好选择CPU。
安迪(aka),

是的,全部。
史蒂夫·库利

2
那是您做的一个可爱的盒子!
shuckc

3
除了其他人所说的,这似乎是您可能打算生产和销售的想法。Arduino的价格为20美元,而AVR的价格为2美元。您不仅可以控制应用程序所需的硬件,还可以节省很多钱。
Phil Frost

Answers:


5

中断是定时敏感任务的朋友,但前提是您必须将定时关键方面放到中断中,并且不会发生其他优先级更高的中断。“基于AVR的” Arduino上的微控制器(例如ATmega328P)具有固定的中断优先级,详见数据表第58ff页。因此,如果您将TIMER2 COMPA用作关键时序中断,并且没有其他中断,则应该没问题(因为它具有最高优先级)。如果您还想使用优先级较低的中断,则需要确保在进入中断服务程序时,它们全部重新启用全局中断:

发生中断时,清除全局中断允许I位,并禁用所有中断。用户软件可以将逻辑1写入I位以启用嵌套中断。然后,所有允许的中断都可以中断当前的中断程序。

数据表第14页)

这与基于ARM的Arduino稍有不同,因为其Cortex-M3内核具有“嵌套矢量中断控制器”,其优先级不固定(可以在软件中设置),并且嵌套中断处理已成为常态。因此,对于定时关键的应用程序,基于ARM的Arduino将为您提供更大的灵活性。但是,我认为这对于您的应用程序不是真正必要的。

更大的问题是,使用Arduino库可以轻松实现这些功能。为了获得最佳性能,您可能必须在库外部进行某种程度的编码,至少对于时序关键位而言,即完全避免诸如delay()或millis()之类的事情。

是否需要拆分取决于您打算进行多少处理。同样,走出库可能会给您带来更好的性能。


3

通过适当的编程,这绝对可以在ATmega328P上完成(在某种程度上取决于鼓循环的复杂性。我假设循环中的循环事件少于50个。这合理吗?)。

请注意,我说的是ATmega328P,不一定是Arduino

Arduino环境在后台运行着许多默认的东西,这给确定性编程(因为您需要一些对时间要求严格的东西)提出了挑战。

您需要在这里提出的真正问题是,您对编程多大兴趣,而对开发仪器有多大兴趣?

尽管我非常有信心,可以在单个ATmega上完成您想做的所有事情(鼓循环,多个模拟输入,LCD,按钮,MIDI接口),但真正的问题是,将所有东西都挤进去需要多少工作?同样,您是否想学习优化嵌入式MCU代码或构建仪器?这是很容易的,只需去一个更快的MCU如果需要的话,但是你需要确定MCU的性能,你需要现在,让工作半年的,你不知道你不能得到的一切工作一样快,你需要。


如果我是你,我要做的第一件事就是在没有arduino东西的情况下使其正常工作(基本上,将其视为原始ATmega,并使用AVR Studio或类似工具)。然后,您可以更有效地分析所需的性能以及ATmega是否可以对其进行管理。

一旦您摆脱了arduino的麻烦,您就可以更加自由地使用不同的MCU(它们通常更相似,然后又有所不同。如果您可以从其文档中找到一个,则可能对其他人也可以这样做)。

我最近在很多地方都在使用ATxmega设备,它们真的很棒。您将获得三个中断优先级,这使得管理时间紧迫的工作变得更加容易。它们也非常好用(健全的外围设计!便捷的端口结构!等等)。

也有来自恩智浦的基于ARM的LPC设备,以及Atmel的一些ARM设备(用于Arduino Due),或来自ST的STM32 MCU。所有这些都将有显著更多的表现那么的ATmega,甚至是ATxmega。

更大,功能更强大的处理器的主要缺点是价格,但是除非您要制造成千上万个这样的单元,否则每个单元的组装和制造成本将大大超过成本差异(可能只有几美元) ),这基本上是无关紧要的。


很好的说-对于商业产品而言,Arduino绝非可行之举-它们耗电,速度慢,并且IDE并非针对最佳(快速/小型)代码而设计,而是为了方便和易于学习。以更低的成本,您甚至可以拥有STM32 F4(32位Cortex M4> 100MHz)或类似产品,尽管这样做可能会过分。正如您所提到的,我认为像较小的PIC32之一,Cortex M3或AVR32之类的东西可能是要走的路。与Arduino相比,众多的中断优先级,DMA,复杂的外设,快速/低功耗和大量RAM使之成为轻松的选择。
奥利·格拉瑟

@OliGlaser-我认为您需要清楚地区分ArduinoATmega。您可以在ATmega上编写小的快速代码,而ATmega甚至可以在Arduino板上。另一方面,Arduino“ IDE”是我曾经使用过的最糟糕的代码编辑器之一。另一方面,OptiBoot引导程序非常好。仅仅因为某些部分是垃圾,并不意味着您应该将整个东西扔掉。
康纳·沃尔夫

绝对-我指的是整个Arduino,包括板和IDE-不包括ATmega,我敢肯定它会与其他任何可比较的uC(PIC16 / 18F等)一样好,但我会将其包括在清单中我认为,如今8位和16/32位之间的价格是如此接近,花一个额外的$ 1并知道您有处理器的余地可能是个好主意(除非您提到,我们在谈论数量巨大并以绝对的最低价格建造,但后来我怀疑是否应该考虑使用Arduino :
Oli Glaser 2013年

1

在开始考虑计时精度之前,我需要阅读计时器(也可以使用arduino构建midi步进音序器,尽管可以保证它看起来不那么酷^^)。该系列文章提供的信息最丰富:

http://maxembedded.com/category/microcontrollers-2/atmel-avr/avr-timers-atmel-avr/

现在,我认为我的解决方案将获得精确的时间。

A.使用AVR arduino

B.将任务保留在一个微处理器上

C.明智地使用预分频器,计时器和中断来获得所需的精度。

更新

使用Arduino的基本midi教程,并在阅读了有关定时器和预分频器的文章之后,下面的代码就是我想到的。该代码使用timer1和CTC模式在每四分之一秒播放一次中音,然后每四分之一秒播放一次音符(应为120 bpm)。可悲的是,尽管这是我得到的最接近的速度,但它仍然比120bpm慢一些。

// Includes
#include <avr/io.h>
#include <avr/interrupt.h>

int last_action=0;

void setup()
{
    //  Set MIDI baud rate:
    Serial.begin(31250);

    // initialize Timer1
    cli();          // disable global interrupts
    TCCR1A = 0;     // set entire TCCR1A register to 0
    TCCR1B = 0;     // same for TCCR1B

    // set compare match register to desired timer count:
    OCR1A = 15624;
    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);
    // Set CS12 bits for 256 prescaler:
    TCCR1B |= (1 << CS12);
    // enable timer compare interrupt:
    TIMSK1 |= (1 << OCIE1A);
    // enable global interrupts:
    sei();
}

void loop()
{
    // do some crazy stuff while my midi notes are playing
}

ISR(TIMER1_COMPA_vect)
{
  // Turn notes on
  if (last_action == 0) {
    send_note(0x90, 60, 0x45);
    last_action = 1;

  // Turn notes off
  } else {
    send_note(0x90, 60, 0x00);
    last_action = 0;
  }
}

//  plays a MIDI note
void send_note(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

更新

我已经为此苦苦挣扎了〜24小时,终于从论坛上得到了一些答案。我认为我在^^上方使用的代码非常好。使用ISR,使用CTC模式和预分频器等。进入论坛后,我认为解决方案不仅仅在于在Midi音序器上获得精度,而是使整个硬件设置(我的合成器和采样器)都连在一起midi时钟,无论时钟是否来自Arduino。


0

根据您希望从系留计算机过渡到基于µC的系统的逐步进度,您可以考虑将Raspberry Pi放入该包装盒中(零售价25-35美元)。这样一来,您就可以拥有一台完整的(尽管功耗低)基于Linux的计算机,该计算机具有USB端口和GPIO引脚。


我敢肯定,有扩展挡板或它们称为Pi的任何东西,但是备用板上有17个GPIO引脚。我正在使用arduino mega上的每个引脚。31步+ 30个LED,10个模拟输入70 + I / O。
史蒂夫·库利

哦,我的意思是,如果当前的目标是删除外部计算机,则可以保留“定序器(该程序是在笔记本电脑上运行的应用程序”)并在Pi上运行,并以与内部系统相同的方式内部连接到现有系统。现在连接。
罗伯·史达琳,2013年

@SteveCooley-听起来您需要研究IO多路复用/按钮矩阵。您不需要每个按钮都有一条完整的专用IO线。
康纳·沃尔夫

@SteveCooley-地狱,真的,您甚至不需要按钮矩阵。您仅需使用4个rPi引脚即可完成所有数字IO。只需将所有按钮和LED挂在某些移位寄存器上(按钮为并行-串行,LED为串行-并行),然后从rPi的SPI端口驱动移位寄存器。借助SPI硬件,您应该可以轻松地获得整个矩阵的> 1Khz更新速率。
康纳·沃尔夫

如果您使用Arduino Mega的唯一原因是IO,那么您将花费大量金钱购买一些可以很容易地用一些外部设备完成的事情,而价格不到3美元。
康纳·沃尔夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.