DALI通信的原理及实现方法

在双碳目标下,具有调光功能的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)?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; //定时器初始值置095 pr1 = 260; //定时器周期设置为te96 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%的误差。 有待改善。

S3C44B0X和M12模块设计的GPS接收终端方案
如何进行嵌入式诊断设计?这些方法拿走不谢
掌握这3类二极管钳位电路少走弯路
随着RFID在鞋服领域的普及度不断上升,应用场景和方式会更加成熟
你了解SSD中的软件算法吗
DALI通信的原理及实现方法
复合惯性传感器的工作原理
东芝推出采用新型高散热封装的车载40V N沟道功率MOSFET,支持车载设备对更大电流的需求
国科微以3.6亿元收购深圳华电通讯有限公司100%股权
孟晚舟律师团队向法院提交备忘录,认为汇丰银行配合美国设计孟晚舟
在互联网+金融的发展下,银行转型的必要性
MOVIN:打破“低价低质”的行业壁垒,存量市场时代的“必然较量”
曝Windows 10 Version 2004功能更新最早3月下旬推送 主要针对现有功能进行优化和调整
RA MCU使用Virtual EEPROM
厦门士兰集科微电子有限公司12英寸生产线正式投产
小米MIUI9什么时候发布?MIUI9最新消息:7月12日将提供外部测试预览版
基尔霍夫定律kcl和kvl
高速贴片机与中速贴片机的优缺点比较:选对设备,事半功倍
赋能智慧交通的“5G+智能算力”技术
晶圆双雄及联发科卡位物联网芯片