基於STM32的DMX512開發

首先基本瞭解一下DMX512的基本協議

一、       DMX512協議

       DMX 是Digital MultipleX 的縮寫,意爲多路數字傳輸。DMX512控制協議是美國舞臺燈光協會(usITT)於1990年發佈的燈光控制器與燈具設備進行數據傳輸的工業標準,全稱是USITTDMX512(1990),包括電氣特性、數據協議、數據格式等方面的內容。

      每一個DMX 控制字節叫做一個指令幀,稱作一個控制通道,可以控制燈光設備的一個或幾個功能。一個DMX 指令幀由1個開始位、8個數據位和2個結束位共11位構成,採用單向異步串行傳輸,如圖1所示。

圖1 DMX512 定時程序的幀結構(上圖)和信息包結構(下圖)

 

       圖1 中虛線內控制指令中的S 爲開始位,寬度爲一個比特,是受控燈具準備接收並解碼控制數據的開始標誌;E爲結束位,寬度爲兩個比特,表示一個指令幀的結束;D0~ D7爲8 位控制數據,其電平組合從0000~一l1111111 共有256個狀態(對應十進制數的0~255),控制燈光的亮度時,可產生256個亮度等級,0000~ (0)對應燈光最暗,l1111111(255)對應燈光最亮。DMX512指令的位寬(每比特寬度)是4 us,每幀寬度爲44 us,傳輸速率爲250 kbps。

       一個完整的DMX512信息包(Packet)由一個MTBP位、一個Break 位、一個MAB位、一個SC 和512個數據幀構成。MTBP(Mark TimeBetween Packets)標誌着一個完整的信息包發送完畢,是下一個信息包即將開始的“空閒位”,高電平有效。Break爲中斷位,對應一個信息包結束後的程序復位階段,寬度不少於兩個幀(22 比特)。程序復位結束後應發送控制數據,但由於每一個數據幀的第一位(即開始位)爲低電平,所以必須用一個高電平脈衝間隔前後兩個低電平脈衝,這個起間隔、分離作用的高電平脈衝即MAB(Mark After Break),此脈衝一到,意味着“新一輪”的控制又開始了。SC(Start Code)意爲開始代碼幀(圖1中的第0幀),和此後到來的數據幀一樣,也是由11 位構成,除兩個高電平的結束位之外,其他9位全部是低電平,通常將其叫做第0 幀或第0通道(Ch~nel No 0),可理解爲一個不存在的通道(Non一~istent Channe1)。

 

表1 DMX512 信息包定時表

 

       表1 是DMX512 信息包的定時表,表中NS意爲Nm Spec~ed,寬度沒有嚴格限制,由程序設計者自行決定,比如MTBP的寬度可以介於0~1秒之間。

       調光控制檯每發送一個信息包,可以對全部512個受控通道形成一次全面的控制。發送一個信息包的時間大約是23 ms,每秒鐘將對所有512個受控通道完成44 次控制,即受控光路的刷新頻率44 Hz,如果實際受控通道少於512個,那麼刷新頻率將相應提高。

 

 
根據標準的512協議,其物理連接與傳統上的RS485是完全一致的,並沒有什麼差別,差別只是在協議上的不同,工業上應用的主要是modbus協議,而這裏是用512通信協議。

 

 DMX512數據協議是美國舞臺燈光協會(USITT)於1990年發佈的一種燈光控制器與燈具設備進行數據傳輸的標準。它包括電氣特性,數據協議,數據格式等方面的內容。

512協議規定使用的波特率是250Kbps,而stm32可以支持上Mbps的波特率,所以說這不是什麼大問題。

 該協議發送的數據幀一共11位,

1位開始位,

8位數據,

2個停止位,無校驗位。

根據波特率可以知道,位時間是4us,11位數據供需要44us的時間。當然對於標準的512協議是需要break和mark after break 

幀的,break是一個92us的低電平,而mark after break是一個12us的高電平,

512協議必須有break和mark,但是在我們通常的非標準收發中,檢測break和mark相對比較困難,如果非要做,耗費的資源也比較多,比如定時器計時,中斷等等。如果不是做標準控制器的,完全可以另闢蹊徑。

每一串數據的開始都要有一個起始碼,也稱復位碼,其數據爲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; //
 
更新調光數據
   }
 }
}


————————————————
原文鏈接:https://blog.csdn.net/qq_36958104/article/details/97010699

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章