0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

DALI通信的原理及实现方法

CHANBAEK 来源:博客园-斑鸠,一生。 作者:博客园-斑鸠,一生 2023-03-08 14:58 次阅读

在双碳目标下,具有调光功能的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%的误差。 有待改善。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6001

    文章

    43973

    浏览量

    620857
  • 通信
    +关注

    关注

    18

    文章

    5706

    浏览量

    134396
  • C语言
    +关注

    关注

    180

    文章

    7530

    浏览量

    128763
  • DALI
    +关注

    关注

    4

    文章

    63

    浏览量

    20638
  • 驱动电源
    +关注

    关注

    22

    文章

    390

    浏览量

    42039
收藏 人收藏

    评论

    相关推荐

    照明照明控制系统中DALI总线调试方法

    随着楼宇自动化和照明工业的快速发展,传统的照明控制逐步被智能控制取代,DALI作为新的智能灯光控制协议,定义了电子镇流器与控制器之间的通信方式,实现智能照明系统的自动化控制。那么如何快速调试照明控制
    的头像 发表于 10-22 08:55 1.1w次阅读

    什么是DALI?数字可寻址照明接口(DALI)的实现方法

    DALI是首字母缩写,代表“数字可寻址照明接口”。这是一个国际标准,可保证不同制造商的可调光镇流器的互换性。
    的头像 发表于 04-21 16:08 1.7w次阅读
    什么是<b class='flag-5'>DALI</b>?数字可寻址照明接口(<b class='flag-5'>DALI</b>)的<b class='flag-5'>实现</b><b class='flag-5'>方法</b>

    DALI协议

    DALI第一套协议”(DALI 1.0),“DALI第二套协议”(DALI 2.0),“DALI NFC”,“
    发表于 10-21 21:29

    PIC24F是否有可用的DALI样例代码?

    大家好,我使用PIC24F08KL302和MPLAB X IDE和XC16编译器。我只是想用这个PIC来实现DALI通信。这有可能是PIC单片机还是有特定的PIC单片机的DALI总线模
    发表于 01-15 14:19

    DALI通信协议有什么想法吗?

    嗨,伙计们,我是DALI的新成员,现在我需要在我的橙色PI零板上实现DALI主协议,有人对硬件要求有什么想法或建议吗?谢谢。 以上来自于百度翻译 以下为原文 Hi guys, I am new
    发表于 04-29 13:51

    ST7DALI-EVAL,在DALI可调光镇流器应用中需要微控制器进行通信

    ST7DALI-EVAL,ST7 MCU电子镇流器照明控制评估系统。在DALI可调光镇流器应用中需要微控制器进行通信通信协议和接口参数已由领先的照明设备制造商定义
    发表于 10-11 08:42

    采用SAMD2x参考设计的DALI从机堆栈,使用SAM D20实现DALI主站

    采用SAMD2x参考设计的DALI从机堆栈。该参考设计使用SAM D20实现DALI(IEC 62386)主站。 Dali master用于大理奴隶在楼宇自动化和家庭网络中的控制照明
    发表于 05-27 12:28

    DALI - DALI电源调试的难点

    在介绍了大量的DALI标准背景和发展趋势之后,我们还需要尽力解决产品落地和工程应用中的痛点,唯有如此,DALI生态才会有健康发展的可能。基于DALI标准的产品中,当前应用最广的当属LED...
    发表于 10-29 09:22

    请问DALI 2.0有相窝DALI 1.0吗?

    请问DALI 2.0有相窝DALI 1.0吗?
    发表于 08-21 06:37

    DALI系统的研究与开发

    DALI协议的开发背景和应用范围的基础上,分析了DALI协议的电气特性,编码格式和传输规则。重点论述了DALI主从式模块的设计,该模块采用MC68HC908KX8芯片为CPU,实现
    发表于 08-09 14:50 88次下载
    <b class='flag-5'>DALI</b>系统的研究与开发

    使用示波器分析DALI协议

    随着楼宇自动化和照明工业的快速发展,传统的照明控制逐步被智能控制取代,DALI作为新的智能灯光控制协议,定义了电子镇流器与控制器之间的通信方式,实现智能照明系统的自动化控制,那么,如何快速调试照明
    发表于 11-08 11:42 12次下载
    使用示波器分析<b class='flag-5'>DALI</b>协议

    DALI解码

    接口功能,符合IEC 60929/IEC 62386标准,兼容性好,可以兼容任何符合DALI协议的设备,通过输入标准的DALI信号,实现产品的开关、调光、场景、群组、编址等功能。4、灵活性本模块输出
    的头像 发表于 09-06 13:39 5006次阅读

    DALI调色温解码

    DALI调色温 一、概述(13923882807,QQ:813267849) 欢迎使用本公司的DALI解码模块,拥有DALI第一套协议 (DALI 1.0),
    的头像 发表于 09-28 09:56 3406次阅读

    DALI2

    DALI接口功能,符合IEC 60929/IEC 62386标准,兼容性好,可以兼容任何符合DALI协议的设备,通过输入标准的DALI信号,实现产品的开关、调光、场景、群组、编址等功
    发表于 12-06 23:46 434次阅读

    大力哥谈 DALI - DALI 调光电源怎么用

    今天我们来谈一谈 DALI 的具体应用, 最主要的是 DALI 控制装置中的调光驱动电源的使用场景, 比如 DT6 和 DT8 产品(参考文章 大力哥谈 DALI - D...
    发表于 01-05 14:20 12次下载
    大力哥谈 <b class='flag-5'>DALI</b> -  <b class='flag-5'>DALI</b> 调光电源怎么用