DALI通信及C語言實現


        在雙碳目標下,具有調光功能的LED驅動電源是重要的分支。DALI通信常用在LED的數字調光控制中,下文將通過C語言與單片機結合,解釋DALI的原理及實現方法。

一、通信原理

  1.1 DALI 的物理電平信號定義如下:
             9.5~22.5V: 高電平或者DALI 空閑狀態
             6.5~9.5V:   未定義
             -6.5V~6.5V:定義為低電平
    
       1.2 波特率:1200bps + 10%
 
  1.3 DALI 負載最大短路電流<250mA
    當從機發生故障,例如短路時,DALI總線上的電流,需要限制在250mA以下。
 
  1.4 編碼方式
    使用曼切斯特編碼,即上升沿為信號1,下降沿為信號0。
  1.5 主機發送指令結構
             主機發送的包含1個起始位、1個地址位類型位、6個地址位、一個選擇位、8個數據位和兩個停止位。

 

  1.6 從機回復指令結構

    從機向主機回復包含1個起始位、8個數據位和兩個停止位。

  1.7 前向幀與后向幀時序約束

    Te表示半個位的時間,即4.16.67uS;

    兩個前向幀時間間隔大於22個Te;

    前向幀與后向幀之間時間間隔為7~22個Te;

               后向幀與前向幀之間時間間隔大於22個Te;

  1.8 主機與從機的握手

              主機在發送指令后,在等候響應階段,

                      如果收到從機發送的”0xFF“,就會認為從機接收成功;

                      如果在這個階段處於空閑狀態,就會認為從機沒有接收成功;

二、實現方法

   2.1 硬件原理圖

    下面的硬件主要是將DALI的電平信號,轉為單片機能夠接受的電平,下面那張是微芯公司DALI的參考通信電路。

 

 

 

   2.1 從機接收思路及實現

    本次從機的接收端,主要使用了一個邊沿檢測中斷和一個定時器中斷。

    代碼思路:

      1)由於空閑狀態,接收端的電平為高電平,產生起始信號時,需要從產生一個上升沿。於是,使用了外部下降沿觸發中斷,並關閉邊沿觸發中斷;

      2)檢測到第一個下降沿后,定時器定時到0.75個周期,0.75個周期后讀取第一位數據,並修改定時器周期為1個數據位時長。

      3)第二次定時結束時讀取第二位數據,依次讀取后面的數據

      4)當讀到最后一位數據的時候,也就是LSB后的兩位時,停止定時器,並初始化定時器為0.75個數據周期,然后開啟邊沿觸發中斷。

     C語言程序:

  1 //配置邊沿觸發及中斷
  2 void IO_Change_Init(void){  
  3     
  4     //Set the CN2 as the IO state change flag 
  5     CNEN1bits.CN2IE=1;//Open the IO state interrupt
  6     CNPU1bits.CN2PUE=0;//Disable the weak up
  7     
  8     IFS1bits.CNIF=0;//Clear the interrupt flag
  9     IPC4bits.CNIP=7;//Configure the interrupt level 7
 10     IEC1bits.CNIE=1;//Enable this interrupt
 11 }
 12 //檢測到第一個下降沿
 13 void __attribute__ ((__interrupt__,__no_auto_psv__)) _CNInterrupt(void){
 14    
 15    IFS1bits.CNIF = 0; //Clear the interrupt flag 
 16    
 17    //Disable the IO State Interrupt and start the Time
18 T1CONbits.TON = 1; 19 CNEN1bits.CN2IE = 0; 20 21 } 22 //配置定時器初使周期為0.75個數據位時長 23 void Tim1_Init(void){ 24 T1CON = 0x0020; 25 26 IEC0bits.T1IE = 1; 27 IPC0bits.T1IP = 7; 28 IFS0bits.T1IF = 0; 29 30 TMR1 = 0; 31 PR1 = 390; 32 T1CONbits.TON = 0; 33 } 34 //在定時器中斷里面讀取數據 35 void __attribute__((__interrupt__,auto_psv,__shadow__)) _T1Interrupt(void) 36 { 37 IFS0bits.T1IF = 0; 38 39 if(LLC_DALI_Rx_Mode == 1) 40 { 41 switch(Timer_Num) 42 { 43 case 0: 44 Timer_Num++; 45 T1CONbits.TON = 0; //關閉定時器 46 PR1 = 520; //設置下一個定時時長為1個周期 47 TMR1 = 0;//初使化定時器初始值 48 T1CONbits.TON = 1;//開啟定時器 49 break; 50 case 1: 51 if(_RB0 == 1 )Address_temp |= (1<<7); 52 Timer_Num++; 53 break; 54 case 2: 55 if(_RB0 == 1 )Address_temp |= (1<<6); 56 Timer_Num++; 57 break; 58 case 3: 59 if(_RB0 == 1 )Address_temp |= (1<<5); 60 Timer_Num++; 61 break; 62 case 4: 63 if(_RB0 == 1 )Address_temp |= (1<<4); 64 Timer_Num++; 65 break; 66 case 5: 67 if(_RB0 == 1 )Address_temp |= (1<<3); 68 Timer_Num++; 69 break; 70 case 6: 71 if(_RB0 == 1 )Address_temp |= (1<<2); 72 Timer_Num++; 73 break; 74 case 7: 75 if(_RB0 == 1 )Address_temp |= (1<<1); 76 Timer_Num++; 77 break; 78 case 8: 79 if(_RB0 == 1 )Address_temp |= (1<<0); 80 Timer_Num++; 81 break; 82 case 9: 83 if(_RB0 == 1 )Command_temp |= (1<<7); 84 Timer_Num++; 85 break; 86 case 10: 87 if(_RB0 == 1 )Command_temp |= (1<<6); 88 Timer_Num++; 89 break; 90 case 11: 91 if(_RB0 == 1 )Command_temp |= (1<<5); 92 Timer_Num++; 93 break; 94 case 12: 95 if(_RB0 == 1 )Command_temp |= (1<<4); 96 Timer_Num++; 97 break; 98 case 13: 99 if(_RB0 == 1 )Command_temp |= (1<<3); 100 Timer_Num++; 101 break; 102 case 14: 103 if(_RB0 == 1 )Command_temp |= (1<<2); 104 Timer_Num++; 105 break; 106 case 15: 107 if(_RB0 == 1 )Command_temp |= (1<<1); 108 Timer_Num++; 109 break; 110 case 16: 111 if(_RB0 == 1 )Command_temp |= (1<<0); 112 Timer_Num++; 113 break; 114 case 17: 115 if(_RB0 == 1 )StopBit_temp |= (1<<1); 116 Timer_Num++; 117 break; 118 case 18: 119 if(_RB0 == 1 )StopBit_temp |= (1<<0); 120 Timer_Num++; 121 break; 122 case 19: 123 T1CONbits.TON = 0;//關閉定時器 124 PR1 = 390;//設置下一個定時器周期為0.75個數據位時長 125 TMR1 = 0;//定時器計數初始值置0 126 CNEN1bits.CN2IE = 1;//開啟邊沿檢測中斷 127 //數據獲取,這里還可以添加數據包檢驗程序 128 Command = Command_temp; 129 Address = Address_temp; 130 StopBit = StopBit_temp; 131 132 Command_temp = 0; 133 Address_temp = 0; 134 StopBit_temp = 0; 135 Timer_Num = 0; 136 break; 137 } 138 } 139 140 141

  2.2 從機思路及實現

              從機的回復相對較簡單,只需要在每半個數據位修改輸出引腳的電平。分別發送1個起始位、8個數據位和兩個停止位。

    代碼思路:

      1)接收數據完成並定時等待8Te

      2)發送一個引腳低電平,並設置下一個定時周期為Te,定時器初使值為0,並開啟定時器;

      3)在后面的定時器中斷里面,發送起始位;

      4)在后面的定時器中斷里面,發送數據位;

      5)在后面的定時器中斷里面,發送停止位;

      6)初使化發送數據計數變量,初始化定時器計數值為零,關閉定時器;

                      7)開啟邊沿觸發中斷;

    C語言程序實現

 1   if(LLC_DALI_Tx_Mode == 1){
 2         switch(Timer_Num)
 3         {
 4             case 0:
 5                 //Send the Start Bit
 6                 _RF3 = 0;
 7                 T1CONbits.TON = 0;
 8                 PR1 = 260;
 9                 TMR1 = 0;
10                 T1CONbits.TON = 1;
11                 Timer_Num++;
12                 break;
13             case 1:
14                 _RF3 = 1;
15                 Timer_Num++;
16                 break;
17             case 2:
18                  //Send the Data Bits
19                 _RF3 = ((Transfer_Data & 0x80)>0)?0:1;
20                 Timer_Num++;
21                 break;
22             case 3:
23                 _RF3 = ((Transfer_Data & 0x80)>0)?1:0;
24                 Timer_Num++;            
25                 break;
26             case 4:
27                  _RF3 = ((Transfer_Data & 0x40)>0)?0:1;
28                 Timer_Num++;
29                 break;
30             case 5:
31                 _RF3 = ((Transfer_Data & 0x40)>0)?1:0;
32                 Timer_Num++;            
33                 break;
34             case 6:
35                 _RF3 = ((Transfer_Data & 0x20)>0)?0:1;
36                 Timer_Num++;        
37                 break;
38             case 7:
39                 _RF3 = ((Transfer_Data & 0x20)>0)?1:0;
40                 Timer_Num++;
41                 break;
42             case 8:
43                 _RF3 = ((Transfer_Data & 0x10)>0)?0:1;
44                 Timer_Num++;
45                 break;
46             case 9:
47                 _RF3 = ((Transfer_Data & 0x10)>0)?1:0;
48                 Timer_Num++;
49                 break;
50             case 10:
51                 _RF3 = ((Transfer_Data & 0x08)>0)?0:1;
52                 Timer_Num++;
53                 break;
54             case 11:
55                 _RF3 = ((Transfer_Data & 0x08)>0)?1:0;
56                 Timer_Num++;
57                 break;
58             case 12:
59                 _RF3 = ((Transfer_Data & 0x04)>0)?0:1;
60                 Timer_Num++;
61                 break;
62             case 13:
63                 _RF3 = ((Transfer_Data & 0x04)>0)?1:0;
64                 Timer_Num++;
65                 break;
66             case 14:
67                 _RF3 = ((Transfer_Data & 0x02)>0)?0:1;
68                 Timer_Num++;
69                 break;
70             case 15:
71                 _RF3 = ((Transfer_Data & 0x02)>0)?1:0;
72                 Timer_Num++;
73                 break;
74             case 16:
75                 _RF3 = ((Transfer_Data & 0x01)>0)?0:1;
76                 Timer_Num++;
77                 break;
78             case 17:
79                 _RF3 = ((Transfer_Data & 0x01)>0)?1:0;
80                 Timer_Num++;
81                 break;
82             case 18:
83                 //Send the stop bit;
84                 T1CONbits.TON = 0;
85                 TMR1 = 0;
86                 PR1 = 260<<2;
87                 T1CONbits.TON = 1;
88                 _RF3 = 1;
89                 Timer_Num++;
90                 break;
91             case 19:
92                    T1CONbits.TON = 0;  //關閉定時器
93                    CNEN1bits.CN2IE = 1;//開啟邊沿檢測中斷
94                    TMR1 = 0;  //定時器初始值置0
95                    PR1 = 260; //定時器周期設置為Te
96                    Timer_Num = 0;//初使定時器數據位計數
97                 break;
98         }
99     }

 

三、測試結果

   3.1 從機發送測試

              從機發送數據100,對應二進制為0b0110 0100,實際發送波形見下圖:

 

      實際發送數據為0b01100100,發送正常。

  3.2 主機發送從機識別測試

    主機通過上位機發送調光指令為239,從機在線調試識別出來的數據為239。接收正常。

 

 

 

四、小結

       從機的接收程序,定時器的定時步長先是1.5個Te,然后是2個Te;

         從機的發送程序,定時器的定時步長為1個Te;

         從機的接收程序,邊沿觸發只觸發依次就關閉了。

         從機的發送程序,發送完畢開啟邊沿觸發。

   在定時器中斷里面,修改下一個定時時長,理論上可以做到每一個定時周期都不一樣,這思維可以用於實現更加復雜的功能。

         注意:

    1)以上代碼發送和接收是獨立的,沒有遵循通信的時序。1.7節里面有具體時序要求,根據時序稍做修改就可以啦。

    2)本次代碼,沒有考慮到時序有10%的誤差。有待改善。

五、參考資料

  【1】Digital Addressable Lighting Interface (DALI) Control Devices Protocol,PART 1-2004 

    【2】DALI控制裝置,AN1487,Microchip

         【3】數字可尋址照明接口(DALI)通信,AN1465,Microchip

    【4】Digital Addressable Lighting Interface (DALI) Implementation Using MSP430 Value Line Microcontrollers,TI


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM