200 lines
4.5 KiB
C++
200 lines
4.5 KiB
C++
#include <math.h>
|
|
|
|
#define PIN_DATA_VOL_A 8
|
|
#define PIN_DATA_VOL_B 7
|
|
#define PIN_DATA_VOL_C 6
|
|
#define PIN_DATA_VOL_D 5
|
|
#define PIN_DATA_CLOCK 9
|
|
#define PIN_SR_DATA 2
|
|
#define PIN_SR_LTCH 3
|
|
#define PIN_SR_CLOCK 4
|
|
#define PIN_LED 13
|
|
|
|
// Serial Protocol:
|
|
// 9600 Baud
|
|
// 1 char: room number 1-5
|
|
// 2 char: command v (volume) / r (relais)
|
|
// relais command:
|
|
// 3 char: a or b
|
|
// volume command:
|
|
// 3-5 char: 0-100 volume
|
|
|
|
|
|
long tick;
|
|
uint16_t relaisData = 0xffff;
|
|
|
|
void setup() {
|
|
Serial.begin(9600);
|
|
Serial.setTimeout(100);
|
|
|
|
pinMode(PIN_DATA_VOL_A, OUTPUT);
|
|
pinMode(PIN_DATA_VOL_B, OUTPUT);
|
|
pinMode(PIN_DATA_VOL_C, OUTPUT);
|
|
pinMode(PIN_DATA_VOL_D, OUTPUT);
|
|
pinMode(PIN_DATA_CLOCK, OUTPUT);
|
|
pinMode(PIN_SR_DATA, OUTPUT);
|
|
pinMode(PIN_SR_LTCH, OUTPUT);
|
|
pinMode(PIN_SR_CLOCK, OUTPUT);
|
|
pinMode(PIN_LED, OUTPUT);
|
|
|
|
// shift out one time 0xffff to set all pins high. our relais boards
|
|
// are active-low
|
|
shiftRelais(relaisData);
|
|
|
|
setVolume(1, 50);
|
|
setVolume(2, 50);
|
|
setVolume(3, 50);
|
|
setVolume(4, 50);
|
|
setVolume(5, 50);
|
|
|
|
}
|
|
|
|
void shiftRelais(uint16_t data) {
|
|
digitalWrite(PIN_SR_LTCH, LOW);
|
|
shiftOut(PIN_SR_DATA, PIN_SR_CLOCK, MSBFIRST, (data >> 8));
|
|
shiftOut(PIN_SR_DATA, PIN_SR_CLOCK, MSBFIRST, data & 0xff);
|
|
digitalWrite(PIN_SR_LTCH, HIGH);
|
|
}
|
|
|
|
// channel is our "room" 1-5 / state for switching between A or B input
|
|
void switchInputs(uint8_t channel, bool state) {
|
|
|
|
// 16 . . . . . . . . . . . . . . . . . . . 0
|
|
|
|
// we use a simple switch case with some if instead of
|
|
// tricky bitmagic to allow a more visual programming
|
|
// of our relais configuration
|
|
|
|
switch(channel) {
|
|
case 1:
|
|
if(state) {
|
|
relaisData |= _BV(7) | _BV(6);
|
|
} else {
|
|
relaisData &= ~(_BV(7) | _BV(6));
|
|
}
|
|
break;
|
|
case 2:
|
|
if(state) {
|
|
relaisData |= _BV(5) | _BV(4);
|
|
} else {
|
|
relaisData &= ~(_BV(5) | _BV(4));
|
|
}
|
|
break;
|
|
case 3:
|
|
if(state) {
|
|
relaisData |= _BV(3) | _BV(2);
|
|
} else {
|
|
relaisData &= ~(_BV(3) | _BV(2));
|
|
}
|
|
break;
|
|
case 4:
|
|
if(state) {
|
|
relaisData |= _BV(1) | _BV(0);
|
|
} else {
|
|
relaisData &= ~(_BV(1) | _BV(0));
|
|
}
|
|
break;
|
|
case 5:
|
|
if(state) {
|
|
relaisData |= (_BV(15) | _BV(14));
|
|
} else {
|
|
relaisData &= ~(_BV(15) | _BV(14));
|
|
}
|
|
break;
|
|
}
|
|
|
|
shiftRelais(relaisData);
|
|
|
|
}
|
|
|
|
uint8_t logify(uint8_t volumelinear){
|
|
double volumelog=log10( ((double)volumelinear)/10.0 +1)*97;
|
|
return (int)volumelog;
|
|
}
|
|
|
|
// control a M62429 Chip for Volume Control
|
|
// function take from here: http://forum.arduino.cc/index.php?topic=244152.0
|
|
void setVolume(uint8_t volume, uint8_t dataPin) {
|
|
uint8_t bits;
|
|
uint16_t data = 0; // control word is built by OR-ing in the bits
|
|
|
|
// convert attenuation to volume / remember 0 is full volume!
|
|
volume = (volume > 100) ? 0 : (((volume * 83) / -100) + 83);
|
|
|
|
data |= (0 << 0);
|
|
data |= (0 << 1);
|
|
data |= ((21 - (volume / 4)) << 2);
|
|
data |= ((3 - (volume % 4)) << 7);
|
|
data |= (0b11 << 9);
|
|
|
|
for (bits = 0; bits < 11; bits++) {
|
|
_delay_us(2);
|
|
digitalWrite(dataPin, 0);
|
|
_delay_us (2);
|
|
digitalWrite(PIN_DATA_CLOCK, 0);
|
|
_delay_us (2);
|
|
digitalWrite(dataPin, (data >> bits) & 0x01);
|
|
_delay_us (2);
|
|
digitalWrite(PIN_DATA_CLOCK, 1);
|
|
}
|
|
|
|
_delay_us(2);
|
|
digitalWrite(dataPin, 1); // final clock latches data in
|
|
_delay_us (2);
|
|
digitalWrite(PIN_DATA_CLOCK, 0);
|
|
}
|
|
|
|
|
|
void loop() {
|
|
|
|
long currentMillis = millis();
|
|
|
|
if (Serial.available() > 0) {
|
|
String ser = Serial.readString();
|
|
|
|
int room = ser.charAt(0) - 48;
|
|
|
|
if(room >= 1 && room <= 5) {
|
|
|
|
char command = ser.charAt(1);
|
|
|
|
if(command == 'v') { //volume
|
|
int datapin=0;
|
|
|
|
switch(room){
|
|
case 1:
|
|
datapin=PIN_DATA_VOL_A;
|
|
break;
|
|
case 2:
|
|
datapin=PIN_DATA_VOL_B;
|
|
break;
|
|
case 3:
|
|
datapin=PIN_DATA_VOL_C;
|
|
break;
|
|
case 4:
|
|
datapin=PIN_DATA_VOL_D;
|
|
break;
|
|
}
|
|
|
|
int vol=ser.substring(2).toInt();
|
|
setVolume(logify(vol),datapin);
|
|
|
|
} else if(command == 'r') { // relais
|
|
|
|
char state = ser.charAt(2);
|
|
|
|
if (state=='a') {
|
|
switchInputs(room,true);
|
|
} else if (state=='b') {
|
|
switchInputs(room,false);
|
|
}
|
|
|
|
} // end if command check
|
|
} // end if room check
|
|
} // end serial available check
|
|
}
|
|
|
|
|
|
|
|
|