Interface DALI and Arduino. Real surrealism

    Hello. Our department was tasked to present the DALI digital interface. And a presentation with a demonstration of the work of this interface. If necessary, then it is necessary. What we just did. For this purpose, two LED lighting control modules were provided. Both were led. And the master? Began to choose a controller to control this interface. In the end, or the price of some transcendental or delivery times are the same. A vacation is coming, and I don’t want to postpone it. Once again, we looked at the characteristics and paid attention to the features of this digital protocol:

    • DALI is an open protocol;
    • DALI is a decentralized bus, that is, it does not have a central controller and allows any topology.

    All this seemed very attractive and the task seemed completely uncomplicated. At first sight. We decided to make the master DALI on Arduino.

    Many thanks to Timur Nabiyev for his publication on Habré . Please read. I will not repeat, the theory he prescribed well. The interface circuit - is never easier. But with the library published by him, something was not very good for us.

    Therefore, we decided to make our own sketches. Made two. The first is to assign short addresses to all “members” of the network.
    Look
    #define DALI_TX_PIN   3#define DALI_RX_PIN   A0#define LED_PIN       13#define RESET               0b00100000#define INITIALISE          0xA5#define RANDOMISE           0xA7#define SEARCHADDRH         0xB1#define SEARCHADDRM         0xB3#define SEARCHADDRL         0xB5#define PRG_SHORT_ADDR      0xB7#define COMPARE             0xA9#define WITHDRAW            0xAB#define TERMINATE           0xA1#define START_SHORT_ADDR    2#define DALI_ANALOG_LEVEL   650#define DALI_HALF_BIT_TIME         416 //microseconds#define DALI_TWO_PACKET_DELAY      10 //miliseconds#define DALI_RESPONSE_DELAY_COUNT  15 //максимальное число полубитов//до ответаuint8_t ShortAddr = START_SHORT_ADDR;
    voidsetup(){
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, LOW);
      pinMode(DALI_TX_PIN, OUTPUT);
      digitalWrite(DALI_TX_PIN, HIGH);
        Serial.begin(115200);
      DaliInit();
    }
    //-----------------------------------------------------voidloop(){
    }
    //-----------------------------------------------------voidDaliInit(){
      Serial.println("Initialization...");
      DaliTransmitCMD(RESET, 0x00);
      delay(2*DALI_TWO_PACKET_DELAY);
      DaliTransmitCMD(RESET, 0x00);
      delay(2*DALI_TWO_PACKET_DELAY);
      delay(100);
      DaliTransmitCMD(INITIALISE, 0x00); 
      delay(DALI_TWO_PACKET_DELAY);
      DaliTransmitCMD(INITIALISE, 0x00);
      delay(DALI_TWO_PACKET_DELAY);
      DaliTransmitCMD(INITIALISE, 0x00);
      delay(DALI_TWO_PACKET_DELAY);
      delay(100);
      DaliTransmitCMD(RANDOMISE, 0x00);
      delay(DALI_TWO_PACKET_DELAY);
      DaliTransmitCMD(RANDOMISE, 0x00);
      delay(DALI_TWO_PACKET_DELAY);
      delay(100);
      while(ShortAddr < 64)
      {
        long SearchAddr = 0xFFFFFF;
        bool Response = 0;
        long LowLimit = 0;
        long HighLimit = 0x1000000;
        Response = SearchAndCompare(SearchAddr);
        delay(DALI_TWO_PACKET_DELAY);
        if(Response)
        {
          digitalWrite(LED_PIN, LOW);
          Serial.println("Device detected, address searching...");
          if(!SearchAndCompare(SearchAddr - 1))
          {
            delay(DALI_TWO_PACKET_DELAY);
            SearchAndCompare(SearchAddr);
            delay(DALI_TWO_PACKET_DELAY);
            DaliTransmitCMD(PRG_SHORT_ADDR, ((ShortAddr << 1) | 1));
            delay(3*DALI_TWO_PACKET_DELAY);
            DaliTransmitCMD(WITHDRAW, 0x00);
            Serial.print("24-bit address found: 0x");
            Serial.println(SearchAddr, HEX);
            Serial.print("Assigning short address ");
            Serial.println(ShortAddr);
            break;
          }
        }
        else
        {
          Serial.println("No devices detected");
          break;
        }
        while(1)
        {
          SearchAddr = (long)((LowLimit + HighLimit) / 2);
          Response = SearchAndCompare(SearchAddr);
          delay(DALI_TWO_PACKET_DELAY);
          if (Response)
          {
            digitalWrite(LED_PIN, LOW);
            if ((SearchAddr == 0) || (!SearchAndCompare(SearchAddr - 1)))
              break;
            HighLimit = SearchAddr;
          }
          else
            LowLimit = SearchAddr;
        }
        delay(DALI_TWO_PACKET_DELAY);
        SearchAndCompare(SearchAddr);
        delay(DALI_TWO_PACKET_DELAY);
        DaliTransmitCMD(PRG_SHORT_ADDR, ((ShortAddr << 1) | 1));
        delay(5*DALI_TWO_PACKET_DELAY);
        DaliTransmitCMD(WITHDRAW, 0x00);
        delay(DALI_TWO_PACKET_DELAY);
        Serial.print("24-bit address found: 0x");
        Serial.println(SearchAddr, HEX);
        Serial.print("Assigning short address ");
        Serial.println(ShortAddr);
        ShortAddr++;
       // break; //только для одного модуля
      }
      delay(DALI_TWO_PACKET_DELAY);
      DaliTransmitCMD(TERMINATE, 0x00);
      delay(DALI_TWO_PACKET_DELAY);
      Serial.println("Init complete");
    }
    //-------------------------------------------------boolSearchAndCompare(long SearchAddr){
      bool Response = 0;
      uint8_t HighByte = SearchAddr >> 16;
      uint8_t MiddleByte = SearchAddr >> 8;
      uint8_t LowByte = SearchAddr;
      for(uint8_t i = 0; i < 3; i++)
      {
        DaliTransmitCMD(SEARCHADDRH, HighByte);
        delay(DALI_TWO_PACKET_DELAY);
        DaliTransmitCMD(SEARCHADDRM, MiddleByte);
        delay(DALI_TWO_PACKET_DELAY);
        DaliTransmitCMD(SEARCHADDRL, LowByte);
        delay(DALI_TWO_PACKET_DELAY);
      }
      DaliTransmitCMD(COMPARE, 0x00);
      delayMicroseconds(7 * DALI_HALF_BIT_TIME);
      for(uint8_t i = 0; i < DALI_RESPONSE_DELAY_COUNT; i++)
      {
        if (analogRead(DALI_RX_PIN) < DALI_ANALOG_LEVEL)
        {
          Response = 1;
          digitalWrite(LED_PIN, HIGH);
          break;
        }
        delayMicroseconds(DALI_HALF_BIT_TIME);
      }
      return Response;
    }
    //-------------------------------------------------voidDaliTransmitCMD(uint8_t Part1, uint8_t Part2){
      uint8_t DALI_CMD[] = { Part1, Part2 };
      //Старт бит
      digitalWrite(DALI_TX_PIN, LOW);
      delayMicroseconds(DALI_HALF_BIT_TIME);
      digitalWrite(DALI_TX_PIN, HIGH);
      delayMicroseconds(DALI_HALF_BIT_TIME);
      //командаfor (uint8_t CmdPart = 0; CmdPart < 2; CmdPart++)
      {
        for(int i = 7; i >= 0; i--)
        {
          bool BitToSend = false;
          if ((DALI_CMD[CmdPart] >> i) & 1)
            BitToSend = true;
          if (BitToSend)
            digitalWrite(DALI_TX_PIN, LOW);
          else
            digitalWrite(DALI_TX_PIN, HIGH);
          delayMicroseconds(DALI_HALF_BIT_TIME);
          if (BitToSend)
            digitalWrite(DALI_TX_PIN, HIGH);
          else
            digitalWrite(DALI_TX_PIN, LOW);
          delayMicroseconds(DALI_HALF_BIT_TIME);
        }
      }
      digitalWrite(DALI_TX_PIN, HIGH);
    }
    

    Or download

    And this is a test. We manage two modules connected to DALI.
    Look
    #define DALI_TX_PIN   3#define DALI_RX_PIN   A0#define BROADCAST_CMD       0b11111111#define DOWN                0b00000010#define UP                  0b00000001#define DALI_CHNL_COUNT     4#define LAMP_OFF_VALUE      0#define DALI_HALF_BIT_TIME      416 //microseconds#define DALI_TWO_PACKET_DELAY   10 //miliseconds//аналоговые входыuint8_t AnalogPins[DALI_CHNL_COUNT] = {A1, A2, A3, A4, };
    //кнопкиuint8_t KeyPins[DALI_CHNL_COUNT] = {4, 5, 6, 7, };
    uint8_t DALIPrevVals[DALI_CHNL_COUNT] = {0, 0, 0, 0};
    uint8_t LampState[DALI_CHNL_COUNT] = {0, 0, 0, 0};
    voidsetup(){
      pinMode(DALI_TX_PIN, OUTPUT);
      digitalWrite(DALI_TX_PIN, HIGH);
      for(uint8_t i = 0; i < DALI_CHNL_COUNT; i++)
      {
        pinMode(KeyPins[i], INPUT);
        digitalWrite(KeyPins[i], HIGH);
      }
    }
    voidloop(){
      for(uint8_t PWM = 2; PWM < DALI_CHNL_COUNT; PWM++)
      {
        if (LampState[PWM] == 1)
        {
        uint16_t ADCValue = analogRead(AnalogPins[PWM]);
        if (ADCValue > 1016)
          ADCValue = 1016;
        ADCValue /= 4;
        uint8_t PWMVal = ADCValue;
        if (abs(DALIPrevVals[PWM] - PWMVal) >= 1)
        {
          DALIPrevVals[PWM] = PWMVal;
          DaliTransmitCMD(PWM << 1, PWMVal);
          if (LampState[PWM] == 0)
            LampState[PWM] = 1;
          delay(DALI_TWO_PACKET_DELAY);
        }
        }
      }
      for(uint8_t KEY = 0; KEY < DALI_CHNL_COUNT; KEY++)
      {
        if (digitalRead(KeyPins[KEY]) == LOW)
        {
          delay(70);
          if (KEY == 0)
          {
           DaliTransmitCMD(BROADCAST_CMD, UP);
           delay(DALI_TWO_PACKET_DELAY);
           break;
          }
          elseif (KEY == 1)
          {
           DaliTransmitCMD(BROADCAST_CMD, DOWN);
           delay(DALI_TWO_PACKET_DELAY);
           break;
          }
          if (digitalRead(KeyPins[KEY]) == LOW)
          {
            if (LampState[KEY] == 0)
            {
              LampState[KEY] = 1;
              uint16_t ADCValue = analogRead(AnalogPins[KEY]);
              if (ADCValue > 1016)
                ADCValue = 1016;
              ADCValue /= 4;
              uint8_t PWMVal = ADCValue;
              DaliTransmitCMD(KEY << 1, PWMVal);
            }
            else
            {
              LampState[KEY] = 0;
              DaliTransmitCMD(KEY << 1, LAMP_OFF_VALUE);
            }
            delay(DALI_TWO_PACKET_DELAY);
          }
          delay(500);
        }
      }
    }
    //-------------------------------------------------voidDaliTransmitCMD(uint8_t Part1, uint8_t Part2){
      uint8_t DALI_CMD[] = { Part1, Part2 };
      //Старт бит
      digitalWrite(DALI_TX_PIN, LOW);
      delayMicroseconds(DALI_HALF_BIT_TIME);
      digitalWrite(DALI_TX_PIN, HIGH);
      delayMicroseconds(DALI_HALF_BIT_TIME);
      //командаfor (uint8_t CmdPart = 0; CmdPart < 2; CmdPart++)
      {
        for(int i = 7; i >= 0; i--)
        {
          bool BitToSend = false;
          if ((DALI_CMD[CmdPart] >> i) & 1)
            BitToSend = true;
          if (BitToSend)
            digitalWrite(DALI_TX_PIN, LOW);
          else
            digitalWrite(DALI_TX_PIN, HIGH);
          delayMicroseconds(DALI_HALF_BIT_TIME);
          if (BitToSend)
            digitalWrite(DALI_TX_PIN, HIGH);
          else
            digitalWrite(DALI_TX_PIN, LOW);
          delayMicroseconds(DALI_HALF_BIT_TIME);
        }
      }
      digitalWrite(DALI_TX_PIN, HIGH);
    }
    

    Or download
    A lot of work has been done and therefore I want to share with everyone. Maybe it will facilitate the development of someone.

    No full library found in the network. Please use, everything really works. Ask questions, I and my colleagues will try to answer everything. Maybe not immediately, because we are really going on vacation for two weeks.

    In the video report on the work.

    We tested the DAP-04 and LCM-60DA modules from Mean Well. But it will work with any others.

    And this is the Arduino body kit that translates it into DALI master mode and a power supply at the same time.



    This is a button connection for a test sketch.



    And here is a small network DALI




    Also popular now: