Components and supplies
NPN transistor Toshiba 2SC5171
Erco Grasshopper
Arduino Nano R3
AC/DC converter (230V/12V 40W)
LED (generic)
Tools and machines
M-832
Apps and platforms
Arduino IDE
Visual Studio 2015
Project description
Code
DALI.zip
arduino
1inary file (no preview
Dali.cpp
arduino
1#include "Dali.h" 2#include <SoftwareSerial.h> 3 4 5 6Dali::Dali() //constructor 7{ 8 applyWorkAround1Mhz = 0; 9} 10 11 12void Dali::setTxPin(uint8_t pin) 13{ 14 TxPin = pin; // user sets the digital pin as output 15 pinMode(TxPin, OUTPUT); 16 digitalWrite(TxPin, HIGH); 17} 18 19void Dali::setRxAnalogPin(uint8_t pin) 20{ 21 RxAnalogPin = pin; // user sets the digital pin as output 22} 23 24void Dali::workAround1MhzTinyCore(uint8_t a) 25{ 26 applyWorkAround1Mhz = a; 27} 28 29void Dali::setupAnalogReceive(uint8_t pin) 30{ 31 setRxAnalogPin(pin); // user sets the analog pin as input 32} 33 34 35void Dali::setupTransmit(uint8_t pin) 36{ 37 setTxPin(pin); 38 speedFactor = 2; 39 //we don't use exact calculation of passed time spent outside of transmitter 40 //because of high ovehead associated with it, instead we use this 41 //emprirically determined values to compensate for the time loss 42 43 #if F_CPU == 1000000UL 44 uint16_t compensationFactor = 88; //must be divisible by 8 for workaround 45 #elif F_CPU == 8000000UL 46 uint16_t compensationFactor = 12; 47 #else //16000000Mhz 48 uint16_t compensationFactor = 4; 49 #endif 50 51#if (F_CPU == 80000000UL) || (F_CPU == 160000000) // ESP8266 80MHz or 160 MHz 52 delay1 = delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2; 53#else 54 delay1 = (HALF_BIT_INTERVAL >> speedFactor) - compensationFactor; 55 delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2; 56 period = delay1 + delay2; 57 58 #if F_CPU == 1000000UL 59 delay2 -= 22; //22+2 = 24 is divisible by 8 60 if (applyWorkAround1Mhz) { //definition of micro delay is broken for 1MHz speed in tiny cores as of now (May 2013) 61 //this is a workaround that will allow us to transmit on 1Mhz 62 //divide the wait time by 8 63 delay1 >>= 3; 64 delay2 >>= 3; 65 } 66 #endif 67#endif 68 69 } 70 71 72void Dali::transmit(uint8_t cmd1, uint8_t cmd2) // transmit commands to DALI bus (address byte, command byte) 73{ 74 sendBit(1); 75 sendByte(cmd1); 76 sendByte(cmd2); 77 digitalWrite(TxPin, HIGH); 78} 79 80 81void Dali::sendByte(uint8_t b) 82{ 83 for (int i = 7; i >= 0; i--) 84 { 85 sendBit((b >> i) & 1); 86 } 87} 88 89 90void Dali::sendBit(int b) 91{ 92 if (b) { 93 sendOne(); 94 } 95 else { 96 sendZero(); 97 } 98} 99 100 101void Dali::sendZero(void) 102{ 103 digitalWrite(TxPin, HIGH); 104 delayMicroseconds(delay2); 105 digitalWrite(TxPin, LOW); 106 delayMicroseconds(delay1); 107 108} 109 110 111void Dali::sendOne(void) 112{ 113 digitalWrite(TxPin, LOW); 114 delayMicroseconds(delay2); 115 digitalWrite(TxPin, HIGH); 116 delayMicroseconds(delay1); 117} 118 119 120void Dali::busTest() //DALI bus test 121{ 122 int maxLevel; 123 int minLevel; 124 125 //Luminaries must turn on and turn off. If not, check connection. 126 delay(100); 127 dali.transmit(BROADCAST_C, OFF_C); //Broadcast ON 128 delay(500); 129 dali.transmit(BROADCAST_C, ON_C); //Broadcast OFF 130 delay(100); 131 while (!Serial); 132 133 //Receive response from luminaries: max and min level 134 dali.transmit(BROADCAST_C, QUERY_STATUS); 135 maxLevel = dali.maxResponseLevel(); 136 dali.transmit(BROADCAST_C, QUERY_STATUS); 137 minLevel = dali.minResponseLevel(); 138 139 dali.analogLevel = (int)(maxLevel + minLevel) / 2; 140 141 142 143 144 145} 146 147 148void Dali::splitAdd(long input, uint8_t &highbyte, uint8_t &middlebyte, uint8_t &lowbyte) 149{ 150 highbyte = input >> 16; 151 middlebyte = input >> 8; 152 lowbyte = input; 153} 154 155 156 157// define min response level 158int Dali::minResponseLevel() 159{ 160 161 const uint8_t dalistep = 40; //us 162 uint16_t rxmin = 1024; 163 uint16_t dalidata; 164 long idalistep; 165 166 167 168 for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) { 169 dalidata = analogRead(RxAnalogPin); 170 if (dalidata < rxmin) { 171 rxmin = dalidata; 172 }; 173 delayMicroseconds(dalistep); 174 } 175 return rxmin; 176} 177 178// define max response level 179int Dali::maxResponseLevel() 180{ 181 182 const uint8_t dalistep = 40; //us 183 uint16_t rxmax = 0; 184 uint16_t dalidata; 185 long idalistep; 186 187 188 for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) { 189 dalidata = analogRead(dali.RxAnalogPin); 190 if (dalidata > rxmax) { 191 rxmax = dalidata; 192 }; 193 delayMicroseconds(dalistep); 194 } 195 return rxmax; 196} 197 198 199//scan for individual short address 200void Dali::scanShortAdd() 201{ 202 203 const int delayTime = 10; 204 const uint8_t start_ind_adress = 0; 205 const uint8_t finish_ind_adress = 127; 206 uint8_t add_byte; 207 uint8_t device_short_add; 208 uint8_t response; 209 210 dali.transmit(BROADCAST_C, OFF_C); // Broadcast Off 211 delay(delayTime); 212 213 if (dali.msgMode) { 214 Serial.println("Short addresses:"); 215 } 216 217 for (device_short_add = start_ind_adress; device_short_add <= 63; device_short_add++) { 218 219 add_byte = 1 + (device_short_add << 1); // convert short address to address byte 220 221 222 dali.transmit(add_byte, 0xA1); 223 224 response = dali.receive(); 225 226 if (dali.getResponse) { 227 228 dali.transmit(add_byte, ON_C); // switch on 229 delay(1000); 230 dali.transmit(add_byte, OFF_C); // switch off 231 delay(1000); 232 233 } 234 else { 235 response = 0; 236 } 237 238 239 240 if (dali.msgMode) { 241 Serial.print("BIN: "); 242 Serial.print(device_short_add, BIN); 243 Serial.print(" "); 244 Serial.print("DEC: "); 245 Serial.print(device_short_add, DEC); 246 Serial.print(" "); 247 Serial.print("HEX: "); 248 Serial.print(device_short_add, HEX); 249 Serial.print(" "); 250 if (dali.getResponse) { 251 Serial.print("Get response"); 252 } 253 else { 254 Serial.print("No response"); 255 } 256 Serial.println(); 257 } 258 else { 259 if (dali.getResponse) { 260 Serial.println(255, BIN); 261 } 262 else { 263 Serial.println(0, BIN); 264 } 265 266 } 267 268 } 269 270 dali.transmit(BROADCAST_C, ON_C); // Broadcast On 271 Serial.println(); 272 delay(delayTime); 273 274} 275 276 277int Dali::readBinaryString(char *s) 278{ 279 int result = 0; 280 while (*s) { 281 result <<= 1; 282 if (*s++ == '1') result |= 1; 283 } 284 return result; 285} 286 287 288bool Dali::cmdCheck(String & input, int & cmd1, int & cmd2) 289{ 290 bool test = true; 291 292 input.replace(" ", ""); // Delete spaces 293 294 if (input.length() != 16) { 295 test = false; //check if command contain 16bit 296 } 297 else { 298 for (int i = 0; i <= input.length() - 1; i++) { 299 if ((int)input.charAt(i) == 49 or (int)input.charAt(i) == 48) {} 300 else { 301 test = false; 302 }; 303 }; 304 }; 305 306 if (test) { 307 cmd1 = readBinaryString(input.substring(0, 8).c_str()); 308 cmd2 = readBinaryString(input.substring(8, 16).c_str()); 309 } 310 311 return test; 312} 313 314void Dali::initialisation() { 315 316 const int delaytime = 10; //ms 317 318 long low_longadd = 0x000000; 319 long high_longadd = 0xFFFFFF; 320 long longadd = (long)(low_longadd + high_longadd) / 2; 321 uint8_t highbyte; 322 uint8_t middlebyte; 323 uint8_t lowbyte; 324 uint8_t short_add = 0; 325 uint8_t cmd2; 326 327 delay(delaytime); 328 dali.transmit(BROADCAST_C, RESET); 329 delay(delaytime); 330 dali.transmit(BROADCAST_C, RESET); 331 delay(delaytime); 332 dali.transmit(BROADCAST_C, OFF_C); 333 delay(delaytime); 334 dali.transmit(0b10100101, 0b00000000); //initialise 335 delay(delaytime); 336 dali.transmit(0b10100101, 0b00000000); //initialise 337 delay(delaytime); 338 dali.transmit(0b10100111, 0b00000000); //randomise 339 delay(delaytime); 340 dali.transmit(0b10100111, 0b00000000); //randomise 341 342 if (dali.msgMode) { 343 Serial.println("Searching fo long addresses:"); 344 } 345 346 while (longadd <= 0xFFFFFF - 2 and short_add <= 64) { 347 while ((high_longadd - low_longadd) > 1) { 348 349 dali.splitAdd(longadd, highbyte, middlebyte, lowbyte); //divide 24bit adress into three 8bit adresses 350 delay(delaytime); 351 dali.transmit(0b10110001, highbyte); //search HB 352 delay(delaytime); 353 dali.transmit(0b10110011, middlebyte); //search MB 354 delay(delaytime); 355 dali.transmit(0b10110101, lowbyte); //search LB 356 delay(delaytime); 357 dali.transmit(0b10101001, 0b00000000); //compare 358 359 if (minResponseLevel() > dali.analogLevel) 360 { 361 low_longadd = longadd; 362 } 363 else 364 { 365 high_longadd = longadd; 366 } 367 368 longadd = (low_longadd + high_longadd) / 2; //center 369 370 if (dali.msgMode) { 371 Serial.print("BIN: "); 372 Serial.print(longadd + 1, BIN); 373 Serial.print(" "); 374 Serial.print("DEC: "); 375 Serial.print(longadd + 1, DEC); 376 Serial.print(" "); 377 Serial.print("HEX: "); 378 Serial.print(longadd + 1, HEX); 379 Serial.println(); 380 } 381 else { 382 Serial.println(longadd + 1); 383 } 384 } // second while 385 386 387 if (high_longadd != 0xFFFFFF) 388 { 389 splitAdd(longadd + 1, highbyte, middlebyte, lowbyte); 390 dali.transmit(0b10110001, highbyte); //search HB 391 delay(delaytime); 392 dali.transmit(0b10110011, middlebyte); //search MB 393 delay(delaytime); 394 dali.transmit(0b10110101, lowbyte); //search LB 395 delay(delaytime); 396 dali.transmit(0b10110111, 1 + (short_add << 1)); //program short adress 397 delay(delaytime); 398 dali.transmit(0b10101011, 0b00000000); //withdraw 399 delay(delaytime); 400 dali.transmit(1 + (short_add << 1), ON_C); 401 delay(1000); 402 dali.transmit(1 + (short_add << 1), OFF_C); 403 delay(delaytime); 404 short_add++; 405 406 if (dali.msgMode) { 407 Serial.println("Assigning a short address"); 408 } 409 410 high_longadd = 0xFFFFFF; 411 longadd = (low_longadd + high_longadd) / 2; 412 413 } 414 else { 415 if (dali.msgMode) { 416 Serial.println("End"); 417 } 418 } 419 } // first while 420 421 422 dali.transmit(0b10100001, 0b00000000); //terminate 423 dali.transmit(BROADCAST_C, ON_C); //broadcast on 424} 425 426 427uint8_t Dali::receive() { 428 429 430 431 unsigned long startFuncTime = 0; 432 bool previousLogicLevel = 1; 433 bool currentLogicLevel = 1; 434 uint8_t arrLength = 20; 435 int timeArray[arrLength]; 436 int i = 0; 437 int k = 0; 438 bool logicLevelArray[arrLength]; 439 int response = 0; 440 441 dali.getResponse = false; 442 startFuncTime = micros(); 443 444 // add check for micros overlap here!!! 445 446 while (micros() - startFuncTime < dali.daliTimeout and i < arrLength) 447 { 448 // geting response 449 if (analogRead(dali.RxAnalogPin) > dali.analogLevel) { 450 currentLogicLevel = 1; 451 } 452 else { 453 currentLogicLevel = 0; 454 } 455 456 if (previousLogicLevel != currentLogicLevel) { 457 timeArray[i] = micros() - startFuncTime; 458 logicLevelArray[i] = currentLogicLevel; 459 previousLogicLevel = currentLogicLevel; 460 dali.getResponse = true; 461 i++; 462 463 } 464 } 465 466 467 468 arrLength = i; 469 470 //decoding to manchester 471 for (i = 0; i < arrLength - 1; i++) { 472 if ((timeArray[i + 1] - timeArray[i]) > 0.75 * dali.period) { 473 for (k = arrLength; k > i; k--) { 474 timeArray[k] = timeArray[k - 1]; 475 logicLevelArray[k] = logicLevelArray[k - 1]; 476 } 477 arrLength++; 478 timeArray[i + 1] = (timeArray[i] + timeArray[i + 2]) / 2; 479 logicLevelArray[i + 1] = logicLevelArray[i]; 480 } 481 } 482 483 484 485 486 487 k = 8; 488 489 for (i = 1; i < arrLength; i++) { 490 if (logicLevelArray[i] == 1) { 491 if ((int)round((timeArray[i] - timeArray[0]) / (0.5 * dali.period)) & 1) { 492 response = response + (1 << k); 493 } 494 k--; 495 } 496 } 497 498 499 //remove start bit 500 response = (uint8_t)response; 501 502 return response; 503 504} 505 506 507 508 509 Dali dali; 510
Dali.h
arduino
1#ifndef dali_h 2#define dali_h 3#include <SoftwareSerial.h> 4 5//timer scaling factors for different transmission speeds 6#define MAN_300 0 7#define MAN_600 1 8#define MAN_1200 2 9#define MAN_2400 3 10#define MAN_4800 4 11#define MAN_9600 5 12#define MAN_19200 6 13#define MAN_38400 7 14 15/* 16Timer 2 in the ATMega328 and Timer 1 in a ATtiny85 is used to find the time between 17each transition coming from the demodulation circuit. 18Their setup is for sampling the input in regular intervals. 19For practical reasons we use power of 2 timer prescaller for sampling, 20for best timing we use pulse lenght as integer multiple of sampling speed. 21We chose to sample every 8 ticks, and pulse lenght of 48 ticks 22thats 6 samples per pulse, lower sampling rate (3) will not work well for 23innacurate clocks (like internal oscilator) higher sampling rate (12) will 24cause too much overhead and will not work at higher transmission speeds. 25This gives us 16000000Hz/48/256 = 1302 pulses per second (so it's not really 1200) 26At different transmission speeds or on different microcontroller frequencies, clock prescaller is adjusted 27to be compatible with those values. We allow about 50% clock speed difference both ways 28allowing us to transmit even with up to 100% in clock speed difference 29*/ 30 31// DALI coomands 32#define BROADCAST_DP 0b11111110 33#define BROADCAST_C 0b11111111 34#define ON_DP 0b11111110 35#define OFF_DP 0b00000000 36#define ON_C 0b00000101 37#define OFF_C 0b00000000 38# define QUERY_STATUS 0b10010000 39# define RESET 0b00100000 40 41 42//setup timing for transmitter 43#define HALF_BIT_INTERVAL 1666 44 45 46 47 48 49#if defined(ARDUINO) && ARDUINO >= 100 50 #include "Arduino.h" 51#else 52 #include "WProgram.h" 53 #include <pins_arduino.h> 54#endif 55 56class Dali 57{ 58 public: 59 Dali(); //the constructor 60 void setTxPin(uint8_t pin); //set the arduino digital pin for transmit. 61 void setRxAnalogPin(uint8_t pin); //set the arduino digital pin for receive. 62 void workAround1MhzTinyCore(uint8_t a = 1); //apply workaround for defect in tiny Core library for 1Mhz 63 void setupTransmit(uint8_t pin); //set up transmission 64 void setupAnalogReceive(uint8_t pin); 65 void transmit(uint8_t cmd1, uint8_t cmd2); //transmit 16 bits of data 66 void scanShortAdd(); //scan for short address 67 void busTest(); // bus test 68 void initialisation(); //initialization of new luminaries 69 bool cmdCheck(String & input, int & cmd1, int & cmd2); 70 uint8_t receive(); //get response 71 72 int minResponseLevel(); 73 int maxResponseLevel(); 74 75 uint8_t speedFactor; 76 uint16_t delay1; 77 uint16_t delay2; 78 uint16_t period; 79 String errorMsg; //error message of last operation 80 bool msgMode; //0 - get only response from dali bus to COM; 1 - response with text (comments) 81 bool getResponse; 82 uint8_t RxAnalogPin; 83 84 long daliTimeout = 20000; //us, DALI response timeout 85 int analogLevel = 870; //analog border level (less - "0"; more - "1") 86 87 88 89 90 private: 91 92 void sendByte(uint8_t b); //transmit 8 bits of data 93 void sendBit(int b); //transmit 1 bit of data 94 void sendZero(void); //transmit "0" 95 void sendOne(void); //transmit "1" 96 void splitAdd(long input, uint8_t &highbyte, uint8_t &middlebyte, uint8_t &lowbyte); //split random address 97 98 99 int readBinaryString(char *s); 100 101 uint8_t TxPin; 102 103 uint8_t applyWorkAround1Mhz; 104 uint8_t rxAnalogPin = 0; 105 106};//end of class Dali 107 108// Cant really do this as a real C++ class, since we need to have 109// an ISR 110extern "C" 111{ 112 113 114 } 115 116extern Dali dali; 117 118#endif 119
keywords.txt
arduino
1 dali KEYWORD1 setTxPin KEYWORD2 setRxAnalogPin KEYWORD2 workAround1MhzTinyCore KEYWORD2 setupTransmit KEYWORD2 setupAnalogReceive KEYWORD2 transmit KEYWORD2 scanShortAdd KEYWORD2 busTest KEYWORD2 initialisation KEYWORD2 cmdCheck KEYWORD2 minResponseLevel KEYWORD2 maxResponseLevel KEYWORD2
keywords.txt
arduino
1 dali KEYWORD1 setTxPin KEYWORD2 setRxAnalogPin KEYWORD2 workAround1MhzTinyCore KEYWORD2 setupTransmit KEYWORD2 setupAnalogReceive KEYWORD2 transmit KEYWORD2 scanShortAdd KEYWORD2 busTest KEYWORD2 initialisation KEYWORD2 cmdCheck KEYWORD2 minResponseLevel KEYWORD2 maxResponseLevel KEYWORD2
Dali.h
arduino
1#ifndef dali_h 2#define dali_h 3#include <SoftwareSerial.h> 4 5//timer scaling factors for different transmission speeds 6#define MAN_300 0 7#define MAN_600 1 8#define MAN_1200 2 9#define MAN_2400 3 10#define MAN_4800 4 11#define MAN_9600 5 12#define MAN_19200 6 13#define MAN_38400 7 14 15/* 16Timer 2 in the ATMega328 and Timer 1 in a ATtiny85 is used to find the time between 17each transition coming from the demodulation circuit. 18Their setup is for sampling the input in regular intervals. 19For practical reasons we use power of 2 timer prescaller for sampling, 20for best timing we use pulse lenght as integer multiple of sampling speed. 21We chose to sample every 8 ticks, and pulse lenght of 48 ticks 22thats 6 samples per pulse, lower sampling rate (3) will not work well for 23innacurate clocks (like internal oscilator) higher sampling rate (12) will 24cause too much overhead and will not work at higher transmission speeds. 25This gives us 16000000Hz/48/256 = 1302 pulses per second (so it's not really 1200) 26At different transmission speeds or on different microcontroller frequencies, clock prescaller is adjusted 27to be compatible with those values. We allow about 50% clock speed difference both ways 28allowing us to transmit even with up to 100% in clock speed difference 29*/ 30 31// DALI coomands 32#define BROADCAST_DP 0b11111110 33#define BROADCAST_C 0b11111111 34#define ON_DP 0b11111110 35#define OFF_DP 0b00000000 36#define ON_C 0b00000101 37#define OFF_C 0b00000000 38# define QUERY_STATUS 0b10010000 39# define RESET 0b00100000 40 41 42//setup timing for transmitter 43#define HALF_BIT_INTERVAL 1666 44 45 46 47 48 49#if defined(ARDUINO) && ARDUINO >= 100 50 #include "Arduino.h" 51#else 52 #include "WProgram.h" 53 #include <pins_arduino.h> 54#endif 55 56class Dali 57{ 58 public: 59 Dali(); //the constructor 60 void setTxPin(uint8_t pin); //set the arduino digital pin for transmit. 61 void setRxAnalogPin(uint8_t pin); //set the arduino digital pin for receive. 62 void workAround1MhzTinyCore(uint8_t a = 1); //apply workaround for defect in tiny Core library for 1Mhz 63 void setupTransmit(uint8_t pin); //set up transmission 64 void setupAnalogReceive(uint8_t pin); 65 void transmit(uint8_t cmd1, uint8_t cmd2); //transmit 16 bits of data 66 void scanShortAdd(); //scan for short address 67 void busTest(); // bus test 68 void initialisation(); //initialization of new luminaries 69 bool cmdCheck(String & input, int & cmd1, int & cmd2); 70 uint8_t receive(); //get response 71 72 int minResponseLevel(); 73 int maxResponseLevel(); 74 75 uint8_t speedFactor; 76 uint16_t delay1; 77 uint16_t delay2; 78 uint16_t period; 79 String errorMsg; //error message of last operation 80 bool msgMode; //0 - get only response from dali bus to COM; 1 - response with text (comments) 81 bool getResponse; 82 uint8_t RxAnalogPin; 83 84 long daliTimeout = 20000; //us, DALI response timeout 85 int analogLevel = 870; //analog border level (less - "0"; more - "1") 86 87 88 89 90 private: 91 92 void sendByte(uint8_t b); //transmit 8 bits of data 93 void sendBit(int b); //transmit 1 bit of data 94 void sendZero(void); //transmit "0" 95 void sendOne(void); //transmit "1" 96 void splitAdd(long input, uint8_t &highbyte, uint8_t &middlebyte, uint8_t &lowbyte); //split random address 97 98 99 int readBinaryString(char *s); 100 101 uint8_t TxPin; 102 103 uint8_t applyWorkAround1Mhz; 104 uint8_t rxAnalogPin = 0; 105 106};//end of class Dali 107 108// Cant really do this as a real C++ class, since we need to have 109// an ISR 110extern "C" 111{ 112 113 114 } 115 116extern Dali dali; 117 118#endif 119
Dali.cpp
arduino
1#include "Dali.h" 2#include <SoftwareSerial.h> 3 4 5 6Dali::Dali() //constructor 7{ 8 applyWorkAround1Mhz = 0; 9} 10 11 12void Dali::setTxPin(uint8_t pin) 13{ 14 TxPin = pin; // user sets the digital pin as output 15 pinMode(TxPin, OUTPUT); 16 digitalWrite(TxPin, HIGH); 17} 18 19void Dali::setRxAnalogPin(uint8_t pin) 20{ 21 RxAnalogPin = pin; // user sets the digital pin as output 22} 23 24void Dali::workAround1MhzTinyCore(uint8_t a) 25{ 26 applyWorkAround1Mhz = a; 27} 28 29void Dali::setupAnalogReceive(uint8_t pin) 30{ 31 setRxAnalogPin(pin); // user sets the analog pin as input 32} 33 34 35void Dali::setupTransmit(uint8_t pin) 36{ 37 setTxPin(pin); 38 speedFactor = 2; 39 //we don't use exact calculation of passed time spent outside of transmitter 40 //because of high ovehead associated with it, instead we use this 41 //emprirically determined values to compensate for the time loss 42 43 #if F_CPU == 1000000UL 44 uint16_t compensationFactor = 88; //must be divisible by 8 for workaround 45 #elif F_CPU == 8000000UL 46 uint16_t compensationFactor = 12; 47 #else //16000000Mhz 48 uint16_t compensationFactor = 4; 49 #endif 50 51#if (F_CPU == 80000000UL) || (F_CPU == 160000000) // ESP8266 80MHz or 160 MHz 52 delay1 = delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2; 53#else 54 delay1 = (HALF_BIT_INTERVAL >> speedFactor) - compensationFactor; 55 delay2 = (HALF_BIT_INTERVAL >> speedFactor) - 2; 56 period = delay1 + delay2; 57 58 #if F_CPU == 1000000UL 59 delay2 -= 22; //22+2 = 24 is divisible by 8 60 if (applyWorkAround1Mhz) { //definition of micro delay is broken for 1MHz speed in tiny cores as of now (May 2013) 61 //this is a workaround that will allow us to transmit on 1Mhz 62 //divide the wait time by 8 63 delay1 >>= 3; 64 delay2 >>= 3; 65 } 66 #endif 67#endif 68 69 } 70 71 72void Dali::transmit(uint8_t cmd1, uint8_t cmd2) // transmit commands to DALI bus (address byte, command byte) 73{ 74 sendBit(1); 75 sendByte(cmd1); 76 sendByte(cmd2); 77 digitalWrite(TxPin, HIGH); 78} 79 80 81void Dali::sendByte(uint8_t b) 82{ 83 for (int i = 7; i >= 0; i--) 84 { 85 sendBit((b >> i) & 1); 86 } 87} 88 89 90void Dali::sendBit(int b) 91{ 92 if (b) { 93 sendOne(); 94 } 95 else { 96 sendZero(); 97 } 98} 99 100 101void Dali::sendZero(void) 102{ 103 digitalWrite(TxPin, HIGH); 104 delayMicroseconds(delay2); 105 digitalWrite(TxPin, LOW); 106 delayMicroseconds(delay1); 107 108} 109 110 111void Dali::sendOne(void) 112{ 113 digitalWrite(TxPin, LOW); 114 delayMicroseconds(delay2); 115 digitalWrite(TxPin, HIGH); 116 delayMicroseconds(delay1); 117} 118 119 120void Dali::busTest() //DALI bus test 121{ 122 int maxLevel; 123 int minLevel; 124 125 //Luminaries must turn on and turn off. If not, check connection. 126 delay(100); 127 dali.transmit(BROADCAST_C, OFF_C); //Broadcast ON 128 delay(500); 129 dali.transmit(BROADCAST_C, ON_C); //Broadcast OFF 130 delay(100); 131 while (!Serial); 132 133 //Receive response from luminaries: max and min level 134 dali.transmit(BROADCAST_C, QUERY_STATUS); 135 maxLevel = dali.maxResponseLevel(); 136 dali.transmit(BROADCAST_C, QUERY_STATUS); 137 minLevel = dali.minResponseLevel(); 138 139 dali.analogLevel = (int)(maxLevel + minLevel) / 2; 140 141 142 143 144 145} 146 147 148void Dali::splitAdd(long input, uint8_t &highbyte, uint8_t &middlebyte, uint8_t &lowbyte) 149{ 150 highbyte = input >> 16; 151 middlebyte = input >> 8; 152 lowbyte = input; 153} 154 155 156 157// define min response level 158int Dali::minResponseLevel() 159{ 160 161 const uint8_t dalistep = 40; //us 162 uint16_t rxmin = 1024; 163 uint16_t dalidata; 164 long idalistep; 165 166 167 168 for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) { 169 dalidata = analogRead(RxAnalogPin); 170 if (dalidata < rxmin) { 171 rxmin = dalidata; 172 }; 173 delayMicroseconds(dalistep); 174 } 175 return rxmin; 176} 177 178// define max response level 179int Dali::maxResponseLevel() 180{ 181 182 const uint8_t dalistep = 40; //us 183 uint16_t rxmax = 0; 184 uint16_t dalidata; 185 long idalistep; 186 187 188 for (idalistep = 0; idalistep < dali.daliTimeout; idalistep = idalistep + dalistep) { 189 dalidata = analogRead(dali.RxAnalogPin); 190 if (dalidata > rxmax) { 191 rxmax = dalidata; 192 }; 193 delayMicroseconds(dalistep); 194 } 195 return rxmax; 196} 197 198 199//scan for individual short address 200void Dali::scanShortAdd() 201{ 202 203 const int delayTime = 10; 204 const uint8_t start_ind_adress = 0; 205 const uint8_t finish_ind_adress = 127; 206 uint8_t add_byte; 207 uint8_t device_short_add; 208 uint8_t response; 209 210 dali.transmit(BROADCAST_C, OFF_C); // Broadcast Off 211 delay(delayTime); 212 213 if (dali.msgMode) { 214 Serial.println("Short addresses:"); 215 } 216 217 for (device_short_add = start_ind_adress; device_short_add <= 63; device_short_add++) { 218 219 add_byte = 1 + (device_short_add << 1); // convert short address to address byte 220 221 222 dali.transmit(add_byte, 0xA1); 223 224 response = dali.receive(); 225 226 if (dali.getResponse) { 227 228 dali.transmit(add_byte, ON_C); // switch on 229 delay(1000); 230 dali.transmit(add_byte, OFF_C); // switch off 231 delay(1000); 232 233 } 234 else { 235 response = 0; 236 } 237 238 239 240 if (dali.msgMode) { 241 Serial.print("BIN: "); 242 Serial.print(device_short_add, BIN); 243 Serial.print(" "); 244 Serial.print("DEC: "); 245 Serial.print(device_short_add, DEC); 246 Serial.print(" "); 247 Serial.print("HEX: "); 248 Serial.print(device_short_add, HEX); 249 Serial.print(" "); 250 if (dali.getResponse) { 251 Serial.print("Get response"); 252 } 253 else { 254 Serial.print("No response"); 255 } 256 Serial.println(); 257 } 258 else { 259 if (dali.getResponse) { 260 Serial.println(255, BIN); 261 } 262 else { 263 Serial.println(0, BIN); 264 } 265 266 } 267 268 } 269 270 dali.transmit(BROADCAST_C, ON_C); // Broadcast On 271 Serial.println(); 272 delay(delayTime); 273 274} 275 276 277int Dali::readBinaryString(char *s) 278{ 279 int result = 0; 280 while (*s) { 281 result <<= 1; 282 if (*s++ == '1') result |= 1; 283 } 284 return result; 285} 286 287 288bool Dali::cmdCheck(String & input, int & cmd1, int & cmd2) 289{ 290 bool test = true; 291 292 input.replace(" ", ""); // Delete spaces 293 294 if (input.length() != 16) { 295 test = false; //check if command contain 16bit 296 } 297 else { 298 for (int i = 0; i <= input.length() - 1; i++) { 299 if ((int)input.charAt(i) == 49 or (int)input.charAt(i) == 48) {} 300 else { 301 test = false; 302 }; 303 }; 304 }; 305 306 if (test) { 307 cmd1 = readBinaryString(input.substring(0, 8).c_str()); 308 cmd2 = readBinaryString(input.substring(8, 16).c_str()); 309 } 310 311 return test; 312} 313 314void Dali::initialisation() { 315 316 const int delaytime = 10; //ms 317 318 long low_longadd = 0x000000; 319 long high_longadd = 0xFFFFFF; 320 long longadd = (long)(low_longadd + high_longadd) / 2; 321 uint8_t highbyte; 322 uint8_t middlebyte; 323 uint8_t lowbyte; 324 uint8_t short_add = 0; 325 uint8_t cmd2; 326 327 delay(delaytime); 328 dali.transmit(BROADCAST_C, RESET); 329 delay(delaytime); 330 dali.transmit(BROADCAST_C, RESET); 331 delay(delaytime); 332 dali.transmit(BROADCAST_C, OFF_C); 333 delay(delaytime); 334 dali.transmit(0b10100101, 0b00000000); //initialise 335 delay(delaytime); 336 dali.transmit(0b10100101, 0b00000000); //initialise 337 delay(delaytime); 338 dali.transmit(0b10100111, 0b00000000); //randomise 339 delay(delaytime); 340 dali.transmit(0b10100111, 0b00000000); //randomise 341 342 if (dali.msgMode) { 343 Serial.println("Searching fo long addresses:"); 344 } 345 346 while (longadd <= 0xFFFFFF - 2 and short_add <= 64) { 347 while ((high_longadd - low_longadd) > 1) { 348 349 dali.splitAdd(longadd, highbyte, middlebyte, lowbyte); //divide 24bit adress into three 8bit adresses 350 delay(delaytime); 351 dali.transmit(0b10110001, highbyte); //search HB 352 delay(delaytime); 353 dali.transmit(0b10110011, middlebyte); //search MB 354 delay(delaytime); 355 dali.transmit(0b10110101, lowbyte); //search LB 356 delay(delaytime); 357 dali.transmit(0b10101001, 0b00000000); //compare 358 359 if (minResponseLevel() > dali.analogLevel) 360 { 361 low_longadd = longadd; 362 } 363 else 364 { 365 high_longadd = longadd; 366 } 367 368 longadd = (low_longadd + high_longadd) / 2; //center 369 370 if (dali.msgMode) { 371 Serial.print("BIN: "); 372 Serial.print(longadd + 1, BIN); 373 Serial.print(" "); 374 Serial.print("DEC: "); 375 Serial.print(longadd + 1, DEC); 376 Serial.print(" "); 377 Serial.print("HEX: "); 378 Serial.print(longadd + 1, HEX); 379 Serial.println(); 380 } 381 else { 382 Serial.println(longadd + 1); 383 } 384 } // second while 385 386 387 if (high_longadd != 0xFFFFFF) 388 { 389 splitAdd(longadd + 1, highbyte, middlebyte, lowbyte); 390 dali.transmit(0b10110001, highbyte); //search HB 391 delay(delaytime); 392 dali.transmit(0b10110011, middlebyte); //search MB 393 delay(delaytime); 394 dali.transmit(0b10110101, lowbyte); //search LB 395 delay(delaytime); 396 dali.transmit(0b10110111, 1 + (short_add << 1)); //program short adress 397 delay(delaytime); 398 dali.transmit(0b10101011, 0b00000000); //withdraw 399 delay(delaytime); 400 dali.transmit(1 + (short_add << 1), ON_C); 401 delay(1000); 402 dali.transmit(1 + (short_add << 1), OFF_C); 403 delay(delaytime); 404 short_add++; 405 406 if (dali.msgMode) { 407 Serial.println("Assigning a short address"); 408 } 409 410 high_longadd = 0xFFFFFF; 411 longadd = (low_longadd + high_longadd) / 2; 412 413 } 414 else { 415 if (dali.msgMode) { 416 Serial.println("End"); 417 } 418 } 419 } // first while 420 421 422 dali.transmit(0b10100001, 0b00000000); //terminate 423 dali.transmit(BROADCAST_C, ON_C); //broadcast on 424} 425 426 427uint8_t Dali::receive() { 428 429 430 431 unsigned long startFuncTime = 0; 432 bool previousLogicLevel = 1; 433 bool currentLogicLevel = 1; 434 uint8_t arrLength = 20; 435 int timeArray[arrLength]; 436 int i = 0; 437 int k = 0; 438 bool logicLevelArray[arrLength]; 439 int response = 0; 440 441 dali.getResponse = false; 442 startFuncTime = micros(); 443 444 // add check for micros overlap here!!! 445 446 while (micros() - startFuncTime < dali.daliTimeout and i < arrLength) 447 { 448 // geting response 449 if (analogRead(dali.RxAnalogPin) > dali.analogLevel) { 450 currentLogicLevel = 1; 451 } 452 else { 453 currentLogicLevel = 0; 454 } 455 456 if (previousLogicLevel != currentLogicLevel) { 457 timeArray[i] = micros() - startFuncTime; 458 logicLevelArray[i] = currentLogicLevel; 459 previousLogicLevel = currentLogicLevel; 460 dali.getResponse = true; 461 i++; 462 463 } 464 } 465 466 467 468 arrLength = i; 469 470 //decoding to manchester 471 for (i = 0; i < arrLength - 1; i++) { 472 if ((timeArray[i + 1] - timeArray[i]) > 0.75 * dali.period) { 473 for (k = arrLength; k > i; k--) { 474 timeArray[k] = timeArray[k - 1]; 475 logicLevelArray[k] = logicLevelArray[k - 1]; 476 } 477 arrLength++; 478 timeArray[i + 1] = (timeArray[i] + timeArray[i + 2]) / 2; 479 logicLevelArray[i + 1] = logicLevelArray[i]; 480 } 481 } 482 483 484 485 486 487 k = 8; 488 489 for (i = 1; i < arrLength; i++) { 490 if (logicLevelArray[i] == 1) { 491 if ((int)round((timeArray[i] - timeArray[0]) / (0.5 * dali.period)) & 1) { 492 response = response + (1 << k); 493 } 494 k--; 495 } 496 } 497 498 499 //remove start bit 500 response = (uint8_t)response; 501 502 return response; 503 504} 505 506 507 508 509 Dali dali; 510
DALI.zip
arduino
1inary file (no preview
DALI.ino
arduino
1#include <Dali.h> 2 3 4const int DALI_TX = 3; 5const int DALI_RX_A = 0; 6 7 8 9#define BROADCAST_DP 0b11111110 10#define BROADCAST_C 0b11111111 11#define ON_DP 0b11111110 12#define OFF_DP 0b00000000 13#define ON_C 0b00000101 14#define OFF_C 0b00000000 15# define QUERY_STATUS 0b10010000 16# define RESET 0b00100000 17 18void setup() { 19 20 Serial.begin(74880); 21 dali.setupTransmit(DALI_TX); 22 dali.setupAnalogReceive(DALI_RX_A); 23 dali.busTest(); 24 dali.msgMode = true; 25 Serial.println(dali.analogLevel); 26 help(); //Show help 27 28} 29 30 31void help() { 32 Serial.println("Enter 16 bit command or another command from list:"); 33 Serial.println("help - command list"); 34 Serial.println("on - broadcast on 100%"); 35 Serial.println("off - broadcast off 0%"); 36 Serial.println("scan - device short address scan"); 37 Serial.println("initialise - start process of initialisation"); 38 Serial.println(); 39} 40 41 42void sinus () { 43 uint8_t lf_1_add = 0; 44 uint8_t lf_2_add = 1; 45 uint8_t lf_3_add = 2; 46 uint8_t lf_1; 47 uint8_t lf_2; 48 uint8_t lf_3; 49 int i; 50 int j = 0; 51 52 while (Serial.available() == 0) { 53 for (i = 0; i < 360; i = i + 1) { 54 55 if (Serial.available() != 0) { 56 dali.transmit(BROADCAST_C, ON_C); 57 break; 58 } 59 60 lf_1 = (int) abs(254 * sin(i * 3.14 / 180)); 61 lf_2 = (int) abs(254 * sin(i * 3.14 / 180 + 2 * 3.14 / 3)); 62 lf_3 = (int) abs(254 * sin(i * 3.14 / 180 + 1 * 3.14 / 3)); 63 dali.transmit(lf_1_add << 1, lf_1); 64 delay(5); 65 dali.transmit(lf_2_add << 1, lf_2); 66 delay(5); 67 dali.transmit(lf_3_add << 1, lf_3); 68 delay(5); 69 delay(20); 70 } 71 } 72} 73 74 75void loop() { 76 77 const int delaytime = 500; 78 int i; 79 int cmd1; 80 int cmd2; 81 String comMsg; 82 83 84 // Read command from port 85 86 delay(delaytime); 87 88 while (Serial.available()) { 89 comMsg = comMsg + (char)(Serial.read()); 90 }; // read data from serial 91 92 if (comMsg == "sinus") { 93 sinus(); 94 }; 95 96 if (comMsg == "scan") { 97 dali.scanShortAdd(); 98 }; // scan short addresses 99 100 if (comMsg == "on") { 101 dali.transmit(BROADCAST_C, ON_C); 102 }; // broadcast, 100% 103 104 if (comMsg == "off") { 105 dali.transmit(BROADCAST_C, OFF_C); 106 }; // broadcast, 0% 107 108 if (comMsg == "initialise" or comMsg == "ini") { 109 dali.initialisation(); 110 }; // initialisation 111 112 if (comMsg == "help") { 113 help(); 114 }; //help 115 116 117 if (dali.cmdCheck(comMsg, cmd1, cmd2)) { 118 dali.transmit(cmd1, cmd2); // command in binary format: (address byte, command byte) 119 } 120 delay(delaytime); 121 122}; 123 124 125 126 127 128 129 130 131 132 133 134 135
Downloadable files
Curcuit diagram
Curcuit diagram
DALI command list
DALI command list
DALI command list
DALI command list
Curcuit diagram
Curcuit diagram
Comments
Only logged in users can leave comments