redThermoKontroll2

for my upcoming solo at the sound of stockholm festival, i decided to rebuild my main wireless controller. previously it used a nordic nRF24L01+transceiver as radio module, but the range wasn't great and communication often broke down during live performances. i don't know much about these things, but i guess that when the audience bring in mobile phones the radio spectrum quickly fills up.

so i constructed a new circuit from scratch and while i was at it also reworked the resistor ladders and other cabling inside the box. now it's using wifi. the new radio module i installed in the controller box is adafruit's great CC3000 WiFi Breakout, and as receiver i use a small tl-wr703n wifi router running openwrt.
the wireless range is now excellent and everything is a lot more stable. i could also drastically reduce the amount of data being sent by fixing the resistor ladders.

circuit... (basically just one atmega382p, a 16 channel adc, voltage divider resistors and the wifi module)

redThermoKontroll2-00

inside...
redThermoKontroll2-01

outside...
redThermoKontroll2-02

100ohm resistor ladder...

redThermoKontroll2-03

below are parts list, schematics, firmware and a supercollider class.

redThermoKontroll (wifi version) parts list:

1 4067 multiplexer
1 atmega328p
1 16mhz crystal
2 27p
1 socket 2x14 (28pin)
1 adafruit cc3000 module
1 1x9 pin header
1 1x10 pin header
1 1x8 pin header
1 1x5 pin header

1 resettable fuse 1a
1 zener diode 5.6v
1 0.1uF cap
1 100uF electrolytic cap
1 470uF electrolytic cap

10 220, 270, 330, 680, 1k, 2, 10k resistors
1 220 resistor for led

1 power jack
1 ldr
1 red led

lots of 100ohm resistors for resistor ladders

redThermoKontroll-schematics2

//redThermoKontroll2
//redFrik 2013 gnu gpl v2
//updated 150920 - automatically send to IP x.x.x.99 (constructed from given DHCP IP)

//make sure to use Paul Stoffregen's branch of the Adafruit_CC3000 library
//and cc3000 firmware 1.24 (1.11.1)
//select board UNO and upload to a ATMEGA328P chip (using a usbtinyisp programmer)
//test in terminal with command: nc -ul 58100

#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>

#define WLAN_SSID       "xxx"
#define WLAN_PASS       "yyy"
#define WLAN_SECURITY   WLAN_SEC_WPA2

#define PORT            58100
#define DELAY           10
#define PINGRATE        2000

#define ADAFRUIT_CC3000_IRQ   3   //mega328 pin 5
#define ADAFRUIT_CC3000_VBEN  8   //mega328 pin 14
#define ADAFRUIT_CC3000_CS    10  //mega328 pin 16
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBEN, SPI_CLOCK_DIVIDER);
Adafruit_CC3000_Client client;

uint8_t buf[16];
byte last[] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

byte cnt = 0;
unsigned long time;

void setup(void) {
  Serial.begin(115200);  //debug

  //--pins
  pinMode(7, OUTPUT);         //led
  pinMode(6, OUTPUT);         //4067 d (DDD6)
  pinMode(5, OUTPUT);         //4067 c (DDD5)
  pinMode(4, OUTPUT);         //4067 b (DDD4)
  pinMode(2, OUTPUT);         //4067 a (DDD2)
  pinMode(A5, INPUT);         //4067 x
  pinMode(A4, INPUT_PULLUP);  //capa1 (right)
  pinMode(A3, INPUT_PULLUP);  //capa0 (left)
  pinMode(A2, INPUT_PULLUP);  //swiUp (up)
  pinMode(A1, INPUT_PULLUP);  //swiUp (down)
  pinMode(A0, INPUT_PULLUP);  //swiOn

  //--wifi
  flash(1);
  Serial.println(F("Starting"));
  if (!cc3000.begin()) {
    Serial.println(F("Unable to initialise the CC3000! Check your wiring?"));
    while (1);
  }
  flash(2);
  Serial.println(F("\nDeleting old connection profiles"));
  if (!cc3000.deleteProfiles()) {
    Serial.println(F("Failed!"));
    while (1);
  }
  cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
  Serial.println(F("Connected!"));
  flash(3);
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()) {
    delay(100); // ToDo: Insert a DHCP timeout!
  }
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
  while (!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv)) {
    Serial.println(F("Unable to retrieve the IP Address!"));
    delay(100);
  }
  Serial.print(F("\nCC3000 IP Addr: "));
  cc3000.printIPdotsRev(ipAddress);
  //the following sets receiver to x.x.x.99 and assume cc3000 will never get exactly that IP itself
  ipAddress = cc3000.IP2U32(ipAddress >> 24 & 255, ipAddress >> 16 & 255, ipAddress >> 8 & 255, 99);
  Serial.print(F("\nReceiver IP Addr: "));
  cc3000.printIPdotsRev(ipAddress);
  client = cc3000.connectUDP(ipAddress, PORT);

  //--osc message [/tk2, index, value]
  buf[0] = 47;   // /
  buf[1] = 116;  // t
  buf[2] = 107;  // k
  buf[3] = 50;   // 2
  buf[4] = 0;
  buf[5] = 0;
  buf[6] = 0;
  buf[7] = 0;
  buf[8] = 44;   // ,
  buf[9] = 105;  // i
  buf[10] = 0;
  buf[11] = 0;
  buf[12] = 0;   //msb - index
  buf[13] = 0;   //
  buf[14] = 0;   //
  buf[15] = 0;   //lsb - value
}

void loop(void) {
  byte val;

  //--analog inputs
  for (byte i = 0; i < 13; i++) {
    setChan(i);
    delay(1);                //not sure if needed
    val = analogRead(A5) >> 2; //from 10 to 8 bits
    if (val != last[i]) {
      sendOsc(i, val);
      last[i] = val;
    }
  }

  //--digital inputs
  val = PINC & 0b00011111;
  if (val != last[13]) {
    sendOsc(13, val);
    last[13] = val;
  }

  //--ping
  if (millis() - time > PINGRATE) {
    sendOsc(127, 0);      //ping
    time = millis();
  }
}

void sendOsc(byte index, byte val) {
  buf[12] = index;
  buf[15] = val;
  if (cnt++ % 2 == 0) {   //toggle red led
    PORTD &= ~_BV(DDD7);
  }
  else {
    PORTD |= _BV(DDD7);
  }
  client.write(buf, sizeof(buf));
  delay(DELAY);
}

void setChan(byte index) {
  switch (index) {
    case 0:
      PORTD &= ~_BV(DDD2);                                      //low
      PORTD &= ~_BV(DDD4);                                      //low
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 1:
      PORTD |= _BV(DDD2);                                               //high
      PORTD &= ~_BV(DDD4);                                      //low
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 2:
      PORTD &= ~_BV(DDD2);                                      //low
      PORTD |= _BV(DDD4);                                               //high
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 3:
      PORTD |= _BV(DDD2);                                               //high
      PORTD |= _BV(DDD4);                                               //high
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 4:
      PORTD &= ~_BV(DDD2);                                      //low
      PORTD &= ~_BV(DDD4);                                      //low
      PORTD |= _BV(DDD5);                                               //high
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 5:
      PORTD |= _BV(DDD2);                                               //high
      PORTD &= ~_BV(DDD4);                                      //low
      PORTD |= _BV(DDD5);                                               //high
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 6:
      PORTD &= ~_BV(DDD2);                                      //low
      PORTD |= _BV(DDD4);                                               //high
      PORTD |= _BV(DDD5);                                               //high
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 7:
      PORTD |= _BV(DDD2);                                               //high
      PORTD |= _BV(DDD4);                                               //high
      PORTD |= _BV(DDD5);                                               //high
      PORTD &= ~_BV(DDD6);                                      //low
      break;
    case 8:
      PORTD &= ~_BV(DDD2);                                      //low
      PORTD &= ~_BV(DDD4);                                      //low
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD |= _BV(DDD6);                                               //high
      break;
    case 9:
      PORTD |= _BV(DDD2);                                               //high
      PORTD &= ~_BV(DDD4);                                      //low
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD |= _BV(DDD6);                                               //high
      break;
    case 10:
      PORTD &= ~_BV(DDD2);                                      //low
      PORTD |= _BV(DDD4);                                               //high
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD |= _BV(DDD6);                                               //high
      break;
    case 11:
      PORTD |= _BV(DDD2);                                               //high
      PORTD |= _BV(DDD4);                                               //high
      PORTD &= ~_BV(DDD5);                                      //low
      PORTD |= _BV(DDD6);                                               //high
      break;
    case 12:
      PORTD &= ~_BV(DDD2);                                      //low
      PORTD &= ~_BV(DDD4);                                      //low
      PORTD |= _BV(DDD5);                                               //high
      PORTD |= _BV(DDD6);                                               //high
      break;
  }
}
void flash(int num) {
  for(byte i= 0; i<num; i++) {
    digitalWrite(7, HIGH);
    delay(100);
    digitalWrite(7, LOW);
    delay(100);
  }
}

AttachmentSize
Package icon redThermoKontroll2-supercollider.zip8.59 KB