STM32通过HAL库实现DMX512控制灯

DMX512协议是什么

关于DMX512协议的解释下面这篇文章写的十分详尽:
链接:作者:夏沫の浅雨

实现DMX512协议

通过串口模拟

通过上文我们可以得知,数据帧需要1位低电平+8位数据位+2位高电平,这种格式与串口通信协议的格式可以说是几乎一模一样,因为平日基本上都是使用串口8N1格式。因此,若是不考虑接收基于DMX512协议的数据,也就是本文这种情况,完全可以使用8位数据位+2位停止位的串口通信方式模拟DMX512协议。

串口配置(通过cubmx):

Alt
为实现发送一位数据用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位数据位无校验时用于存储待发送数据的。至此就能通过这个函数发送数据控制灯了。

一些问题

为什么不用寄存器方式发

一开始网上能找到的有限的教程都是寄存器方式发送,按照一般逻辑这种方式应该也是最快的,所以我也是照着写了一次拿逻辑分析仪看了看:
Alt
代码如下:

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协议发送同样的数据通过逻辑分析仪获取效果:
Alt
相信区别是很明显的,虽然实际使用起来没什么区别,但是就是看着别扭,至于为什么多一个位高电平我也不清楚,若是有大佬能解释还请告知,不胜感激!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值