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%的误差。 有待改善。

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

    关注

    6043

    文章

    44617

    浏览量

    638232
  • 通信
    +关注

    关注

    18

    文章

    6069

    浏览量

    136380
  • C语言
    +关注

    关注

    180

    文章

    7614

    浏览量

    137628
  • DALI
    +关注

    关注

    4

    文章

    67

    浏览量

    20811
  • 驱动电源
    +关注

    关注

    22

    文章

    411

    浏览量

    42456
收藏 人收藏

    评论

    相关推荐

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

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

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

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

    DALI系统的研究与开发

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

    Dali通信的工作原理 如何使用Dali通信协议

    一、引言 Dali(Digital Addressable Lighting Interface,数字可寻址照明接口)是一种用于照明控制产品之间双向通信的协议。通过Dali通信协议,可
    的头像 发表于 01-31 10:33 57次阅读

    Dali通信在智能照明中的应用

    ,通过总线将照明设备连接在一起,实现对照明设备的精确控制。 1.2 Dali通信技术的原理 Dali通信技术
    的头像 发表于 01-10 10:21 154次阅读

    Dali通信和传统照明的比较

    控制照明设备。Dali通信可以实现对照明设备的精确控制,包括亮度、色温等参数。 二、传统照明的工作原理 传统照明主要依赖于机械开关和手动调节,用户需要亲自操作开关来控制照明设备的开关和亮度。传统照明无法
    的头像 发表于 01-10 10:22 131次阅读

    Dali通信网络的最佳配置

    DALI(数字可寻址照明接口)通信网络的最佳配置涉及多个方面,包括网络架构、设备选择、布线要求以及功能实现等。以下是对DALI通信网络最佳配
    的头像 发表于 01-10 10:32 175次阅读

    Dali通信系统常见故障及解决方法

    Dali通信系统因其高效、灵活和可靠的特点,在现代照明控制领域中得到了广泛应用。然而,任何系统都有可能遇到故障。 1. 通信故障 1.1 故障现象 控制器无法与Dali设备
    的头像 发表于 01-10 10:38 262次阅读

    Dali通信的优势和劣势

    Dali通信的优势 1. 数字化控制 Dali通信采用数字信号传输,与传统的模拟控制相比,数字信号更稳定、抗干扰能力强,能够实现更精确的控制
    的头像 发表于 01-10 10:40 153次阅读

    Dali通信协议的标准解析

    DALI协议最初由欧洲委员会在1990年代中期开发,旨在为照明控制系统提供一个开放的、标准化的通信接口。DALI协议允许照明设备(如调光器、传感器和灯具)之间进行双向通信
    的头像 发表于 01-10 10:42 254次阅读

    Dali通信与物联网的结合

    地增强了其能效和用户体验。 一、DALI通信协议简介 DALI协议是一种国际标准的光伏照明控制系统,用于控制和管理照明设备。它支持单线双向通信,每个灯具都具备唯一地址,可以通过
    的头像 发表于 01-10 10:45 143次阅读

    Dali通信如何提高能源效率

    实现这一目标提供了有效的技术支持。 一、DALI通信的基本原理 DALI通信协议是一种双向、可寻址的照明控制协议,它允许单个灯具或灯具组被单
    的头像 发表于 01-10 10:46 119次阅读

    Dali通信系统的调试指南

    调试通信系统是一个复杂的过程,涉及到对系统性能的测试、故障排除和优化。以下是一个关于调试Dali通信系统的指南,假设Dali是一个特定的通信
    的头像 发表于 01-10 10:47 266次阅读

    Dali通信与其他通信协议的对比

    DALI协议最初由欧洲照明制造商开发,旨在为照明控制系统提供一个标准化的接口。它支持双向通信,允许中央控制系统与每个灯具进行通信,从而实现精确的控制和监控。
    的头像 发表于 01-10 10:51 181次阅读

    Dali通信模块的选择与配置

    DALI(数字可寻址照明接口)通信模块的选择与配置涉及多个方面,包括网络架构、设备选择、布线要求以及功能实现等。以下是对DALI通信模块选择
    的头像 发表于 01-10 10:55 148次阅读