Воспроизведение звука и работа с моторами ардуино

Kulibin_

✩✩✩✩✩✩✩
13 Мар 2023
12
0
Здравствуйте, возникла проблема. Делаю классического робота, который будет ездить по комнате и обнаруживать препятствия при помощи известного УЗ-датчика. Но решил добавить ему ещё и воспроизведение звука, всего одну фразу. Звук воспроизводится не с карты памяти, а с отдельного файла. Проблема в том, что при воспроизведении звука один из моторов перестаёт крутиться, если скорость для него указана ниже 255. Без этого всё работает как надо, скорость настраивается в коде без проблем, но как только в коде появляется команда воспроизведения звука всё сразу перестаёт работать. Моторы подключены через драйвер MX1508, один к выводам D6 и D5, второй, с которым и возникают проблемы, к D9 и D10. Динамик подключен через усилитель PAM8403 к пину D11. Вот код:

C++:
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "sounddata.h"
#define SAMPLE_RATE 8000  // скорость воспроизведения

const int PinB1 = 10;
const int PinB2 = 9;
const int PinA1 = 6;
const int PinA2 = 5;
int trigPin = 8; 
int echoPin = 7;
long duration, distance;

#define LEFT_SENSOR_PIN  A3
#define RIGHT_SENSOR_PIN A4

int MaxSpdR = 105;
int MaxSpdL = 82;

#define SLOW_SPEED       35
#define BACK_SLOW_SPEED  30
#define BACK_FAST_SPEED  50

#define BRAKE_K          4

#define STATE_FORWARD    0
#define STATE_RIGHT      1
#define STATE_LEFT       2

#define SPEED_STEP       2

#define FAST_TIME_THRESHOLD     500

#define SPEED            85
int state = STATE_FORWARD;
int currentSpeed = SPEED;
int fastTime = 0;
unsigned long timing;
unsigned long timingn;
unsigned long timingf;

int detectState1 = 0;
int detectState2 = 0;
int speakerPin = 11;
volatile uint16_t sample;
byte lastSample;
unsigned long timing1;  // Переменная для хранения точки отсчета воспроизведения звука

ISR(TIMER1_COMPA_vect) {
  if (sample >= sounddata_length) {
    if (sample == sounddata_length + lastSample) {
      stopPlayback();
    } else {
      // Рампа вниз до нуля, чтобы уменьшить щелчок в конце воспроизведения.
      OCR2A = sounddata_length + lastSample - sample;
    }
  } else {
    OCR2A = pgm_read_byte(&sounddata_data[sample]);
  }
  ++sample;
}

void startPlayback() {
  pinMode(speakerPin, OUTPUT);
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));
  TCCR2A |= _BV(WGM21) | _BV(WGM20);
  TCCR2B &= ~_BV(WGM22);
  TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
  TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
  TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
  OCR2A = pgm_read_byte(&sounddata_data[0]);
  cli();
  TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
  TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
  TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
  OCR1A = F_CPU / SAMPLE_RATE;  // 16e6 / 8000 = 2000
  TIMSK1 |= _BV(OCIE1A);
  lastSample = pgm_read_byte(&sounddata_data[sounddata_length - 1]);
  sample = 0;
  sei();
}

void stopPlayback() {
  TIMSK1 &= ~_BV(OCIE1A);
  TCCR1B &= ~_BV(CS10);
  TCCR2B &= ~_BV(CS10);
  digitalWrite(speakerPin, LOW);
}

void runForward()
{
  state = STATE_FORWARD;

  fastTime += 1;
  if (fastTime < FAST_TIME_THRESHOLD) {
    currentSpeed = SLOW_SPEED;
  } else {
    currentSpeed = min(currentSpeed + SPEED_STEP, SPEED);
  }

  analogWrite(PinA1, 0);
  analogWrite(PinA2, currentSpeed);
  analogWrite(PinB1, currentSpeed);
  analogWrite(PinB2, 0);


}

void steerRight()
{
  state = STATE_RIGHT;
  fastTime = 0;

  analogWrite(PinA1, 0);
  analogWrite(PinA2, 0);
  analogWrite(PinB1, SPEED);
  analogWrite(PinB2, 0);
}

void steerLeft()
{
  state = STATE_LEFT;
  fastTime = 0;

  analogWrite(PinA1, 0);
  analogWrite(PinA2, SPEED);
  analogWrite(PinB1, 0);
  analogWrite(PinB2, 0);
}


void stepBack(int duration, int state) {
  if (!duration)
    return;

  int leftSpeed = (state == STATE_RIGHT) ? BACK_SLOW_SPEED : BACK_FAST_SPEED;
  int rightSpeed = (state == STATE_LEFT) ? BACK_SLOW_SPEED : BACK_FAST_SPEED;

  analogWrite(PinA1, rightSpeed);
  analogWrite(PinA2, 0);
  analogWrite(PinB1, 0);
  analogWrite(PinB2, leftSpeed);

  delay(duration);
}

void runRight() {
  analogWrite(PinA1, MaxSpdR);
  analogWrite(PinA2, 0);
  analogWrite(PinB1, MaxSpdL);
  analogWrite(PinB2, 0);
}

void runLeft() {
  analogWrite(PinA1, 0);
  analogWrite(PinA2, MaxSpdR);
  analogWrite(PinB1, 0);
  analogWrite(PinB2, MaxSpdL);
}

void runBack() {
  analogWrite(PinA1, MaxSpdR);
  analogWrite(PinA2, 0);
  analogWrite(PinB1, 0);
  analogWrite(PinB2, MaxSpdL);
}

void runForward1() {
  analogWrite(PinA1, 0);
  analogWrite(PinA2, MaxSpdR);
  analogWrite(PinB1, MaxSpdL);
  analogWrite(PinB2, 0);
}

void stopp() {
  analogWrite(PinA1, 0);
  analogWrite(PinA2, 0);
  analogWrite(PinB1, 0);
  analogWrite(PinB2, 0);
}

void setup() {
  pinMode(13, INPUT_PULLUP);
  pinMode(PinA1, OUTPUT);
  pinMode(PinA2, OUTPUT); 
  pinMode(PinB1, OUTPUT); 
  pinMode(PinB2, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  Serial.begin(9600);
  startPlayback();
}

void loop() {
  while (digitalRead(13)) {

    if (millis() - timing > 5) {
      digitalWrite(trigPin, LOW);
      delayMicroseconds(2);
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      duration = pulseIn(echoPin, HIGH);
      distance = duration / 58.2;
      timing = millis();
    }

    if (millis() - timingn > 4000) {
    //  startPlayback();
      timingn = millis();
    }

    if (distance > 27) {
      runForward1();
    }
    else {
      stopp();
      delay(1000);
      runBack();
      delay(500);
      stopp();
      delay(800);
      runLeft();
      delay(220);
    }
  }
  stopp();
  delay(3000);
  while (digitalRead(13) == 0) {
    boolean left = digitalRead(LEFT_SENSOR_PIN);
    boolean right = !digitalRead(RIGHT_SENSOR_PIN);
    int targetState;
    if (left == right) {
      targetState = STATE_FORWARD;
    } else if (left) {
      targetState = STATE_LEFT;
    } else {
      targetState = STATE_RIGHT;
    }

    if (state == STATE_FORWARD && targetState != STATE_FORWARD) {
      int brakeTime = (currentSpeed > SLOW_SPEED) ?
                      currentSpeed : 0;
      stepBack(brakeTime, targetState);
    }

    switch (targetState) {
      case STATE_FORWARD:
        runForward();
        break;

      case STATE_RIGHT:
        steerRight();
        break;

      case STATE_LEFT:
        steerLeft();
        break;
    }
  }
}
Вот эти функции отвечают за воспроизведение звука:
C++:
SR(TIMER1_COMPA_vect) {
  if (sample >= sounddata_length) {
    if (sample == sounddata_length + lastSample) {
      stopPlayback();
    } else {
      // Рампа вниз до нуля, чтобы уменьшить щелчок в конце воспроизведения.
      OCR2A = sounddata_length + lastSample - sample;
    }
  } else {
    OCR2A = pgm_read_byte(&sounddata_data[sample]);
  }
  ++sample;
}

void startPlayback() {
  pinMode(speakerPin, OUTPUT);
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));
  TCCR2A |= _BV(WGM21) | _BV(WGM20);
  TCCR2B &= ~_BV(WGM22);
  TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
  TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
  TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
  OCR2A = pgm_read_byte(&sounddata_data[0]);
  cli();
  TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
  TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
  TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
  OCR1A = F_CPU / SAMPLE_RATE;  // 16e6 / 8000 = 2000
  TIMSK1 |= _BV(OCIE1A);
  lastSample = pgm_read_byte(&sounddata_data[sounddata_length - 1]);
  sample = 0;
  sei();
}

void stopPlayback() {
  TIMSK1 &= ~_BV(OCIE1A);
  TCCR1B &= ~_BV(CS10);
  TCCR2B &= ~_BV(CS10);
  digitalWrite(speakerPin, LOW);
}
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
501
149
@Kulibin_,
Сейчас у вас TIMER1 используется для формирования звука, поэтому нежелательно (или нельзя) использовать его выводы D9 и D10 для управления мотором.
Для управления двумя моторами при помощи MX1508 достаточно одного таймера. Перепишите ваш скетч, чтобы моторы управлялись двумя аналоговыми выводами D5 и D6 и двумя свободными цифровыми.
 
  • Лойс +1
Реакции: Kulibin_

Kulibin_

✩✩✩✩✩✩✩
13 Мар 2023
12
0
То есть один мотор подключить на D5 и любой другой вывод без ШИМ, а второй на D6 и точно также на любой другой вывод без ШИМ, верно?
 
Изменено: