#include <MozziGuts.h> // Mozzi main library
#include <Oscil.h> // Mozzi template for an oscillator
#include <tables/sin2048_int8.h> // Mozzi wavetable holding a sine wave
#include <twi_nonblock.h> // Mozzi non-blocking I2C Library
#include <Metronome.h> // Mozzi metronome / task scheduler
#include <Smooth.h> // Mozzi sound smoothening library
#include <avr/wdt.h> // AVR Watchdog library
// --- Mozzi definitions ---
Oscil <2048, AUDIO_RATE> aSin(SIN2048_DATA); // defines an sine tone oscillator with the sin2048 wavetable. Structure: Oscil <table_size, update_rate> name(table_data);
#define CONTROL_RATE 1024 // number of control updates per second, only powers of 2
volatile int audioFrequency = 440; // stores present audio frequency
volatile byte volume = 100; // stores present selected volume
volatile boolean mute = false; // stores audio mute state
// --- Ultrasonic Sensor I2C definitions ---
#define ULT_ADDRESS 0x70 // I2CXL-Maxsonar-EZ device address
#define ULT_INIT_RANGING 0x51 // Initiate range reading
// --- Ultrasonic Sensor constants and variables ---
static volatile byte ult_status = 0; // Status byte
#define ULT_IDLE 0
#define ULT_READING 1
#define ULT_WRITING 2
#define AVERAGING_SIZE 3
byte ult_bytedata[2]; // Ultrasonic Sensor distance Information in two bytes
int ult_distance[AVERAGING_SIZE]; // Ultrasonic Sensor distance Information as Integer
int ult_clean_distance = 0;
byte averagingCounter = 0;
// --- Task schedulers ---
Metronome parameterScheduler(10); // update input parameters all 10ms
Metronome sonarScheduler(50); // read sonar every 50ms
Metronome frequencyScheduler(50*AVERAGING_SIZE); // change frequency every 150ms
// --- Smoothening ---
Smooth <int> smoothFreq(0.975f);
volatile int targetFrequency;
void setup() {
delay(400); // wait for stable power supply
wdt_enable(WDTO_2S); // enable watchdog timer, 2 second timeout
Serial.begin(9600); // serial debug
Serial.println("Gestartet"); // debug
startMozzi(CONTROL_RATE); // start sound library
initialize_twi_nonblock(); // initialize I2C library and join I2C-Bus
}
void updateControl() {
wdt_reset(); // reset watchdog
int smoothedFrequency = smoothFreq.next(targetFrequency);
aSin.setFreq(smoothedFrequency);
if (parameterScheduler.ready() == true)
{
volume = 0; // debug
}
if (sonarScheduler.ready() == true)
{
ult_ranging();
targetFrequency = audioFrequency; // debug
}
if (frequencyScheduler.ready() == true)
{
//targetFrequency = some mathematical function which uses ult_clean_distance
}
}
int updateAudio() {
return (aSin.next() * volume)>>8;
}
void initiate_read_maxbotix()
{
// Reads num bytes starting from address register on device in to _buff array
// indicate that we are transmitting
// transmitting = 1;
// set address of targeted slave
txAddress = ULT_ADDRESS;
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// put byte in tx buffer
txBuffer[txBufferIndex] = ULT_INIT_RANGING;
++txBufferIndex;
// update amount in buffer
txBufferLength = txBufferIndex;
twi_initiateWriteTo(txAddress, txBuffer, txBufferLength);
ult_status = ULT_WRITING;
}
void initiate_request_maxbotix()
{
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
// transmitting = 0;
byte read = twi_initiateReadFrom(ULT_ADDRESS, 2);
ult_status = ULT_READING;
}
void finalise_request_maxbotix()
{
byte read = twi_readMasterBuffer( rxBuffer, 2 );
// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = read;
byte i = 0;
while( rxBufferLength - rxBufferIndex > 0) // device may send less than requested (abnormal)
{
ult_bytedata[i] = rxBuffer[rxBufferIndex];
++rxBufferIndex;
i++;
}
ult_status = ULT_IDLE;
}
void ult_ranging()
{
switch( ult_status ){
case ULT_IDLE:
ult_distance[averagingCounter-1] = (int) (ult_bytedata[0]*256 + ult_bytedata[1]); // Ultrasonic Sensor distance reading
initiate_read_maxbotix();
if (averagingCounter < AVERAGING_SIZE)
{
averagingCounter++;
}
else
{
averagingCounter = 0;
filter_range();
}
break;
case ULT_WRITING:
if ( TWI_MTX != twi_state ){
initiate_request_maxbotix();
}
break;
case ULT_READING:
if ( TWI_MRX != twi_state ){
finalise_request_maxbotix();
}
break;
}
}
void filter_range()
{
isort(ult_distance, AVERAGING_SIZE);
ult_clean_distance = mode(ult_distance, AVERAGING_SIZE);
}
//Sorting function
void isort(int *a, int n){
// *a is an array pointer function
for (int i = 1; i < n; ++i)
{
int j = a[i];
int k;
for (k = i - 1; (k >= 0) && (j < a[k]); k--)
{
a[k + 1] = a[k];
}
a[k + 1] = j;
}
}
//Mode function, returning the mode or median.
int mode(int *x,int n){
int i = 0;
int count = 0;
int maxCount = 0;
int mode = 0;
int bimodal;
int prevCount = 0;
while(i<(n-1)){
prevCount=count;
count=0;
while(x[i]==x[i+1]){
count++;
i++;
}
if(count>prevCount&count>maxCount){
mode=x[i];
maxCount=count;
bimodal=0;
}
if(count==0){
i++;
}
if(count==maxCount){//If the dataset has 2 or more modes.
bimodal=1;
}
if(mode==0||bimodal==1){//Return the median if there is no mode.
mode=x[(n/2)];
}
return mode;
}
}
void loop() {
audioHook();
}