I'm using Arduino's analogWrite() function to control volume.
By pressing an up or down button I hope to adjust the volume incrementally....it kinda works, but the values are linear so the volume isn't smooth.
so......
I've been looking at using Arduino Playground - Fscale but I can't seem to get it working.
Cheers in advance
//////////////
// Melodies //
//////////////
const unsigned long melody[8] = {c5,d5,e5,f5,g5,a5,b5,c6};
const unsigned long melody2[8] = {c6,as5,gs5,g5,f5,ds5,d5,c5};
const unsigned long melody3[6] = {c4,d4,e4,g4,a4,c5};
const unsigned long melody4[7] = {c5,as4,g4,fs4,f4,ds4,c4};
////////////////////
// Pin Assignment //
////////////////////
const byte dataPin = 4;
const byte latchPin = 5;
const byte clockPin = 6;
const byte button1 = 0;
const byte button2 = 2;
const byte button3 = 12;
const byte button4 = 10;
const byte upButton = 7;
const byte selectButton = 8;
const byte downButton = 9;
const byte xAxis = 0;
const byte yAxis = 1;
const byte zAxis = 2;
/////////////////////////////
// Temporary Memory Stores //
/////////////////////////////
byte sr1 = 0;
byte sr2 = 0;
byte t = 0;
unsigned int mainVOLUME = 0;
unsigned int VOLUME = 0;
boolean state = false;
int note = 0;
int mult = 8;
int attack = 1;
int sustain = 0;
int release = 4;
int velocity = 200;
int gap = 10;
///////////
// Setup //
///////////
void setup()
{
/////////////////////////////////////////////////////////////////////////////////////
// Configure PWM on pins 3 and 11 to run at maximum speed, rather than the default //
/////////////////////////////////////////////////////////////////////////////////////
pinMode(3,OUTPUT); // speaker on pin 3
pinMode(11,OUTPUT); // amp on pin 11
cli(); // disable interrupts while registers are configured
bitSet(TCCR2A, WGM20);
bitSet(TCCR2A, WGM21); // set Timer2 to fast PWM mode (doubles PWM frequency on pins 3 & 11)
bitSet(TCCR2B, CS20);
bitClear(TCCR2B, CS21);
bitClear(TCCR2B, CS22);
sei(); // enable interrupts now that registers have been set
/////////////////////////////////////////////////////////////////////////////////////
// LED Shift Registers
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
// Main Buttons
pinMode(button1, INPUT);
pinMode(button2, INPUT);
pinMode(button3, INPUT);
pinMode(button4, INPUT);
// Menu Buttons
pinMode(upButton, INPUT); // Up Button
pinMode(selectButton, INPUT); // Select Button
pinMode(downButton, INPUT); // Down Button
// Set All Button Pins High
digitalWrite(button1, HIGH);
digitalWrite(button2, HIGH);
digitalWrite(button3, HIGH);
digitalWrite(button4, HIGH);
digitalWrite(upButton, HIGH);
digitalWrite(selectButton, HIGH);
digitalWrite(downButton, HIGH);
Serial.begin(9600);
setupLCD();
analogWrite(11, mainVOLUME);
Serial.print("Volume = ");
Serial.print(mainVOLUME / 2.55);
playMelody();
}
///////////////
// Main Loop //
///////////////
void loop()
{
if(digitalRead(upButton) == LOW && mainVOLUME < 255) // If Up Button Is Pressed
{
mainVOLUME++;
clearLCD();
selectLineOne();
Serial.print("Volume = ");
Serial.print(mainVOLUME / 2.55);
[glow]mainVOLUME = fscale(0, 255, 0.0, 255.0, mainVOLUME, -2.0);[/glow]
analogWrite(11, mainVOLUME);
selectLineTwo();
Serial.print("Actual = ");
Serial.print(mainVOLUME);
playTone(c8,5);
delay(10);
}
if(digitalRead(downButton) == LOW && mainVOLUME > 0) // If Down Button Is Pressed
{
mainVOLUME--;
clearLCD();
selectLineOne();
Serial.print("Volume = ");
Serial.print(mainVOLUME / 2.55);
[glow]mainVOLUME = fscale(0, 255, 0.0, 255.0, mainVOLUME, -2.0);[/glow]
analogWrite(11, mainVOLUME);
selectLineTwo();
Serial.print("Actual = ");
Serial.print(mainVOLUME);
playTone(c8,5);
delay(10);
}
if(digitalRead(selectButton) == LOW) // If Select Button Is Pressed
{
clearLCD();
selectLineOne();
Serial.print("Select");
selectLineTwo();
Serial.print("Button Pressed");
playTone(c9,5);
}
if(digitalRead(upButton) == HIGH && digitalRead(downButton) == HIGH && digitalRead(selectButton) == HIGH)
{
playMelody();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////
// Shift Data To LEDs //
////////////////////////
void shift()
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, sr2);
shiftOut(dataPin, clockPin, MSBFIRST, sr1);
digitalWrite(latchPin, HIGH);
}
/////////////////////////
// Functions For Sound //
/////////////////////////
void playTone(int tone, int duration)
{
for (long i = 0; i < duration * 1000L; i += tone * 2)
{
analogWrite(3, VOLUME);
delayMicroseconds(tone);
analogWrite(3, 0);
delayMicroseconds(tone);
}
}
void playMelody()
{
if(state == false) // Ramp Up Note (Attack)
{
VOLUME += mult;
playTone(melody[note], attack);
}
if(state == true) // Ramp Down Note (release)
{
VOLUME -= mult;
playTone(melody[note], release);
}
if(VOLUME >= velocity)
{
playTone(melody[note], sustain);
state = true;
}
if(VOLUME <= 0)
{
delay(gap);
note++;
state = false;
}
if (note >= 8) // If last note in sequence is reached then reset to the begining
{
note = 0;
}
}
///////////////////////
// Functions for LCD //
///////////////////////
void clearLCD()
{
Serial.print(0xFE, BYTE); // Command Flag
Serial.print(0x01, BYTE); // Clear Command
}
void selectLineOne()
{
Serial.print(0xFE, BYTE); // Command Flag
Serial.print(128, BYTE); // puts the cursor at line 0 char 0.
}
void selectLineTwo()
{
Serial.print(0xFE, BYTE); // Command Flag
Serial.print(192, BYTE); // puts the cursor at line 2 char 0.
}
void setupLCD()
{
// Serial.print(0x7C, BYTE); // Command Flag
// Serial.print(0x09, BYTE); // Splash Screen Toggle on/off
// Serial.print(0x7C, BYTE); // Command Flag
// Serial.print(0x0C, BYTE); // Display On
// Serial.print(0x7C, BYTE); // Command Flag
// Serial.print(0x0D, BYTE); // Baud Rate: 9600
// Serial.print(0x7C, BYTE); // Command Flag
// Serial.print(157, BYTE); // Backlight On
Serial.print(0x07, BYTE); // Command Flag
Serial.print(18, BYTE); // reset LCD
clearLCD();
selectLineOne();
}
[glow]float fscale( float originalMin, float originalMax, float newBegin, float
newEnd, float inputValue, float curve){
float OriginalRange = 0;
float NewRange = 0;
float zeroRefCurVal = 0;
float normalizedCurVal = 0;
float rangedValue = 0;
boolean invFlag = 0;
// condition curve parameter
// limit range
if (curve > 10) curve = 10;
if (curve < -10) curve = -10;
curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output
curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function
/*
Serial.println(curve * 100, DEC); // multply by 100 to preserve resolution
Serial.println();
*/
// Check for out of range inputValues
if (inputValue < originalMin) {
inputValue = originalMin;
}
if (inputValue > originalMax) {
inputValue = originalMax;
}
// Zero Refference the values
OriginalRange = originalMax - originalMin;
if (newEnd > newBegin){
NewRange = newEnd - newBegin;
}
else
{
NewRange = newBegin - newEnd;
invFlag = 1;
}
zeroRefCurVal = inputValue - originalMin;
normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float
/*
Serial.print(OriginalRange, DEC);
Serial.print(" ");
Serial.print(NewRange, DEC);
Serial.print(" ");
Serial.println(zeroRefCurVal, DEC);
Serial.println();
*/
// Check for originalMin > originalMax - the math for all other cases i.e. negative numbers seems to work out fine
if (originalMin > originalMax ) {
return 0;
}
if (invFlag == 0){
rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;
}
else // invert the ranges
{
rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);
}
return rangedValue;
}
[/glow]