RC Sound module

Nedaří se vám s projektem a nenašli jste vhodné místo, kde se zeptat? Napište sem.
Pravidla fóra
Tohle subfórum je určeno pro konzultaci ucelených nápadů, popřípadě řešení komplexnějších projektů, které opravdu není možné rozdělit na menší části.
Většinu problémů jde rozdělit na menší a ptát se na ně v konkrétních subfórech.
Odpovědět
Woyta
Příspěvky: 16
Registrován: 17 črc 2019, 17:04
Reputation: 0

RC Sound module

Příspěvek od Woyta » 17 črc 2019, 18:12

Pustil jsem se do úpravy projektu RC sound modulu pro moje RC Offroad auta.
Jako základ používám tent projekt https://github.com/TheDIYGuy999/Rc_Engine_Sound
Plán je nahradit i jinou elektroniku v autě jmenovitě světelný modul a řídící jednotky navijáků.

Motory navijáků budu ovládat pomocí L298N: https://www.aliexpress.com/item/32977306174.html

Plán je následující.
Vyhodit z programu nepotřebné části a uvolnit tak piny. Pár pinů přemístit aby vysledné zapojení bylo jednodušší.

Piny plánuji užít takto:
A0 Input - jumper pro režim svícení
A1 Input - RC prijimac CH1
A2 Input - RC prijimac CH2 (v původním programu D2)
A3 Input - RC prijimac CH3
A4 Input - RC prijimac CH4
A5 Input - RC prijimac CH5
A6 volný
A7 volný

D0 Output - Světlomety
D1 Output - Světelná rampa
D2 Output - Zpátečka
D3 Output - Momentálně Repro. (Pry by mělo jít přesunout na D11 Potom by zde byli brzdová světla)
D4 Output - Digitální potenciometr
D5 Output - Digitální potenciometr
D6 Output - Digitální potenciometr
D7 Output - Naviják 1
D8 Output - Naviják 1
D9 Output - Naviják 2
D10 Output - Naviják 2
D11 Output - Brzdová světla (pokud nepujde přehodit repro)
D12 Output - Levý Blinkr
D13 Output - Pravý Blinkr

První co jsem udělal bylo vyházet části které nepotřebuji.
SPI, řízení potenciometrem
Smazány tedy byli řádky 51-55, 68-74,116-124, 144-160, 348-356
K tomu samozřejmě přizpůsobeny řádky 100-107.
A v settings.H zmizel řadek 23 #define POT_PIN A1
Timhle jsem si uvolnil piny A0,A1,A2,D10,D12 pro moje účely. A kod se na dev boardu chová jak by měl.

V tuhle chvíli se snažím přesunout vstup signálu z D2 na A2. Jediné definice vidím na řádku 77 (pinmode) a 332 kde zněj čte (pro zjednoduššení nahrazeno příkazem digitalread(a2))
Výsledkem je, že zvuk je generován jen pokud přivedu signál současně na piny A2 a D2. Přehlížím nějakou kontrolu či definici?

Pokud se pokusím řádek 22 #define SPEAKER 3 změnit na #define SPEAKER 11 tak zvuk není ani na pinu 3 ani 11. To budu muset asi kouknout do části PCM setup (238) jak to posílá zvuk ven. Hádám, že asi přes nějaký registr.

Uvítal bych jestli by na to někdo kouknul a řekl mi kam zaměřit moji pozornost případně mi řekl, zda piny co plánuji požít neblokuje něco jiného.


Takhle vypadá aktuálni stav se kterým si hraju.

Kód: Vybrat vše

/*
      This code was quick and dirty, based on a PCM audio example in the
      arduino playground: http://playground.arduino.cc/Code/PCMAudio

      It's been heavely modified for use with RC to generate something that's
      a bit like an engine sound. I've started work on making the program
      readable, still some to do though.
      https://github.com/BeigeMatchbox/mojoEngineSim/blob/master/README.md

      Enhancements, done by TheDIYGUY999 in january 2017: https://github.com/TheDIYGuy999/Rc_Engine_Sound
        - more sounds added,
        - also works on a 8MHz MCU, but not in servo throttle mode
*/

// All the required settings are done in settings.h!
#include "settings.h" // <<------- SETTINGS

const float codeVersion = 1.2; // Software revision

// Stuff not to play with! ----------------------------------------------------------------------------
#define SPEAKER 3 // This is kept as 3, original code had 11 as option, but this conflicts with SPI
volatile uint16_t currentSmpleRate = BASE_RATE; // Current playback rate, this is adjusted depending on engine RPM
boolean audioRunning = false;                   // Audio state, used so we can toggle the sound system
boolean engineOn = true;                        // Signal for engine on / off
uint16_t curVolume = 0;                         // Current digi pot volume, used for fade in/out
volatile uint16_t curEngineSample;              // Index of current loaded sample
uint8_t  lastSample;                            // Last loaded sample
int16_t  currentThrottle = 0;                   // 0 - 1000, a top value of 1023 is acceptable
uint8_t  throttleByte = 0;                      // Raw throttle position in SPI mode, gets mapped to currentThrottle
uint8_t  spiReturnByte = 0;                     // The current RPM mapped to a byte for SPI return
volatile int16_t pulseWidth = 0;                // Current pulse width when in PWM mode
volatile boolean pulseAvailable;                  // RC signal pulses are coming in
#define FREQ 16000000L                          // Always 16MHz, even if running on a 8MHz MCU!

int16_t pulseMaxNeutral; // PWM throttle configuration storage variables
int16_t pulseMinNeutral;
int16_t pulseMax;
int16_t pulseMin;
int16_t pulseMaxLimit;
int16_t pulseMinLimit;

//
// =======================================================================================================
// MAIN ARDUINO SETUP (1x during startup)
// =======================================================================================================
//

void setup() {


  // MCP4131 digi pot
  pinMode(POT_CS, OUTPUT);
  pinMode(POT_SCK, OUTPUT);
  pinMode(POT_SDO, OUTPUT);
  digitalWrite(POT_CS, HIGH);
  digitalWrite(POT_SCK, HIGH);
  digitalWrite(POT_SDO, HIGH);

  if (managedThrottle) writePot(0);
  else writePot(DEFAULT_VOLUME);

  // pwm in setup, for a standard servo pulse
  pinMode(2, INPUT); // We don't want INPUT_PULLUP as the 5v may damage some receivers!
  if (pwmThrottle) { // And we don't want the interrupt firing when not in pwm mode
    attachInterrupt(0, getPulsewidth, CHANGE);
  }

  // Calculate throttle range
  pulseMaxNeutral = pulseZero + pulseNeutral;
  pulseMinNeutral = pulseZero - pulseNeutral;
  pulseMax = pulseZero + pulseSpan;
  pulseMin = pulseZero - pulseSpan;
  pulseMaxLimit = pulseZero + pulseLimit;
  pulseMinLimit = pulseZero - pulseLimit;

  // setup complete, so start making sounds
  setupPcm();
}

//
// =======================================================================================================
// MAIN LOOP
// =======================================================================================================
//

void loop() {
  if (pwmThrottle) {
    doPwmThrottle();
    noPulse();
  }
  if (managedThrottle) manageSpeed();
}

//
// =======================================================================================================
// THROTTLES
// =======================================================================================================
//


// RC PWM signal -------------------------------------------------------------------------------------
void doPwmThrottle() {

  if (pulseWidth > pulseMinLimit && pulseWidth < pulseMaxLimit) { // check if the pulsewidth looks like a servo pulse
    if (pulseWidth < pulseMin) pulseWidth = pulseMin; // Constrain the value
    if (pulseWidth > pulseMax) pulseWidth = pulseMax;

    if (pulseWidth > pulseMaxNeutral) currentThrottle = (pulseWidth - pulseZero) * 2; // make a throttle value from the pulsewidth 0 - 1000
    else if (pulseWidth < pulseMinNeutral) currentThrottle = abs( (pulseWidth - pulseZero) * 2);
    else currentThrottle = 0;
  }

  if (!managedThrottle) {
    // The current sample rate will be written later, if managed throttle is active
    currentSmpleRate = FREQ / (BASE_RATE + long(currentThrottle * TOP_SPEED_MULTIPLIER));
  }
}


//
// =======================================================================================================
// MASS SIMULATION
// =======================================================================================================
//

void manageSpeed() {

  static int16_t prevThrottle = 0xFFFF;
  static int16_t currentRpm = 0;
  const  int16_t maxRpm = 8184; //8184
  const  int16_t minRpm = 0;

  static unsigned long throtMillis;
  static unsigned long startStopMillis;
  static unsigned long volMillis;

  // Engine RPM -------------------------------------------------------------------------------------
  if (millis() - throtMillis > 5) { // Every 5ms
    throtMillis = millis();

    if (currentThrottle + 18 > currentRpm) {
      currentRpm += 18;
      if (currentRpm > maxRpm) currentRpm = maxRpm;
      prevThrottle = currentThrottle;

    }
    else if (currentThrottle - 12 < currentRpm) {
      currentRpm -= 12;
      if (currentRpm < minRpm) currentRpm = minRpm;
      prevThrottle = currentThrottle;
    }

    if (currentRpm >> 2 < 255) spiReturnByte = currentRpm >> 2;
    else spiReturnByte = 255;
    if (currentRpm >> 2 < 0) spiReturnByte = 0;

    currentSmpleRate = FREQ / (BASE_RATE + long(currentRpm * TOP_SPEED_MULTIPLIER) );
  }

  // Engine volume (for MCP4131 digipot only) -------------------------------------------------------
  if (millis() - volMillis > 50) {
    volMillis = millis();

    int vol = map(currentThrottle, 0, 1023, VOL_MIN, VOL_MAX);

    if (vol > curVolume) curVolume = vol;
    else {
      curVolume -= (curVolume / 10);
      if (curVolume < VOL_MIN) curVolume = VOL_MIN;
    }

    int lastVolume = 0xFFFF;
    if (curVolume != lastVolume) {
      lastVolume = curVolume;
      writePot(curVolume);
    }
  }
}

// Write pot subfunction -----------------------------------------------------------------------------
void writePot(uint8_t data) {
  // This function should get a value from 0 - 127
  // It would be trivial to convert this to work with
  // an I2C device.

  if (data > VOL_MAX) data = VOL_MAX; // cap it just in case

  digitalWrite(POT_CS, LOW);
  shiftOut(POT_SDO, POT_SCK, MSBFIRST, 0x00);
  shiftOut(POT_SDO, POT_SCK, MSBFIRST, data);
  digitalWrite(POT_CS, HIGH);
}

//
// =======================================================================================================
// PCM setup
// =======================================================================================================
//

void setupPcm() {
  
  pinMode(SPEAKER, OUTPUT);
  audioRunning = true;

  // Set up Timer 2 to do pulse width modulation on the speaker pin.
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));                         // Use internal clock (datasheet p.160)

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

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

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

  // Set up Timer 1 to send a sample every interrupt.
  cli();

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

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

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

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

  lastSample = pgm_read_byte(&idle_data[idle_length - 1]);
  curEngineSample = 0;
  sei();


  uint8_t target = map(currentThrottle, 0, 1023, VOL_MIN, VOL_MAX); // Fadein the volume pot
  for (uint8_t i = 0; i < target; i ++) {
    curVolume = i;
    writePot(curVolume);
    delay(1);
  }
}

// ----------------------------------------------------------------------------------------------
void stopPlayback() {
  
  // Fadeout the volume pot
  for (uint8_t i = curVolume; i > 0; i--) {
    curVolume = i;
    writePot(i);
    delay(1);
  }

  audioRunning = false;

  TIMSK1 &= ~_BV(OCIE1A); // Disable playback per-sample interrupt.
  TCCR1B &= ~_BV(CS10);   // Disable the per-sample timer completely.
  TCCR2B &= ~_BV(CS10);   // Disable the PWM timer.

  digitalWrite(SPEAKER, LOW);
}

//
// =======================================================================================================
// NO RC SIGNAL PULSE?
// =======================================================================================================
//

void noPulse() {
  static unsigned long pulseDelayMillis;

  if (pulseAvailable) pulseDelayMillis = millis(); // reset delay timer, if pulses are available

  if (millis() - pulseDelayMillis > 100) {
    engineOn = false; // after 100ms delay, switch engine off
    curEngineSample = 0; // go to first sample
  }
  else engineOn = true;
}

//
// =======================================================================================================
// INTERRUPTS
// =======================================================================================================
//

// Uses a pin change interrupt and micros() to get the pulsewidth at pin 2 ---------------------------
void getPulsewidth() {
  unsigned long currentMicros = micros();
  boolean currentState = digitalRead(2);
  static unsigned long prevMicros = 0;
  static boolean lastState = LOW;

  if (lastState == LOW && currentState == HIGH) {    // Rising edge
    prevMicros = currentMicros;
    pulseAvailable = true;
    lastState = currentState;
  }
  else if (lastState == HIGH && currentState == LOW) { // Falling edge
    pulseWidth = currentMicros - prevMicros;
    pulseAvailable = false;
    lastState = currentState;
  }
}



// This is the main playback interrupt, keep this nice and tight!! -----------------------------------
ISR(TIMER1_COMPA_vect) {
  OCR1A = currentSmpleRate;

  if (curEngineSample >= idle_length) { // Loop the sample
    curEngineSample = 0;
  }

  if (engineOn) {
    OCR2B = pgm_read_byte(&idle_data[curEngineSample]); // Volume
    curEngineSample++;
  }
  else OCR2B = 255; // Stop engine (volume = 0)
}

Woyta
Příspěvky: 16
Registrován: 17 črc 2019, 17:04
Reputation: 0

Re: RC Sound module

Příspěvek od Woyta » 17 črc 2019, 23:49

Tak na jednu vec jsem prisel.
Pin D2 slouzi i jako preruseni 0.
A na tohle preruseni bylo navazano sledovani signalu.

Takze cele preruseni se smazalo. A v kodu ho nahradil prikaz: pulseWidth = pulseIn(A2, HIGH, 2500);
A uz to funguje jak potrebuju. :)
Problemy to nedela.

Ted jeste co s tim reprakem na pinu 3?

Woyta
Příspěvky: 16
Registrován: 17 črc 2019, 17:04
Reputation: 0

Re: RC Sound module

Příspěvek od Woyta » 18 črc 2019, 12:59

Copak mi blokuje piny D7-D12 :?:

Aktuální podoba programu.

Kód: Vybrat vše

/*
      This code was quick and dirty, based on a PCM audio example in the
      arduino playground: http://playground.arduino.cc/Code/PCMAudio

      It's been heavely modified for use with RC to generate something that's
      a bit like an engine sound. I've started work on making the program
      readable, still some to do though.
      https://github.com/BeigeMatchbox/mojoEngineSim/blob/master/README.md

      Enhancements, done by TheDIYGUY999 in january 2017: https://github.com/TheDIYGuy999/Rc_Engine_Sound
        - more sounds added,
        - also works on a 8MHz MCU, but not in servo throttle mode
*/

// All the required settings are done in settings.h!
#include "settings.h" // <<------- SETTINGS

const float codeVersion = 1.2; // Software revision

/*/Pins for lights
#define LIGHTS 0
#define LIGHTBAR 1
#define REVERSE 2
#define BRAKE 3
*/

//Pins for two winches
#define WINCH1WIND 7
#define WINCH1UNWIND 8
#define WINCH2WIND 9
#define WINCH2UNWIND 10

//Pins for turn signals
#define RIGHTTURN 12
#define LEFTTURN 13


// Stuff not to play with! ----------------------------------------------------------------------------
#define SPEAKER 3                               // This is kept as 3, original code had 11 as option, but this conflicts with SPI
volatile uint16_t currentSmpleRate = BASE_RATE; // Current playback rate, this is adjusted depending on engine RPM
boolean audioRunning = false;                   // Audio state, used so we can toggle the sound system
boolean engineOn = true;                        // Signal for engine on / off
uint16_t curVolume = 0;                         // Current digi pot volume, used for fade in/out
volatile uint16_t curEngineSample;              // Index of current loaded sample
uint8_t  lastSample;                            // Last loaded sample
int16_t  currentThrottle = 0;                   // 0 - 1000, a top value of 1023 is acceptable
uint8_t  throttleByte = 0;                      // Raw throttle position in SPI mode, gets mapped to currentThrottle
uint8_t  spiReturnByte = 0;                     // The current RPM mapped to a byte for SPI return
volatile int16_t pulseWidthCH2 = 0;                // Current pulse width for CH2 Throttle
volatile boolean pulseAvailable;                  // RC signal pulses are coming in
#define FREQ 16000000L                          // Always 16MHz, even if running on a 8MHz MCU!

int16_t pulseMaxNeutral; // PWM throttle configuration storage variables
int16_t pulseMinNeutral;
int16_t pulseMax;
int16_t pulseMin;
int16_t pulseMaxLimit;
int16_t pulseMinLimit;

unsigned int pulseWidthCH1 = 0;                // Current pulse width for CH1 Steering
                                               //CH2 In stuff not to play with!
unsigned int pulseWidthCH3 = 0;                // Current pulse width for CH3 C button for lights
unsigned int pulseWidthCH4 = 0;                // Current pulse width for CH4 Winch 1
unsigned int pulseWidthCH5 = 0;                // Current pulse width for CH5 Winch 2

unsigned int CH1 = 0;                // For cleaning up pulse value
                                     //Not used for CH2
unsigned int CH3 = 0;                // Current pulse width for CH3 C button for lights
unsigned int CH4 = 0;                // Current pulse width for CH4 Winch 1
unsigned int CH5 = 0;                // Current pulse width for CH5 Winch 2

//
// =======================================================================================================
// MAIN ARDUINO SETUP (1x during startup)
// =======================================================================================================
//

void setup() {

  Serial.begin(9600); //For diagnostic

  // MCP4131 digi pot
  pinMode(POT_CS, OUTPUT);
  pinMode(POT_SCK, OUTPUT);
  pinMode(POT_SDO, OUTPUT);
  digitalWrite(POT_CS, HIGH);
  digitalWrite(POT_SCK, HIGH);
  digitalWrite(POT_SDO, HIGH);

  // Lights outputs
/*  pinMode(LIGHTS, OUTPUT);
  pinMode(LIGHTBAR, OUTPUT);
  pinMode(BRAKE, OUTPUT);
  pinMode(REVERSE, OUTPUT);
  */
  pinMode(LEFTTURN, OUTPUT);
  pinMode(RIGHTTURN, OUTPUT);
/*  digitalWrite(LIGHTS, LOW);
  digitalWrite(LIGHTBAR, LOW);
  digitalWrite(BRAKE, LOW);
  digitalWrite(REVERSE, LOW);
  */
  digitalWrite(LEFTTURN, LOW);
  digitalWrite(RIGHTTURN, LOW);


  if (managedThrottle) writePot(0);
  else writePot(DEFAULT_VOLUME);


  // pwm in setup, for a standard servo pulse
  // We don't want INPUT_PULLUP as the 5v may damage some receivers!
  pinMode(A1, INPUT); // 1ch Steering
  pinMode(A2, INPUT); // 2ch Throttle
  pinMode(A3, INPUT); // 3ch C button for lights
  pinMode(A4, INPUT); // 4ch for winch 1
  pinMode(A5, INPUT); // 5ch for winch 2

  // Calculate throttle range
  pulseMaxNeutral = pulseZero + pulseNeutral;
  pulseMinNeutral = pulseZero - pulseNeutral;
  pulseMax = pulseZero + pulseSpan;
  pulseMin = pulseZero - pulseSpan;
  pulseMaxLimit = pulseZero + pulseLimit;
  pulseMinLimit = pulseZero - pulseLimit;

  // setup complete, so start making sounds
  setupPcm();
}

//
// =======================================================================================================
// MAIN LOOP
// =======================================================================================================
//

void loop() {
  
    doPwmThrottle();
    doTurnSignal();
    doWinch1();
    doWinch2();
    //noPulse();
  
  if (managedThrottle) manageSpeed();
}

//
// =======================================================================================================
// THROTTLES
// =======================================================================================================
//


// RC PWM signal -------------------------------------------------------------------------------------
void doPwmThrottle() {
  pulseWidthCH2 = pulseIn(A2, HIGH, 25000);
  if (pulseWidthCH2 > pulseMinLimit && pulseWidthCH2 < pulseMaxLimit) { // check if the pulseWidthCH2 looks like a servo pulse
    if (pulseWidthCH2 < pulseMin) pulseWidthCH2 = pulseMin; // Constrain the value
    if (pulseWidthCH2 > pulseMax) pulseWidthCH2 = pulseMax;

    if (pulseWidthCH2 > pulseMaxNeutral) currentThrottle = (pulseWidthCH2 - pulseZero) * 2; // make a throttle value from the pulseWidthCH2 0 - 1000
    else if (pulseWidthCH2 < pulseMinNeutral) currentThrottle = abs( (pulseWidthCH2 - pulseZero) * 2);
    else currentThrottle = 0;
  }

  if (!managedThrottle) {
    // The current sample rate will be written later, if managed throttle is active
    currentSmpleRate = FREQ / (BASE_RATE + long(currentThrottle * TOP_SPEED_MULTIPLIER));
  }
}


//
// =======================================================================================================
// LIGHTS
// =======================================================================================================
//

void    doTurnSignal() {
  static unsigned int CH1T;
  pulseWidthCH1 = pulseIn(A1, HIGH, 25000);
  
  if (pulseWidthCH1>10) {           //Primitive signal loss protection
    CH1=pulseWidthCH1;
    CH1T=0;
  }
  else {
    ++CH1T;
    if (CH1T> 10){ CH1=1250;
    CH1T=99;
    }
  }

                          if (CH1>1100 && CH1<1400)  //Temporary turn indicators for testing
                                  {
                                   digitalWrite(LEFTTURN, LOW);
                                   digitalWrite(RIGHTTURN, LOW);
                                  }
                                  else
                                  {
                                  if (CH1>1400)
                                        {
                                        digitalWrite(LEFTTURN, LOW);
                                        digitalWrite(RIGHTTURN, HIGH);
                                        }
                                        else
                                        {
                                        digitalWrite(LEFTTURN, HIGH);
                                        digitalWrite(RIGHTTURN, LOW);              
                                        }
                                  }
  
}


//
// =======================================================================================================
// WINCHES
// =======================================================================================================
//


// Winch 1 Pins 7,8 -------------------------------------------------------------------------------------
void    doWinch1() {
  static unsigned int CH4T;
  pulseWidthCH5 = pulseIn(A4, HIGH, 25000);
  
  if (pulseWidthCH4>10) {           //Primitive signal loss protection
    CH4=pulseWidthCH4;
    CH4T=0;
  }
  else {
    ++CH4T;
    if (CH4T> 5){ CH1=1250;
    CH4T=99;
    }
  }

                          if (CH4>1100 && CH4<1400)
                                  {
                                   digitalWrite(WINCH1WIND, LOW);
                                   digitalWrite(WINCH1UNWIND, LOW);
                                  }
                                  else
                                  {
                                  if (CH4>1400)
                                        {
                                        digitalWrite(WINCH1WIND, LOW);
                                        digitalWrite(WINCH1UNWIND, HIGH);
                                        }
                                        else
                                        {
                                        digitalWrite(WINCH1WIND, HIGH);
                                        digitalWrite(WINCH1UNWIND, LOW);              
                                        }
                                  }
  
}



// Winch 2 Pins 9,10------------------------------------------------------------------------------------
void    doWinch2() {
  static unsigned int CH5T;
  pulseWidthCH5 = pulseIn(A5, HIGH, 25000);
  
  if (pulseWidthCH5>10) {           //Primitive signal loss protection
    CH5=pulseWidthCH5;
    CH5T=0;
  }
  else {
    ++CH5T;
    if (CH5T> 5){ CH1=1250;
    CH5T=99;
    }
  }
        Serial.print("Channel 5:"); 
        Serial.println(pulseWidthCH5);

                          if (CH5>1100 && CH5<1400)
                                  {
                                   digitalWrite(WINCH2WIND, LOW);
                                   digitalWrite(WINCH2UNWIND, LOW);
                                  }
                                  else
                                  {
                                  if (CH5>1400)
                                        {
                                        digitalWrite(WINCH2WIND, LOW);
                                        digitalWrite(WINCH2UNWIND, HIGH);
                                        }
                                        else
                                        {
                                        digitalWrite(WINCH2WIND, HIGH);
                                        digitalWrite(WINCH2WIND, LOW);              
                                        }
                                  }
  
}

//
// =======================================================================================================
// MASS SIMULATION
// =======================================================================================================
//

void manageSpeed() {

  static int16_t prevThrottle = 0xFFFF;
  static int16_t currentRpm = 0;
  const  int16_t maxRpm = 8184; //8184
  const  int16_t minRpm = 0;

  static unsigned long throtMillis;
  static unsigned long startStopMillis;
  static unsigned long volMillis;

  // Engine RPM -------------------------------------------------------------------------------------
  if (millis() - throtMillis > 5) { // Every 5ms
    throtMillis = millis();

    if (currentThrottle + 18 > currentRpm) {
      currentRpm += 18;
      if (currentRpm > maxRpm) currentRpm = maxRpm;
      prevThrottle = currentThrottle;

    }
    else if (currentThrottle - 12 < currentRpm) {
      currentRpm -= 12;
      if (currentRpm < minRpm) currentRpm = minRpm;
      prevThrottle = currentThrottle;
    }

    if (currentRpm >> 2 < 255) spiReturnByte = currentRpm >> 2;
    else spiReturnByte = 255;
    if (currentRpm >> 2 < 0) spiReturnByte = 0;

    currentSmpleRate = FREQ / (BASE_RATE + long(currentRpm * TOP_SPEED_MULTIPLIER) );
  }

  // Engine volume (for MCP4131 digipot only) -------------------------------------------------------
  if (millis() - volMillis > 50) {
    volMillis = millis();

    int vol = map(currentThrottle, 0, 1023, VOL_MIN, VOL_MAX);

    if (vol > curVolume) curVolume = vol;
    else {
      curVolume -= (curVolume / 10);
      if (curVolume < VOL_MIN) curVolume = VOL_MIN;
    }

    int lastVolume = 0xFFFF;
    if (curVolume != lastVolume) {
      lastVolume = curVolume;
      writePot(curVolume);
    }
  }
}

// Write pot subfunction -----------------------------------------------------------------------------
void writePot(uint8_t data) {
  // This function should get a value from 0 - 127
  // It would be trivial to convert this to work with
  // an I2C device.

  if (data > VOL_MAX) data = VOL_MAX; // cap it just in case

  digitalWrite(POT_CS, LOW);
  shiftOut(POT_SDO, POT_SCK, MSBFIRST, 0x00);
  shiftOut(POT_SDO, POT_SCK, MSBFIRST, data);
  digitalWrite(POT_CS, HIGH);
}

//
// =======================================================================================================
// PCM setup
// =======================================================================================================
//

void setupPcm() {
  
  pinMode(SPEAKER, OUTPUT);
  audioRunning = true;

  // Set up Timer 2 to do pulse width modulation on the speaker pin.
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));                         // Use internal clock (datasheet p.160)

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

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

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

  // Set up Timer 1 to send a sample every interrupt.
  cli();

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

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

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

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

  lastSample = pgm_read_byte(&idle_data[idle_length - 1]);
  curEngineSample = 0;
  sei();


  uint8_t target = map(currentThrottle, 0, 1023, VOL_MIN, VOL_MAX); // Fadein the volume pot
  for (uint8_t i = 0; i < target; i ++) {
    curVolume = i;
    writePot(curVolume);
    delay(1);
  }
}

// ----------------------------------------------------------------------------------------------
void stopPlayback() {
  
  // Fadeout the volume pot
  for (uint8_t i = curVolume; i > 0; i--) {
    curVolume = i;
    writePot(i);
    delay(1);
  }

  audioRunning = false;

  TIMSK1 &= ~_BV(OCIE1A); // Disable playback per-sample interrupt.
  TCCR1B &= ~_BV(CS10);   // Disable the per-sample timer completely.
  TCCR2B &= ~_BV(CS10);   // Disable the PWM timer.

  digitalWrite(SPEAKER, LOW);
}

//
// =======================================================================================================
// NO RC SIGNAL PULSE?
// =======================================================================================================
//

void noPulse() {
  static unsigned long pulseDelayMillis;

  if (pulseAvailable) pulseDelayMillis = millis(); // reset delay timer, if pulses are available

  if (millis() - pulseDelayMillis > 100) {
    engineOn = false; // after 100ms delay, switch engine off
    curEngineSample = 0; // go to first sample
  }
  else engineOn = true;
}

//
// =======================================================================================================
// INTERRUPTS
// =======================================================================================================
//




// This is the main playback interrupt, keep this nice and tight!! -----------------------------------
ISR(TIMER1_COMPA_vect) {
  OCR1A = currentSmpleRate;

  if (curEngineSample >= idle_length) { // Loop the sample
    curEngineSample = 0;
  }

  if (engineOn) {
    OCR2B = pgm_read_byte(&idle_data[curEngineSample]); // Volume
    curEngineSample++;
  }
  else OCR2B = 255; // Stop engine (volume = 0)
}

Woyta
Příspěvky: 16
Registrován: 17 črc 2019, 17:04
Reputation: 0

Re: RC Sound module

Příspěvek od Woyta » 18 črc 2019, 16:48

Vrtám se a zkouším.
A narazil jsem na vtipnou věc. Signál pro generátor beru z pinu A2.
Pokud ale přivedu signál současně na A1 a A3 tak generování zvuku také funguje. WTF?

Woyta
Příspěvky: 16
Registrován: 17 črc 2019, 17:04
Reputation: 0

Re: RC Sound module

Příspěvek od Woyta » 23 črc 2019, 21:16

No vidim, ze vystupu bude malo, takze pin expander MCP23017 bude nutnost pridat do projektu.

Woyta
Příspěvky: 16
Registrován: 17 črc 2019, 17:04
Reputation: 0

Re: RC Sound module

Příspěvek od Woyta » 09 srp 2019, 03:35

Trošičku se to začíná komplikovat. :D
Obrázek

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 10 hostů