DMX512调光协议和DALI一样属于数字调光协议,一个完整的DMX512数据包格式:1break+1mab+1startcode+512个调光数据。
DMX512发送是基于485串口的基础上实现的特殊的数据协议。
使用RTT需要把串口打开并且定义好相应的定义,这里不再赘述;因RTT的部分外设初始化不完善,本次使用的HAL库进行初始化部分。
实现步骤:
1.初始化GPIO口,使能485串口的3.3v以及使能为发送模式,这个根据实际需求进行初始化
/*
* 初始化dmx512所要用到的pin,打开485的3.3v以及使能发送模式 PC8 3.3v, PC9 模式控制
* */
int dmx512_pin_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
/*Configure GPIO pins : PC7 PC8 PC9 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
return RT_EOK;
}
2.初始化要用到的485串口,数据位9,波特率250000
/*
* 初始化dmx512所要用到的uart4
* */
int dmx512_uart_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_UART4_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
huart4.Instance = UART4;
huart4.Init.BaudRate = 250000;
huart4.Init.WordLength = UART_WORDLENGTH_9B;
huart4.Init.StopBits = UART_STOPBITS_1;
huart4.Init.Parity = UART_PARITY_NONE;
huart4.Init.Mode = UART_MODE_TX_RX;
huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart4.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart4);
return RT_EOK;
}
3.写一个切换串口引脚功能的函数,用于形成break和mab信号
/*
* 切换dmx512发送pin脚的模式
* */
int dmx512_pin_mode(int mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
if(mode) //mode=1,当串口发送用,在dmx512发送中主要用于发送数据帧
{
GPIO_InitStructure.Pin = GPIO_PIN_10;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; //复用推挽输出
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
}
else if(mode == 0)//mode=0,当普通io用,在dmx512发送中主要用来形成break和mab信号
{
GPIO_InitStructure.Pin = GPIO_PIN_10;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
}
return RT_EOK;
}
4.写DMX512的数据发送函数,定义全局变量 int pDMX_buf、char dmx_buf[513]
/*
* dmx512发送数据函数
* */
int dmx512_send_frame(void)
{
dmx512_pin_mode(0);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, 0);
rt_hw_us_delay(100);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, 1);
rt_hw_us_delay(10);
dmx512_pin_mode(1);
for(pDMX_buf = 0; pDMX_buf <= 512; pDMX_buf++) //0:startcode 1-512:调光数据
{
if(pDMX_buf == 0)
{
UART4->DR = 0x00 | 0x100;//第一帧startcode
while((UART4->SR & 0X40) == 0); //确保数据发送完成
}
else
{
UART4->DR = 0x100 | dmx_buf[pDMX_buf];
while((UART4->SR & 0X40) == 0); //确保数据发送完成
}
}
return RT_EOK;
}
5.写一个DMX512的初始化函数,可以把前面的初始化的所有函数放进去并开启线程用于发送DMX512数据
*
* 包含了dmx512所用到的所有初始化,并开启线程发送dmx512数据
* */
int dmx512_init(void)
{
int ret = RT_EOK;
dmx512_pin_init();
dmx512_uart_init();
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("dmx512", dmx512_send_thread, RT_NULL, 1024, 25, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
ret = RT_ERROR;
}
return ret;
}
6.实现线程函数,每隔400ms发送一个DMX512数据包
/*
* dmx512数据发送线程,dmx512数据需要持续发送而且必须在1S内发送下一条
* */
static void dmx512_send_thread(void *parameter)
{
while(1)
{
dmx512_send_frame();
rt_thread_mdelay(400);
}
}
7.将dmx512_init放到MAIN中执行即可。
版权声明:本文为CSDN博主「小火汁-,-」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43962818/article/details/122842364
暂无评论