DT7遥控DBUS协议解析

文章目录

    • 运行环境:
    • 1.1 DBUS协议解析
      • 1)DT7遥控
      • 2)配置串口引脚
      • 3)配置串口接收DMA
    • 2.1例程代码移植
      • 1)例程移动到 Inc 和 Src
      • 2)makefile添加.c文件
    • 3.1核心代码解释
    • 4.1代码修改
      • 1)bsp_rc.c 和 remote_control.c
      • 2)调用代码
    • 5.1调试
      • 1)硬件接线
      • 2)串口工具监视拨杆数据

运行环境:

ubuntu18.04.melodic
宏基暗影骑士笔记本
stm32f427IIH6
stlink
9-24v可调电源
usb转串口
杜邦线转4pin
DBUS遥控
接收机

1.1 DBUS协议解析

1)DT7遥控

DT7遥控示意图:每个通道由11位数据控制
在这里插入图片描述

2)配置串口引脚

详情见:USART串口发送

UASRT6
发送TX_PG14
接收RX_PG9
在这里插入图片描述
在这里插入图片描述

3)配置串口接收DMA

串口接收DMA:接收由遥控发送过来的数据

DBUS 的传输速率为 100k bit/s,数据长度为 8 位,奇偶校验位为偶校验,结束位 1 位。
在这里插入图片描述

串口6接收DMA
环形储存器

在这里插入图片描述

打开串口全局中断

在这里插入图片描述

2.1例程代码移植

1)例程移动到 Inc 和 Src

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2)makefile添加.c文件

在这里插入图片描述

3.1核心代码解释

在这里插入图片描述

每个通道由11位数据控制

在这里插入图片描述

rc_ctrl->rc.ch[0] = (sbus_buf[0] | (sbus_buf[1] << 8)) & 0x07ff;
sbus_buf[1] << 8是将pData[1]左移8位到高8位,然后和sbus_buf[0]的pData[0]进行与运算, 拼接成左下图的16位
然后和0x07ff(0x07ff二进制是1111111111)进行或运算,取出后11位。

rc_ctrl->rc.ch[1] = ((sbus_buf[1] >> 3) | (sbus_buf[2] << 5)) & 0x07ff
同理,sbus_buf[1] >> 3是将pData[1]右移3位,舍弃3位,保留低5位。
sbus_buf[2] << 5是将pData[2]左移5位,然后拼接如右下图,取后11位。

在这里插入图片描述

4.1代码修改

1)bsp_rc.c 和 remote_control.c

bsp_rc.c 文件是串口3的初始化, 我们用的是串口6,需要修改代码。
remote_control.c是对数据进行处理和解析,我们用的是串口6,需要修改代码。

void RC_init(uint8_t *rx1_buf, uint8_t *rx2_buf, uint16_t dma_buf_num)
{
    //enable the DMA transfer for the receiver request
    SET_BIT(huart6.Instance->CR3, USART_CR3_DMAR);

    //enalbe idle interrupt
    __HAL_UART_ENABLE_IT(&huart6, UART_IT_IDLE);

    //disable DMA
    __HAL_DMA_DISABLE(&hdma_usart6_rx);
    while(hdma_usart6_rx.Instance->CR & DMA_SxCR_EN)
    {
        __HAL_DMA_DISABLE(&hdma_usart6_rx);
    }

    hdma_usart6_rx.Instance->PAR = (uint32_t) & (USART6->DR);
  
    //memory buffer 1
    hdma_usart6_rx.Instance->M0AR = (uint32_t)(rx1_buf);
  
    //memory buffer 2
    hdma_usart6_rx.Instance->M1AR = (uint32_t)(rx2_buf);
  
    //data length
    hdma_usart6_rx.Instance->NDTR = dma_buf_num;
  
    //enable double memory buffer
    SET_BIT(hdma_usart6_rx.Instance->CR, DMA_SxCR_DBM);

    //enable DMA
    __HAL_DMA_ENABLE(&hdma_usart6_rx);

}
extern UART_HandleTypeDef huart6;
extern DMA_HandleTypeDef hdma_USART6_rx;

/**
  * @brief          remote control protocol resolution
  * @param[in]      sbus_buf: raw data point
  * @param[out]     rc_ctrl: remote control data struct point
  * @retval         none
  */
/**
  * @brief          ң����Э�����
  * @param[in]      sbus_buf: ԭ������ָ��
  * @param[out]     rc_ctrl: ң��������ָ
  * @retval         none
  */
static void sbus_to_rc(volatile const uint8_t *sbus_buf, RC_ctrl_t *rc_ctrl);

//remote control data 
//ң�������Ʊ���
RC_ctrl_t rc_ctrl;

//receive data, 18 bytes one frame, but set 36 bytes 
//����ԭʼ���ݣ�Ϊ18���ֽڣ�����36���ֽڳ��ȣ���ֹDMA����Խ��
static uint8_t sbus_rx_buf[2][SBUS_RX_BUF_NUM];

/**
  * @brief          remote control init
  * @param[in]      none
  * @retval         none
  */
/**
  * @brief          ң������ʼ��
  * @param[in]      none
  * @retval         none
  */
void remote_control_init(void)
{
    RC_init(sbus_rx_buf[0], sbus_rx_buf[1], SBUS_RX_BUF_NUM);
}
/**
  * @brief          get remote control data point
  * @param[in]      none
  * @retval         remote control data point
  */
/**
  * @brief          ��ȡң��������ָ��
  * @param[in]      none
  * @retval         ң��������ָ��
  */
const RC_ctrl_t *get_remote_control_point(void)
{
    return &rc_ctrl;
}


//�����ж�
void USART6_IRQHandler(void)
{
    if(huart6.Instance->SR & UART_FLAG_RXNE)//���յ�����
    {
        __HAL_UART_CLEAR_PEFLAG(&huart6);
    }
    else if(USART6->SR & UART_FLAG_IDLE)
    {
        static uint16_t this_time_rx_len = 0;

        __HAL_UART_CLEAR_PEFLAG(&huart6);

        if ((hdma_USART6_rx.Instance->CR & DMA_SxCR_CT) == RESET)
        {
            /* Current memory buffer used is Memory 0 */
    
            //disable DMA
            //ʧЧDMA
            __HAL_DMA_DISABLE(&hdma_USART6_rx);

            //get receive data length, length = set_data_length - remain_length
            //��ȡ�������ݳ���,���� = �趨���� - ʣ�೤��
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_USART6_rx.Instance->NDTR;

            //reset set_data_lenght
            //�����趨���ݳ���
            hdma_USART6_rx.Instance->NDTR = SBUS_RX_BUF_NUM;

            //set memory buffer 1
            //�趨������1
            hdma_USART6_rx.Instance->CR |= DMA_SxCR_CT;
            
            //enable DMA
            //ʹ��DMA
            __HAL_DMA_ENABLE(&hdma_USART6_rx);

            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                sbus_to_rc(sbus_rx_buf[0], &rc_ctrl);
            }
        }
        else
        {
            /* Current memory buffer used is Memory 1 */
            //disable DMA
            //ʧЧDMA
            __HAL_DMA_DISABLE(&hdma_USART6_rx);

            //get receive data length, length = set_data_length - remain_length
            //��ȡ�������ݳ���,���� = �趨���� - ʣ�೤��
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_USART6_rx.Instance->NDTR;

            //reset set_data_lenght
            //�����趨���ݳ���
            hdma_USART6_rx.Instance->NDTR = SBUS_RX_BUF_NUM;

            //set memory buffer 0
            //�趨������0
            DMA1_Stream1->CR &= ~(DMA_SxCR_CT);
            
            //enable DMA
            //ʹ��DMA
            __HAL_DMA_ENABLE(&hdma_USART6_rx);

            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                //����ң��������
                sbus_to_rc(sbus_rx_buf[1], &rc_ctrl);
            }
        }
    }
}


/**
  * @brief          remote control protocol resolution
  * @param[in]      sbus_buf: raw data point
  * @param[out]     rc_ctrl: remote control data struct point
  * @retval         none
  */
/**
  * @brief          ң����Э�����
  * @param[in]      sbus_buf: ԭ������ָ��
  * @param[out]     rc_ctrl: ң��������ָ
  * @retval         none
  */
static void sbus_to_rc(volatile const uint8_t *sbus_buf, RC_ctrl_t *rc_ctrl)
{
    if (sbus_buf == NULL || rc_ctrl == NULL)
    {
        return;
    }

    rc_ctrl->rc.ch[0] = (sbus_buf[0] | (sbus_buf[1] << 8)) & 0x07ff;        //!< Channel 0
    rc_ctrl->rc.ch[1] = ((sbus_buf[1] >> 3) | (sbus_buf[2] << 5)) & 0x07ff; //!< Channel 1
    rc_ctrl->rc.ch[2] = ((sbus_buf[2] >> 6) | (sbus_buf[3] << 2) |          //!< Channel 2
                         (sbus_buf[4] << 10)) &0x07ff;
    rc_ctrl->rc.ch[3] = ((sbus_buf[4] >> 1) | (sbus_buf[5] << 7)) & 0x07ff; //!< Channel 3
    rc_ctrl->rc.s[0] = ((sbus_buf[5] >> 4) & 0x0003);                  //!< Switch left
    rc_ctrl->rc.s[1] = ((sbus_buf[5] >> 4) & 0x000C) >> 2;                       //!< Switch right
    rc_ctrl->mouse.x = sbus_buf[6] | (sbus_buf[7] << 8);                    //!< Mouse X axis
    rc_ctrl->mouse.y = sbus_buf[8] | (sbus_buf[9] << 8);                    //!< Mouse Y axis
    rc_ctrl->mouse.z = sbus_buf[10] | (sbus_buf[11] << 8);                  //!< Mouse Z axis
    rc_ctrl->mouse.press_l = sbus_buf[12];                                  //!< Mouse Left Is Press ?
    rc_ctrl->mouse.press_r = sbus_buf[13];                                  //!< Mouse Right Is Press ?
    rc_ctrl->key.v = sbus_buf[14] | (sbus_buf[15] << 8);                    //!< KeyBoard value
    rc_ctrl->rc.ch[4] = sbus_buf[16] | (sbus_buf[17] << 8);                 //NULL

    rc_ctrl->rc.ch[0] -= RC_CH_VALUE_OFFSET;
    rc_ctrl->rc.ch[1] -= RC_CH_VALUE_OFFSET;
    rc_ctrl->rc.ch[2] -= RC_CH_VALUE_OFFSET;
    rc_ctrl->rc.ch[3] -= RC_CH_VALUE_OFFSET;
    rc_ctrl->rc.ch[4] -= RC_CH_VALUE_OFFSET;
}

2)调用代码

main.c中包含头文件

#include "bsp_rc.h"
#include "remote_control.h"

定义一个变量储存区(结构体指针)

const RC_ctrl_t *local_rc_ctrl;

初始化串口
初始化储存区

remote_control_init();
local_rc_ctrl = get_remote_control_point();

添加串口输出代码到while循环中

       usart_printf(
"**********\r\n\
ch0:%d\r\n\
ch1:%d\r\n\
ch2:%d\r\n\
ch3:%d\r\n\
ch4:%d\r\n\
s1:%d\r\n\
s2:%d\r\n\
mouse_x:%d\r\n\
mouse_y:%d\r\n\
press_l:%d\r\n\
press_r:%d\r\n\
key:%d\r\n\
**********\r\n",
            local_rc_ctrl->rc.ch[0], local_rc_ctrl->rc.ch[1], local_rc_ctrl->rc.ch[2], local_rc_ctrl->rc.ch[3], local_rc_ctrl->rc.ch[4],
            local_rc_ctrl->rc.s[0], local_rc_ctrl->rc.s[1],
            local_rc_ctrl->mouse.x, local_rc_ctrl->mouse.y,local_rc_ctrl->mouse.z, local_rc_ctrl->mouse.press_l, local_rc_ctrl->mouse.press_r,
            local_rc_ctrl->key.v);

        HAL_Delay(200);

在这里插入图片描述

添加void usart_printf()函数定义

void usart_printf(const char *fmt,...)
{
    static uint8_t tx_buf[256] = {0};
    static va_list ap;
    static uint16_t len;
    va_start(ap, fmt);

    //return length of string 
    //�����ַ�������
    len = vsprintf((char *)tx_buf, fmt, ap);

    va_end(ap);

    // usart1_tx_dma_enable(tx_buf, len);

}

修改bsp_rc.h和remote_control.h

在这里插入图片描述
在这里插入图片描述

注释stm32f4xx_it.c中重复定义的串口6中断服务函数(remote_control.c中已经定义过了)

在这里插入图片描述

5.1调试

1)硬件接线

接收机插A板的dbus接口
对频: 按住接收机的孔,然后打开遥控器

2)串口工具监视拨杆数据

sudo cutecom
make
F5调试运行


⭐⭐⭐ 嘟嘟崽 ⭐⭐⭐
⭐⭐⭐ 祝你成功 ⭐⭐⭐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/18184.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】哈希

一、unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 l o g 2 N log_2 N log2​N&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。 …

Linux学习之Shell(一)

Shell概述 1&#xff09;Linux提供的Shell解析器有 [xiaominghadoop101 ~]$ cat /etc/shells /bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bin/bash /usr/sbin/nologin /bin/tcsh /bin/csh2&#xff09;bash和sh的关系 [xiaominghadoop101 bin]$ ll | grep bash -rwxr…

HTML <area> 标签

实例 带有可点击区域的图像映射: <img src="planets.jpg" border="0" usemap="#planetmap" alt="Planets" /><map name="planetmap" id="planetmap"><area shape="circle" coords=&q…

不用花一分钱!!!获得一个自己的网页版chatGPT

不用花一分钱&#xff01;&#xff01;&#xff01;获得一个自己的网页版chatGPT 当然还是需要一个chatGPT账号的&#xff0c;不会注册的同学可以看一下这篇文章 chatGPT到底要怎么注册 那就先让我们看一下效果吧 chatgpt-web介绍 github项目地址 https://github.com/Chanzha…

Formik使用详解

Formik使用详解 1 引言 在现代Web应用程序中&#xff0c;表单是一种不可避免的输入机制&#xff0c;但是处理表单的过程可能会变得非常复杂。Formik是一个React表单库&#xff0c;它的目标是简化表单处理的过程。本文将介绍Formik的主要功能和用途&#xff0c;以及如何使用它来…

OSI七层网络模型+TCP/IP四层模型

OSI七层模型&#xff1a; 物理层&#xff1a;主要定义物理设备标准&#xff0c;如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流&#xff08;就是由1、0转化为电流强弱来进行传输&#xff0c;到达目的地后再转化为1、0&#xff0c;也就…

2023年淮阴工学院五年一贯制专转本财务管理基础考试大纲

2023年淮阴工学院五年一贯制专转本财务管理基础考试大纲 一、考核对象 本课程的考核对象为五年一贯制高职专转本财务管理专业入学考试普通在校生考生。 二、考核方式 本课程考核采用闭卷笔试的方式。 三、命题依据及原则 1、命题依据 本课程考核命题教材为靳磊编著&…

1_5 pytorch操作

一、torch 算子 1、torch.nn.functional.affine_grid(theta, size) 给定一组仿射矩阵(theta)&#xff0c;生成一个2d的采样位置(流场)&#xff0c;通常与 grid_sample() 结合使用,用于空间仿射变换网络&#xff0c;用于对2D或3D数据进行仿射变换。 输入&#xff1a;theta(Te…

AIGPT中文版(无需魔法,直接使用)不愧是生活工作的好帮手。

AIGPT AIGPT是一款非常强大的人工智能技术的语言处理工具软件&#xff0c;它具有 AI绘画 功能、AI写作、写论文、写代码、哲学探讨、创作等功能&#xff0c;可以说是生活和工作中的好帮手。 我们都知道使用ChatGPT是需要账号以及使用魔法的&#xff0c;其中的每一项对我们初学…

使用JPA自动生成代码(轻松上手看了就会版)

目录 背景&#xff1a;方案概念&#xff1a;JPA 的主要作用 jpa简单使用&#xff08;Springboot项目&#xff09;jpa进阶使用总结 背景&#xff1a; 项目需要自动生成sql代码&#xff0c;不需要写sql语句&#xff0c;能够自动进行查询&#xff0c;我想到了JPA。 方案 概念&a…

Linux驱动编程(分层分离编程思想)

1、面向对象 ⚫ 字符设备驱动程序抽象出一个 file_operations 结构体&#xff1b; ⚫ 我们写的程序针对硬件部分抽象出 led_operations 结构体。 2、分层 上层实现硬件无关的操作&#xff0c;比如注册字符设备驱动&#xff1a;leddrv.c 下层实现硬件相关的操作&#xff0c;比如…

Makefile零基础教学(一)初识makefile

从这篇文章开始就开始进入 Makefile 的零基础教程&#xff0c;相信只要看了本教程的都可以对 Makefile 有一个清晰的理解和正确的运用。那么现在就开始我们的 Makefile 学习之路。 文章目录 一、什么是 Makefile&#xff0c;优点&#xff1f;二、什么是 make, 为什么使用make?…

Linux学习记录——이십이 进程信号(1)

文章目录 1、了解信号2、了解信号处理3、信号产生1、键盘按键产生2、系统接口产生3、软件条件产生4、硬件异常 4、Core和Term的区别5、信号保存1、在系统中的表现形式2、信号集操作函数1、sigprocmask2、sigpending 6、重谈地址空间7、信号处理与捕捉sigaction 1、了解信号 信…

MySQL索引、事务与存储引擎

数据库索引 是一个排序的列表&#xff0c;存储着索引值和这个值对应的物理地址&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于C语言的链表通过指针指向数据记录的内存地址&#xff09;无需对整个表进行扫描&#xff0c;而是先通…

IS210AEBIH3BEC隔离器用于变压器等高压设备

IS210AEBIH3BEC隔离器用于变压器等高压设备 隔离器可以根据在电力系统中的位置进行分类 母线侧隔离器——隔离器直接连接到主母线线路侧隔离器 - 隔离器将放置在任何馈线的线路侧Transfer bus side isolator – isolator will be directly connected with the transfer bus S…

【LeetCode】1143. 最长公共子序列

1.问题 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff0…

怎么让chatGTP写论文-chatGTP写论文工具

chatGTP如何写论文 ChatGPT是一个使用深度学习技术训练的自然语言处理模型&#xff0c;可以用于生成自然语言文本&#xff0c;例如对话、摘要、文章等。作为一个人工智能技术&#xff0c;ChatGPT可以帮助你处理一些文字内容&#xff0c;但并不能代替人类的创造性思考和判断。以…

手机录屏怎么操作?有哪些好用的方法

在现代科技的时代&#xff0c;手机录屏已经成为了常见的操作。这项技术允许我们在手机上录制视频并分享给他人。但是&#xff0c;很多人可能并不知道如何进行手机录屏。下面我们将介绍手机录屏的操作方法和一些值得推荐的工具。 手机录屏操作方法 对于iOS用户&#xff0c;可以…

Ribbon负载均衡

目录 1.Ribbon负载均衡 1.1.负载均衡原理 1.2.源码跟踪 1&#xff09;LoadBalancerIntercepor 2&#xff09;LoadBalancerClient 3&#xff09;负载均衡策略IRule 4&#xff09;总结 1.3.负载均衡策略 1.3.1.负载均衡策略 1.3.2.自定义负载均衡策略 1.4.饥饿加载 1.R…

InnoDB 与MyISAM 的区别

MyISAM和InnoDB都是Mysql里面的两个存储引擎。 在Mysql里面&#xff0c;存储引擎是可以自己扩展的&#xff0c;它的本质其实是定义数据存储的方式以及数据读取的实现逻辑。 不同存储引擎本身的特性&#xff0c;使得我们可以针对性的选择合适的引擎来实现不同的业务场景。从而获…