DMX512协议是什么
关于DMX512协议的解释下面这篇文章写的十分详尽:
链接:作者:夏沫の浅雨
实现DMX512协议
通过串口模拟
通过上文我们可以得知,数据帧需要1位低电平+8位数据位+2位高电平,这种格式与串口通信协议的格式可以说是几乎一模一样,因为平日基本上都是使用串口8N1格式。因此,若是不考虑接收基于DMX512协议的数据,也就是本文这种情况,完全可以使用8位数据位+2位停止位的串口通信方式模拟DMX512协议。
串口配置(通过cubmx):
为实现发送一位数据用4us,配置波特率250000bit/s,8位数据位,2位停止位,无校验。
发送函数:
由于break段与MAB段很长,串口不能模拟,所以得先把串口所用引脚复用给变成输出,去模拟:
void UartPortModeChang(uint8_t mode){
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(mode){
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}else{
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
接下来就是发送数据了,us延时很多,随便使用一种方法都可以,本文使用定时器6产生:
void DMX512_Send(uint8_t buff[],uint16_t num){//num为数据长度,因为有0X00所以不能用strlen计算长度
uint8_t delay_num = 80;
uint8_t send_buff[50] = {0};
for(uint8_t i = 0;i <= num;++i){
if(i == 0){
send_buff[0] = 0X00;
}else{
send_buff[i] = buff[i-1];
}
}
huart2.TxXferCount = num;
UartPortModeChang(1);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
delay_us(88);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET);
while(delay_num--);
UartPortModeChang(0);
HAL_UART_Transmit(&huart2,send_buff,num+1,0xff);//此处为可以发0X00进行了一点修改
}
关于HAL串口发送函数的修改如下:
while (huart->TxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
// if (pdata8bits == NULL)
// {
// huart->Instance->DR = (uint16_t)(*pdata16bits & 0x01FFU);
// pdata16bits++;
// }
// else
// {
huart->Instance->DR = (uint8_t)(*pdata8bits & 0xFFU);
pdata8bits++;
// }
huart->TxXferCount--;
}
注释掉这个判断是因为NULL等于0X00,故而会转而发送pdata16bits,这个变量是在配置串口为9位数据位无校验时用于存储待发送数据的。至此就能通过这个函数发送数据控制灯了。
一些问题
为什么不用寄存器方式发
一开始网上能找到的有限的教程都是寄存器方式发送,按照一般逻辑这种方式应该也是最快的,所以我也是照着写了一次拿逻辑分析仪看了看:
代码如下:文章来源:https://www.toymoban.com/news/detail-849087.html
void DMX512_Send(uint8_t buff[],uint16_t num){
uint8_t delay_num = 80;
uint16_t num_div = num;
huart2.TxXferCount = num;
huart2.gState = HAL_UART_STATE_BUSY_TX;
UartPortModeChang(1);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
delay_us(88);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET);
while(delay_num--);
UartPortModeChang(0);
huart2.Instance->DR = 0X00;
while((huart2.Instance->SR & 0X40) == 0);
huart2.Instance->DR = buff[0];
while((huart2.Instance->SR & 0X40) == 0);
while (huart2.TxXferCount > 0U){
huart2.Instance->DR = *(++buff);
while((huart2.Instance->SR & 0X40) == 0);
huart2.TxXferCount--;
}
huart2.gState = HAL_UART_STATE_READY;
}
再看通过本文写的方法模拟的DMX512协议发送同样的数据通过逻辑分析仪获取效果:
相信区别是很明显的,虽然实际使用起来没什么区别,但是就是看着别扭,至于为什么多一个位高电平我也不清楚,若是有大佬能解释还请告知,不胜感激!文章来源地址https://www.toymoban.com/news/detail-849087.html
到了这里,关于STM32通过HAL库实现DMX512控制灯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!