stm32實現DMX512協議發送與接收(非標)


 最近把玩了一下485,期間也接觸了dmx512通信協議,該協議主要用於各種舞台燈光的控制當中,進而實現各種光效以及色彩變化。根據標准的512協議,其物理連接與傳統上的RS485是完全一致的,並沒有什么差別,差別只是在協議上的不同,工業上應用的主要是modbus協議,而這里是用512通信協議。
       
      DMX512數據協議是美國舞台燈光協會(USITT)於1990年發布的一種燈光控制器與燈具設備進行數據傳輸的標准。它包括電氣特性,數據協議,數據格式等方面的內容。
512協議規定使用的波特率是250Kbps,但是stm32可以支持shangMbps的波特率,所以說這不是什么大問題。
      
     該協議發送的數據幀一共11位,1位開始位,8位數據,2個停止位,無校驗位。

 

根據波特率可以知道,位時間是4us,11位數據供需要44us的時間。當然對於標准的512協議是需要break和mark after break 幀的,break是一個92us的低電平,而mark after break是一個12us的高電平,如下圖所示

 

 

 


    根據上面的圖片(缺失了起始碼,下圖補上),512協議必須有break和mark,但是在我們通常的非標准收發中,檢測break和mark相對比較困難,如果非要做,耗費的資源也比較多,比如定時器計時,中斷等等。如果不是做標准控制器的,完全可以另辟蹊徑。

      

根據512 協議,每一串數據的開始都要有一個起始碼,也稱復位碼,其數據為0,但是從開始位數至第十位是0,用來聲明數據傳輸開始,隨后包含1-512個數據,也稱調光數據,其是標准的數據幀,所以第十位是1,所以我們可以根據這個第十位來進行做文章。大家都知道,一般的單片機,像51,avr等都是支持8-9位數據發送的,所以我們就是用9位數據,1位停止位,無校驗位,通過檢測檢測第十位,也就是所謂的RB8來進行數據的接收與傳輸,不需要發送break和mark。


1、發送端
     
      串口設為 9位數據,1停止位,無校驗位,波特率250000

void USART1_Configuration(void)
{      
  USART_InitTypeDef USART_InitStructure;
 
  USART_InitStructure.USART_BaudRate = 250000;
  USART_InitStructure.USART_WordLength = USART_WordLength_9b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* Configure USART1 */
  USART_Init(USART1, &USART_InitStructure);  
  /* Enable USART1 Receive and Transmit interrupts */
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  //USART_ITConfig(USART1, USART_IT_TC, ENABLE);
  /* Enable the USART1 */
  USART_Cmd(USART1, ENABLE);
}


注意在初始化串口的時候別忘了485芯片設為發送狀態

接下來主要就是數據包的發送,發送的時候注意起始碼的數據第九位設為0,調光數據第九位設為1.

void DMX_SendPacket(void)
{
  pDMX_buf = 0;
  
  while (pDMX_buf <= 512) //1-512
  {
    /* send data packet to slaves*/
    if(USART1->SR & (1<<6))
    {
       /*發送起始碼 00*/
       if (0 == pDMX_buf)   
       {
          USART1->DR = ((USART1->DR) & 0xfe00);   //第九位置0
       }
       else
       {
          USART1->DR = 0x0100 | DMX_buf[pDMX_buf];   //第九位置1
       }
       pDMX_buf++;
    }
  }
}

以上函數相比大家都可以看懂,接下來就是在main函數中進行循環數據的發送了,比如每200ms發送一次,由於發送快,偶爾的錯誤也不是很明顯。


2,、接收端

      接收端得工作就是接收的信息進行解碼(廢話),關鍵是對RB8的處理,接收用到了中斷接收,所以需要使能接收中斷。

void USART1_Configuration(void)
{      
  USART_InitTypeDef USART_InitStructure;
 
  USART_InitStructure.USART_BaudRate = 250000;
  USART_InitStructure.USART_WordLength = USART_WordLength_9b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* Configure USART1 */
  USART_Init(USART1, &USART_InitStructure);  
  /* Enable USART1 Receive and Transmit interrupts */
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中斷
  //USART_ITConfig(USART1, USART_IT_TC, ENABLE);
  /* Enable the USART1 */
  USART_Cmd(USART1, ENABLE);
}


void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
#ifdef  VECT_TAB_RAM
  /* Set the Vector Table base location at 0x20000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
    //設置優先級分組:先占優先級和從優先級 ,先占優先級0位,從優先級4位
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    
  /* Enable the USART1 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void USART1_IRQHandler(void)
{
  uint16_t UDR; 
  static uint16_t RXB8; 
  static uint16_t pDMX_buf = 0; //數據指針
  static uint8_t fDMX_buf_right = 0;
        
  //接收數據
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//USART_FLAG_RXNE
  {
    //USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);
    UDR = USART_ReceiveData(USART1); 
    RXB8 = (UDR & 0x0100); 
    
    if (RXB8 == 0) //復位信號
    {
     
      if (!UDR)
      {
         fDMX_buf_right = 1;//接收數據正確
         pDMX_buf = 1; //直接接收第一個數據  不保存第0個數據。
      }
    }
    else //rb8 =1  pDMX_buf=1 調光數據
    {
      if (1 == fDMX_buf_right)
      {
        DMX_buf[pDMX_buf++] = (u8)UDR;
        //接收到512個數據
        if (pDMX_buf > 512)
        {
          fDMX_buf_right = 0;
          tim_update = SET; //更新調光數據
        }
      }
    }
    
  }

}
————————————————
版權聲明:本文為CSDN博主「愛飛的小兵」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/cunlingwang/java/article/details/6712187


免責聲明!

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



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