Sunday, April 16, 2023

Twitch-n-howl Code and Schematics v2.2



 

Code:




//  Jekyll-Labs Twitch and Sound 
//  Built for Twitchnhowl v2.2
//
//  D2 unused
//  D3 Power MOSFET (PWM avail)
//  D4 unused
//  D5 On Board LED1
//  D6 On Board LED2
//  D7 SoftSerial Tx
//  D8 SoftSerial Rx
//  D9 Trigger Input
//  D10 unused
//  D11 MOSI
//  D12 MISO
//  D13 SCK
//  A0/D14 unused
//  A1/D15 unused
//  A2/D16 unused
//  A3/D17 Potentiometer Top
//  A4/D18 Potentiometer Middle
//  A5/D19 Potentiometer Bottom
//  A6/D20 unused
//  A7/D21 unused

//include libraries
#include "Arduino.h"
#include "SoftwareSerial.h"

// set pin identification
int fetpin = 3;
int trigpin = 9;
int led1 = 5;
int led2 = 6;
int potMpin = A4;
int potTpin = A3;
int potBpin = A5;

//set SoftSerial for JQ8900 and basic Hex commands
SoftwareSerial mySoftwareSerial(8, 7); // RX, TX
byte playnext[] = {0xAA, 0x06, 0x00, 0xB0 };

// set global constants
unsigned long durationlow = 200; // low end of duration range in msec [0.2sec]
unsigned long durationhigh = 15000; // high end of duration range in msec [15sec]
long intervallow = 2000; // low end of interval range in sec [2 sec]
long intervalmid = 10000; // middle of interval range in sec [10sec]
long intervalhigh = 90000; // high end of interval range in sec [90sec]
long intervalmax = 36000000; // interval in sec if pot maxed out [10hrs]
unsigned long mosfetdelay = 0; // extra delay to turn mosfet on after audio triggered [0]

// initialize global variables
long timeunit = 12; // mean untriggered time interval (sec)
unsigned long last = 0; 

unsigned long timeinterval = 0;
float exprob=0.50;

void setup() {
  // setup mosfet pin as output
  pinMode(fetpin, OUTPUT);
  digitalWrite(fetpin, LOW);

  // set up potentiometers and trigger pin
  pinMode(trigpin, INPUT);
  pinMode(potTpin, INPUT);
  pinMode(potMpin, INPUT);
  pinMode(potBpin, INPUT);

  // Set up and turn off LED
  pinMode(led1, OUTPUT);
  digitalWrite(led1, LOW);
  pinMode(led2, OUTPUT);
  digitalWrite(led2, LOW);

  // begin softserial for JQ8900
  mySoftwareSerial.begin(9600);
  
  last = millis(); // updates timer to start  
  randomSeed(A0);

}

void loop() {
  // duration of signal will last from 0.5 - 10 sec
  int durationpot = analogRead(potBpin);
  long duration = map(durationpot,100,1023,durationlow,durationhigh); 
  if (duration <500) duration = 150;

  // read middle pot for PWM of fet signal
  int PWMpot = analogRead(potMpin);
  int PWM = map(PWMpot,0,1000,0,255);
  if (PWM>255) PWM = 255;

  // mean frequency of random signals is 1 events per timeunit
  int intervalpot = analogRead(potTpin);
  long timeunit = map(intervalpot,512,1023,intervalmid,intervalhigh); // 2nd half dial range 12-60 sec
  if (intervalpot>1000) timeunit = intervalmax; // far right dial 1hr
  if (intervalpot<512) timeunit = map(intervalpot,75,512,intervallow,intervalmid); // 1st half dial range 0-12 sec
  if (intervalpot<75) timeunit = 0; // bottom of dial continous on  

  if (timeunit<=0){ // continuous on if left dial all counter clockwise
    analogWrite(fetpin,PWM);
    digitalWrite(led2,HIGH);
  }
  
  else {
    // Check for trigger (X3 for debounce) and adjust
    // timeunit if trigger is positive.
    if (timeunit>0) {
      int trigger = digitalRead(trigpin);  
      if (trigger == HIGH) {
        delay(100);
        int trigger = digitalRead(trigpin);
        if (trigger == HIGH) {
          delay (100);
          int trigger = digitalRead(trigpin);
          if (trigger == HIGH) {
            timeunit = 2000; // minimum mean interval in sec for triggered events
            digitalWrite(led1,HIGH);
          }
        }
      }
      if (trigger == LOW) digitalWrite(led1,LOW);
    }

    // Calcuate time interval between events. timeunit depends on:
    // Potentiometer value if trig = 0 (not triggered) 
    // Duration multiplier (shorter) if trig = 1
    unsigned long timeinterval = exprob * timeunit;    
    
    // Check if time interval has passed and if so trigger event
    if ((millis() - last) > timeinterval) {
      last = millis(); // updates timer to last event
      digitalWrite(led2,HIGH); // indicator LED
      mySoftwareSerial.write(playnext, sizeof(playnext)); // play next MP3
      delay(10);
      if (random(2)<1) mySoftwareSerial.write(playnext, sizeof(playnext)); // 50% of the time skip to next MP3
      delay(100 + mosfetdelay); 
      analogWrite(fetpin,PWM);  // turn on mosfet
      delay(duration);
      digitalWrite(fetpin,LOW);
      digitalWrite(led2,LOW);
      
      // the following equation runs once per event and 
      // generates a random float (exprob) that falls in an 
      // exponential distribution. It will be used to
      // determine the interval time for the next event.
      // Events that occur at exponentially distributed  
      // intervals form poisson processes.
      exprob =  (-2)*(log((100-random(100))/100.00));
    }
    else {
      digitalWrite(fetpin,LOW);
      digitalWrite(led2,LOW);
    }
  }
  delay(20);
}


No comments:

Post a Comment