Как сделать так, чтобы этот звук и светодиод активировались ТОЛЬКО при удерживании кнопки с помощью Arduino? - PullRequest
0 голосов
/ 02 июля 2019

У меня есть этот код, который я использую для воспроизведения звукового эффекта, когда я использовал программу wav2c для преобразования файла .wav в числовые значения, которые я помещаю в заголовочный файл, который я использую в коде для генерации звука.В настоящее время у меня запрограммировано воспроизведение звука после его загрузки в Arduino с включенным светодиодом, который горит только на время действия звукового эффекта.Я пытаюсь запрограммировать его так, чтобы звук и светодиод активировались только при нажатии кнопки.У меня есть контакт, к которому подключена кнопка, уже запрограммированный, но я не уверен, как заставить его управлять звуком и светодиодом, как указано выше.У меня нет большого опыта в программировании или Arduino, поэтому любая помощь очень ценится!Я использую Arduino Mega 2560.

Код

#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define SAMPLE_RATE 20000
#include "Test.h"

int ledPin = 2;
int speakerPin = 9; // Can be either 3 or 11, two PWM outputs connected to Timer 2
const byte pinSwitch1 = 3;
volatile uint16_t sample;
byte lastSample;


void stopPlayback()
{
    digitalWrite(ledPin, LOW);
    // Disable playback per-sample interrupt.
    TIMSK1 &= ~_BV(OCIE1A);

    // Disable the per-sample timer completely.
    TCCR1B &= ~_BV(CS10);

    // Disable the PWM timer.
    TCCR2B &= ~_BV(CS10);

    digitalWrite(speakerPin, LOW);
}

// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
    if (sample >= sounddata_length) {
        if (sample == sounddata_length + lastSample) {
            stopPlayback();
        }
        else {
            if(speakerPin==11){
                // Ramp down to zero to reduce the click at the end of playback.
                OCR2A = sounddata_length + lastSample - sample;
            } else {
                OCR2B = sounddata_length + lastSample - sample;                
            }
        }
    }
    else {
        if(speakerPin==11){
            OCR2A = pgm_read_byte(&sounddata_data[sample]);
        } else {
            OCR2B = pgm_read_byte(&sounddata_data[sample]);            
        }
    }

    ++sample;
}

void startPlayback()
{
    pinMode(speakerPin, OUTPUT);

    // Set up Timer 2 to do pulse width modulation on the speaker
    // pin.

    // Use internal clock (datasheet p.160)
    ASSR &= ~(_BV(EXCLK) | _BV(AS2));

    // Set fast PWM mode  (p.157)
    TCCR2A |= _BV(WGM21) | _BV(WGM20);
    TCCR2B &= ~_BV(WGM22);

    if(speakerPin==11){
        // Do non-inverting PWM on pin OC2A (p.155)
        // On the Arduino this is pin 11.
        TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
        TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
        // No prescaler (p.158)
        TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

        // Set initial pulse width to the first sample.
        OCR2A = pgm_read_byte(&sounddata_data[0]);
    } else {
        // Do non-inverting PWM on pin OC2B (p.155)
        // On the Arduino this is pin 3.
        TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0);
        TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));
        // No prescaler (p.158)
        TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

        // Set initial pulse width to the first sample.
        OCR2B = pgm_read_byte(&sounddata_data[0]);
    }





    // Set up Timer 1 to send a sample every interrupt.

    cli();

    // Set CTC mode (Clear Timer on Compare Match) (p.133)
    // Have to set OCR1A *after*, otherwise it gets reset to 0!
    TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
    TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

    // No prescaler (p.134)
    TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set the compare register (OCR1A).
    // OCR1A is a 16-bit register, so we have to do this with
    // interrupts disabled to be safe.
    OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000

    // Enable interrupt when TCNT1 == OCR1A (p.136)
    TIMSK1 |= _BV(OCIE1A);

    lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
    sample = 0;
    sei();

}


void setup()
{
    pinMode( pinSwitch1, INPUT );
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, HIGH);
    startPlayback();
}

void loop()
{
    while (true);
}

Файл заголовка, указанный в коде с числовыми значениями для создания аудио.

#ifndef _HEADERFILE_H    // Put these two lines at the top of your file.
#define _HEADERFILE_H    // (Use a suitable name, usually based on the file name.)


const int sounddata_length=32000;
//const int sounddata_sampleRate=20000;

const unsigned char sounddata_data[] PROGMEM = {
  15,1,49,0,150,0,138,0,219,255,133,0,176,0,15,1,210,


//There are many lines of more numbers in between that I cut out to save space

};

#endif // _HEADERFILE_H    // Put this line at the end of your file.

1 Ответ

0 голосов
/ 02 июля 2019

Следующие изменения позволят вам начать воспроизведение, когда на вашем контакте переключателя есть спадающий фронт .Вам может потребоваться настроить, чтобы избежать «отскакивания» переключателя.

Во-первых, добавьте глобальную переменную, чтобы записать последнее состояние переключателя:

int lastSwitchState;

Измените setup() на

void setup() {
  pinMode(pinSwitch1, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  lastSwitchState = digitalRead(pinSwitch1);
}

и ваша loop() функция для

void loop() {
  delay(50);

  int switchState = digitalRead(pinSwitch1);

  if (switchState != lastSwitchState) {
    lastSwitchState = switchState;
    if (switchState == LOW) {
      startPlayback();
    }
  }
}

Прерывания по сравнению с опросом

Вместо того, чтобы опрашивать вывод переключателя внутри основного loop(), вы можете использовать прерывания.Для этого вы должны использовать attachInterrupt().Однако прерывания доступны только на определенных выводах, и я думаю, что описанный выше подход концептуально проще.

...