嵌入式平台DMXRDM协议开源项目说明
目录
前言
一、项目简介
二、快速浏览
1、总体结构
2、头文件说明
3、源文件说明
三、项目移植
总结
前言
经过了近一年左右的学习,博主完成了一套相对成熟的DMX协议+RDM协议的驱动模块,现在将源码开放给大家学习,共同进步。
github仓库地址:https://github.com/murongbaibai/dmx-rdm.git
拉取命令:git clone https://github.com/murongbaibai/dmx-rdm.git
一、项目简介
本项目实现了标准DMX协议的收发,RDM协议的基础九大命令(搜寻设备、哑音设备、解除哑音设备、获取设备支持命令列表、获取设备命令类型定义、获取设备信息、获取设备软件版本、获取和设置设备DMX地址、获取和设置设备状态),以及扩展的一个命令(获取和设置设备模式)。本项目能够应用到舞台的各类设备的开发之中,也可作为设备之间的通信协议使用。
本项目适用于小型的嵌入式平台,整体体积较小,对主频的要求也不算很高(单路接收发送)。下面是项目移植要求:
RAM(做输入设备,如灯板、摇头灯、帕灯) | >= 4K |
RAM(做输出设备,如控台、RDM拨码器) | >= 16K |
FLASH | >= 8K |
主频 | >= 24MHZ |
UART LIN模式,检测break中断 | 必须要有 |
二、快速浏览
1、总体结构
本项目的源码结构十分简单,只有两个文件夹,inc存放头文件,src存放源文件。另外两个文件无关紧要。
2、头文件说明
dmx.h:DMX协议相关接口定义。
dmx_rdm.h:相当于项目内部的mian.h,整合了其他头文件。
dmx_rdm_config.h:DMX协议和RDM协议的相关配置,设备通道数,模式数等。
rdm_input.h、rdm_output.h:RDM协议相关接口、结构体定义。
rs_interfaces.h:串口收发接口声明、DMX-RDM链路结构体定义。
uart_init_template.h:用户接口初始化模块头文件、由用户完成
3、源文件说明
rdm_input.c、rdm_output.c:RDM协议相关接口实现。
rs_interfaces.c:串口接收、发送、解包相关接口实现。
uart_init_template.c:用户接口初始化模块示例,需要按照此示例来初始化串口。
三、项目移植
首先下载代码到本地,将dmx-rdm模块复制到你们的工程文件中,这里以keil为例。
首先复制模块到工程路径中,然后打开keil工程
在keil工程中新建一个组,然后将项目源码中的src目录下的所有文件添加到新建的组“dmx-rdm”中。
接着在include path中添加源码头文件的路径,选择你保存的项目源码的位置,选择项目中的inc文件夹。
如果你的工程中使用了HAl库,可以将这个定义添加到宏定义中 USE_HAL_DRIVER (多个宏定义用英文逗号隔开),然后在 dmx_rdm.h文件中修改HAL库头文件为你的HAL库头文件。
项目添加到此结束,下面开始使用项目,首先在你的外设初始化代码中加入这一条函数。
DMX_Init();
还需要实现任务处理函数,可以将任务处理函数放到系统心跳时钟中断或者主循环中,以系统心跳时钟中断为例,将DMX_TaskHandle添加入其中,其中1表示中断频率,如果是每1ms中断就传入1,每10ms中断就传入10。
void SysTick_Handler(void)
{HAL_IncTick();DMX_TaskHandle(1);
}
在主循环中实现可能会因为有其他的任务处理导致延时不精确。
while(1)
{//...DMX_TaskHandle(1);HAL_Delay(1);
}
然后配置设备类型,打开dmx_rdm_config.h文件,根据你开发的产品类型来修改定义,例如选择设备类型为输入设备。
#define DEVICE_TYPE_SWITCH DEVICE_TYPE_INPUT //选择设备类型
配置完成后就需要进行最困难的一步了,需要根据你的硬件平台完成串口初始化代码,以及一个微秒级延时函数的实现。具体的初始化配置可以参考uart_init_template.c文件,下面给出串口配置的要求。
波特率 | 250000 |
停止位 | 2位 |
数据位 | 8位 |
校验位 | 无 |
DMA接收 | v1.0版本硬性需要,后续版本可能添加阻塞、中断接收 |
DMA发送 | v1.0版本硬性需要,后续版本可能添加阻塞、中断发送 |
break中断 | v1.0版本硬性需要,后续版本可能添加更兼容的检测方式 |
其他中断 | 参考uart_init_template.c开启 |
微秒级延时建议采用定时器的方式实现,参考uart_init_template.c。如果无法使用定时器实现,也可以将定时器初始化代码置空,然后在微秒级延时函数中改为CPU计算延时。具体实现需要根据你的主频来编写。
static void DMX_Tim_Delay_Nus(uint16_t nus)
{for(int i = 0; i < N*nus; i++);
}
初始化完成后需要根据对应的中断请求来调用对应的处理函数,实现参考如下。
void USART2_IRQHandler(void)
{//实现断开信号检测接口if(huart2.Instance->CR2 & USART_CR2_LBDIE){if(huart2.Instance->SR & USART_SR_LBD){//清除标志位__HAL_UART_CLEAR_FLAG(&huart2,USART_SR_LBD);DMX_UART_BreakHandle(dmx_line1);}}HAL_UART_IRQHandler(&huart2);
}
//实现发送完成接口
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART2)DMX_UART_TxCompleteHandle(dmx_line1);
}
//实现接收完成接口
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART2)DMX_UART_RxCompleteHandle(dmx_line1);
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{//实现错误重启接口if(huart->Instance == USART2)DMX_UART_ErrorRebootHandle(dmx_line1);
}
最后接收到对应的信号就会进行自动处理然后触发相应的回调函数,回调函数在uart_init_template.c中也有定义。
/******************************** 对用户开放的回调函数(在中断环境中回调、代码需要简短) ********************************/
//发送前回调函数,用于修改发送数组
void DMX_Send_Before_Callback(dmx_line_t *dmx_line)
{ }//RDM解包完成回调函数
void RDM_UnpackComplete_Callback(dmx_line_t *dmx_line)
{}
//DMX解包完成回调函数
void DMX_UnpackComplete_Callback(dmx_line_t *dmx_line)
{}
#ifdef USE_REFRESH_TIM
//断开信号时间到回调
void DMX_Refresh_Tim_CompleteHandle(dmx_line_t* dmx_line)
{}
#endif
总结
本代码首次开源,有不成熟的地方还请包涵,有关源码相关的问题可以在评论区发送,我有空就会查看。祝大家开发顺利。