原创 基于新唐DMX512帧头的判断

2011-10-9 11:52 6277 23 25 分类: MCU/ 嵌入式

DMX 512协议是Digital Multiplex的缩写,是灯光行业数字化设备的通用信号控制协议,同时也是是一种国际协议;由美国剧场技术协会(United State Institute for Theatre TechnologyInc)于19868月提出的一个能在一对线上传送512路可控硅调光亮度信息的标准. DMX512 通信方式是采用了异步通信格式,每个调光点由 11 位组成其中一个是起始位,8位调光数据,两个停止位.每一次传输能512个调光点.

特点:

1.采用EIA485标准硬件线路,波特率250Kbps,每个数据位4us,每帧传输的时间约22.7ms,半双工模式;

       2.每个调光点由1个起始位,8个调光数据位,两个停止位;

       3.需要传输188us的低电平数据间隙,作为一个数据包的起始帧头,接收方有间隙检测电路,需要找到起始帧头;无通信校验位;

4.数据帧头后面是一个空闲帧,通常是8us-1ms,紧接着还有一个字节数据,用来

表示设备代号或自定义用途,通常是0,该字节数据可以用于自动写码命令之用;

 

20111009114939001.jpg

20111009114942002.jpg

DMX512(1990)的时序图看出,其在每一帧的必须有一个不得小于88usbreak信号;接着才是8个数据位2个停止位的uart标准格式数据;所以用单片机的中断定时等方法来判断这个break显然有点麻烦;下面给出一些更为简易的方法:

 

Break的简易判断

方法1: uart/4859bit模式接收,判断第9bit 0还是1

在接收break信号的时候第9位必然为0(因为break为不低于88Us的低电平),而其它的数据的是2位的停止位,接收到的第9位就是其第一个停止位所以必然为1

注意:

在接收break的时候,由于是88us的低电平,停止位不正确;但是单片机还是能正确检测到第9bit0的;

不影响第九位的判断(cotex-M0的内核经过测试);

 51单片机,AVR都有9bit模式,arm内核可以通过强制奇偶校验位,利用奇偶校验错误来判断第9bit,

cortex-M0内核,其拥有RS4859bit模式(起始也是利用奇偶校验位来实现的)

 

以下先给出一个网友提供的基于AVR的代码:

// HardWare: Mega64@16MHz
//
 Tools:    GCC

#define
  CHECK_DMX_SYNC             0
#define
  CHECK_DMX_1ST_DATA         1
#define
  CHECK_DMX_START_CHANNEL    2
#define
  NORMAL_RECEIVE_DMX_DATA    3
#define
  DMX_RECEIVE_OVER           4
#define
  DMX_ERROR                  5

void
 DMX_Receive_Initial(void)
{
 dmx_receive_stage = CHECK_DMX_SYNC;
 dmx_sync_ok_f     = FALSE;
 dmx_fail_timer    = 0;

 UCSR1A = 0x00;
 UCSR1C = 0x86;
 UBRR1L = 0x03; 
 UBRR1H = 0x00; 
 UCSR1B = 0x94;
}


SIGNAL(SIG_UART1_RECV)
{
 unchar tmp_rb8;
 unchar tmp_receive_data;

//ReadSeriesRegister:
 tmp_rb8          = UCSR1B;
 tmp_receive_data = UDR1; 
 
//ReceiveDataProcess:
 tmp_rb8 &= 0x02;
 if(tmp_rb8 == 0) // 9bit -0 ,表示是break
  {
   if(dmx_receive_stage == CHECK_DMX_SYNC)
    {
     dmx_receive_stage = CHECK_DMX_1ST_DATA;
    }
  } 
 else
  {
   if(dmx_receive_stage == CHECK_DMX_1ST_DATA)
    {
     if(tmp_receive_data == 0)  // 第一个数据,通常是0
      {
       dmx_receive_stage = NORMAL_RECEIVE_DMX_DATA;
       dmx_receive_point = 0;
       dmx_sync_ok_f     = TRUE;
       dmx_fail_timer    = 0;
      }
     else
      dmx_receive_stage = CHECK_DMX_SYNC;
     return;
    }
   if(dmx_receive_stage == NORMAL_RECEIVE_DMX_DATA)
    {
     dmx_receive_buf[dmx_receive_point] = tmp_receive_data;
     dmx_receive_point ++;
     if(dmx_receive_point > DMX_CHANNEL_NUMBER-1) dmx_receive_stage = CHECK_DMX_SYNC;
     return;
    }
   dmx_receive_stage = CHECK_DMX_SYNC;
  } 
}

NUvoton M051上的实现

这里给出基于Nuvotn M051系列利用RS485 9bit 普通模式来实现的主要代码(基于CMSIS):

先初始化uart 485

    /* Set UART Configuration */

    sParam.u32BaudRate      = DMX_512 _Baud;

    sParam.u8cDataBits      = DRVUART_DATABITS_8;

    sParam.u8cStopBits      = DRVUART_STOPBITS_1;

    sParam.u8cParity        = DRVUART_PARITY_ODD;

    sParam.u8cRxTriggerLevel= DRVUART_FIFO_1BYTES;

    sParam.u8TimeOut        = 0x7F;

    DrvUART_Open(UART_PORT1,&sParam);

//-----------------------------------------

    /* Set RS485 Configuration */

    sParam_RS485.u8cAddrEnable = ENABLE; // 使能第9bit地址数据

    sParam_RS485.u8cModeSelect = MODE_RS485_NMM|MODE_RS485_AUD ; //设置成普通模式和AUD

    sParam_RS485.u8cDelayTime  = 0;

    sParam_RS485.u8cRxDisable  = 0; 

    DrvUART_SetFnRS485(UART_PORT0,&sParam_RS485);  //请修改该库函数,确保RXDisble , RS_R485_NMM之前设置好(原厂的库函数有bug

 

// 使能相关中断函数

DrvUART_EnableInt(UART_PORT0, DRVUART_RLSINT|DRVUART_RDAINT|DRVUART_TOUTINT,

                                 (PFN_DRVUART_CALLBACK*)RS485_HANDLE);

 

void RS485_HANDLE( void ) 

{

    volatile char addr;

    volatile char regRX;

    if(UART0->ISR.RLS_INT ==1)      /* RLS INT & RDA INT */

    { 

   

        if((UART0->FSR.RS485_ADD_DETF ==1) && (UART0->FUNSEL.FUN_SEL == FUN_RS485))  /* ADD_IF, RS485 mode */

        {          

            addr = UART0->DATA;

            UART0->FSR.RS485_ADD_DETF =1;                       /* clear ADD_IF flag */

            DMX_512_ADDR = 1;

            printf("bit 9 =1 \n");

        }

        printf("RLS_INT = %c \n",addr);

    }

    Else  if((UART0->ISR.RDA_INT == 1))/* Rx Ready */   /* Time-out INT */

    {

        regRX = UART0->DATA;

u8RecData[r_pointer++] = regRX;

        printf("bit 9 =0 \n");

        printf("RDA_INT = %c \n",regRX);

    }

 

    else if((UART0->ISR.TOUT_INT == 1))/* Rx Ready */   /* Time-out INT */

    {

        regRX = UART0->DATA;

 

        if(IsRS485ISR_TX_PORT)

            UART0->DATA = regRX;   

        else

            u8RecData[r_pointer++] = regRX;

            printf("TOUT_INT \n");

    }

 

    else if(UART0->ISR.BUF_ERR_INT == 1)                        /* Buff Error INT */

    {

        printf("\nBuffer Error...\n");

        while(1);  

    }

}

这里只是给出了判断第9bit0还是为1的部分代码,大家可以仿造前面在AVR上实现的DMX512协议代码把其做修改即可;注意设置成RS485 9bit模式后,相关的奇偶校验将不能引发中断;

关于发送的话,可以用延时函数来实现;有的工程师也可以用9bit 模式发送第9bit 10的方法来实现,然而这只是用于自己公司的系统中,并不是标准的DMX512, 不能通用;

 

 

 

 

 

 

方法2:用收线状态中断RLS_INTBIF

cortex M0 可以用收线状态中断RLS_INTBIF(钳制中断标志位:当接收数据时,数据线保持0的时间超过接收整个字节的时间时则置位)中断来实现BREAK的接收;

飘渺九哥已经写了个基于nuvoton M0516的例子,大家可以点击下面链接得到做参考;

http://bbs.21ic.com/icview-231705-1-1.html

方法3:用帧错误中断来判断

接收break的时候,因为break为不低于88us的低电平,必然会引起帧错误中断,所以可以以此来识别其是break信号;具体代码的实现这里不做说明;

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户428812 2012-11-3 10:53

我最近也在用新唐M051来搞DMX512,欢迎交谈:953157565

用户1605399 2012-5-30 11:08

实在!
相关推荐阅读
用户161601 2013-06-06 11:27
AT91LINUX编译试验 SAMA5DX cortex A5
atmel官方网站www.at91.com中对基于DTB的linux内核编译流程如下:   本文档为本人在ubuntu 10.04下实验流程,红色文字为本人添加的记录; by Jevon...
用户161601 2013-04-21 10:54
ubuntu10.04 vm6.5 hgfs 共享实现
以前用的VMWARE6.5+FC12安装好VM TOOL后 就可以在/mnt/hgfs 访问window中的共享文件夹了; 如今把FC12抛弃了,改装了ubuntu10.04但发现hgfs目录...
用户161601 2012-11-29 09:46
芯片制造工艺流程(转)
  芯片制造工艺流程   芯片制作完整过程包括 芯片设计、晶片制作、封装制作、成本测试等几个环节,其中晶片片制作过程尤为...
用户161601 2011-12-13 14:28
摄像头的组成以及红外摄像头
摄像头的工作原理大致为:景物通过镜头(LENS)生成的光学图像投射到图像传感器表面上,然后转为电信号,经过A/D(模数转换)转换后变为数字图像信号,再送到数字信号处理芯片(DSP)中加工处理,再通...
用户161601 2011-11-01 10:50
KEIL MDK生成 bin 文件 for nxp MCU
说明:本文的实践是基于lpc1343; 要想在keil中直接生成bin文件一般需要加用户命令调用fromelf工具: 如下图在Options for Target 中 加上编译后的命令; ...
EE直播间
更多
我要评论
2
23
关闭 站长推荐上一条 /3 下一条