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 cablings inside the box. Now it's using WiFi. The new radio module I installed in the controller box is Adafruit's 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)

Inside...

Outside...

100 Ohm resistor ladder...

Below are parts list, schematics, firmware and a SuperCollider class.
redThermoKontroll (WiFi version) parts list: 1 4067 multiplexer 1 ATmega328p 1 16 MHz crystal 2 27p ceramic caps 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

//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;
//--analogue 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);
}
}
Attachments: | |
---|---|
redThermoKontroll2-supercollider.zip |