DR16接收机硬件底层代码

   DR16接收机D_BUS与开发板通讯方式为单线串口通讯,**DR16只发送遥控器的信号,单片机进行接收,二者之间不能进行交互**,这里面说一下**DR16的发送为固定频率的实时发送**,因此在使用单片机串口进行接收的时候,为了节省单片机的算力,我们使用串口3且接收方式使用占用资源较少的**DMA**通道进行接收,**根据DR16的特性如果使用串口中断进行接收,占用单片机内部资源较多,而且这仅仅是一个遥控器的简单底层,无需占用过多的软件资源考虑,并且使用串口中断接收会增加程序编写的难度,影响实际使用中系统的反应速度**。
   但是RM给出的官方底层代码**9.remote_control_printf_pc**,但是不知是RM官方没进行优化,还是我的资料比较陈旧,这个代码不能正常使用,使用串口1的最简单的串口打印程序,使用上位机串口打印没法打印出来:      ![在这里插入图片描述](https://img-blog.csdnimg.cn/8bf7fbcf96994d25a2f8a3c2fe2cb3ea.png)
   以下为官方例程中的bsp_usart.c  :
   ![在这里插入图片描述](https://img-blog.csdnimg.cn/3be109c5faba4a898f86ee237165a79a.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDA4MDMwNA==,size_16,color_FFFFFF,t_70)
   以下是官方例程中的bsp_rc.c:

在这里插入图片描述
以下是官方例程中的remote_control.c:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上代码为RM给出的官方例程,但是经过个人测试这个程序不可用,目前还没找到具体原因在哪,希望专业人士可以提出指导。
事先声明RM底层和我个人底层均为使用CubeMX进行编写,在后期进行修改完成的。
下面为我个人编写的代码,经过测试可以正常使用,并且通过IIC通讯的OLED屏幕可以进行打印,这里说一下,RM给出的OLED的官方例程,除了能正常显示RoboMaster的官方logo可以正常使用,其它显示字符、显示字符串和中文的函数均无法正常使用,可能是我手里的例程比较陈旧,或者是RM官方没有及时更新新的代码,接下来是我自己写的底层代码的主体部分:
config_usart.c ,这里之所以配置串口1的收发中断的目的是为了方便上位机和单片机进行交互,进行调参或者其它功用
#include “config_usart.h”
#include “main.h”
#include “OLED.h”
#include “sys.h”
#include “stdio.h”
#include “string.h”
#include “led.h”
#include “struct_typedef.h”
#include “usart.h”
#include “receiver_dr16.h”

USART_RECEIVETYPE UsartType;

/**

  • @brief Retargets the C library printf function to the USART.
    */
    int fputc(int ch,FILE *f)
    {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
    }
    //该函数用来清除串口接收的数据
    void Usart1Receive_IDLE(UART_HandleTypeDef *huart)
    {
    uint32_t temp;

    if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
    {
    __HAL_UART_CLEAR_IDLEFLAG(&huart1);//´®¿ÚÇå³ý¿ÕÏк¯Êý
    HAL_UART_DMAStop(&huart1);
    //NDTR为DMA传输通道传输数量寄存器
    temp = huart1.hdmarx->Instance->NDTR;//
    UsartType.RX_Size = RX_LEN - temp;
    UsartType.RX_flag = 1;
    HAL_UART_Receive_DMA(&huart1,UsartType.RX_pData,RX_LEN);
    }
    }
    //DMA串口发送回调函数
    void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
    {
    __HAL_DMA_DISABLE(huart->hdmatx);
    if(huart == &huart1)
    UsartType.dmaSend_flag = USART_DMA_SENDOVER;
    }
    void Usart1SendData_DMA(UART_HandleTypeDef * huart,USART_RECEIVETYPE recivetype,uint8_t *pdata, uint16_t Length)
    {
    while(recivetype.dmaSend_flag == USART_DMA_SENDING);
    recivetype.dmaSend_flag = USART_DMA_SENDING;
    HAL_UART_Transmit_DMA(huart, pdata, Length);
    }

void USART1_Interrupt(void)
{
HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_IT(&huart1, UsartType.RX_pData,RX_LEN);
}
config_usart.h:
#ifndef __CONFIG_USART_H
#define __CONFIG_USART_H

#include “main.h”
#include “OLED.h”
#include “sys.h”
#include “stdio.h”
#include “string.h”
#include “led.h”
#include “struct_typedef.h”
#include “usart.h”

#define RX_LEN 1024
#define USART_DMA_SENDING 1//发送中标志位
#define USART_DMA_SENDOVER 0//发送完成标志位

typedef struct
{
uint8_t RX_flag:1; //IDLE receive flag接收中断清除标志位
uint16_t RX_Size; //receive length 接收数据长度
uint8_t RX_pData[RX_LEN]; //DMA receive bufferDMA接收数据通道
uint8_t dmaSend_flag:1;
}USART_RECEIVETYPE;

extern USART_RECEIVETYPE UsartType;

void Usart1SendData_DMA(UART_HandleTypeDef * huart,USART_RECEIVETYPE recivetype,uint8_t *pdata, uint16_t Length);
void USART1_Interrupt(void);

#endif
stm32f4xx_it.c中的代码一定要注意,因为没有一下代码,串口1的收发中断无法正常使用:
在这里插入图片描述
**

代码主体部分,DR16串口3以DMA的方式进行接收,receiver_dr16.c(下面只展示我个人编写的遥控器解码程序,RM官方底层在这不做赘述):

**
void Get_DR16_Data(void)
{
HAL_UART_Receive_DMA(&huart3,sbus_buf,18);
}

int16_t RC_CH0,RC_CH1,RC_CH2,RC_CH3,RC_CH4,RC_S0,RC_S1;
int16_t X;
int16_t Y;
int16_t Z;
uint8_t PRESS_L;
uint8_t PRESS_R;
uint16_t KEY_V;

void Translate_DR16(void)
{
RC_CH0 = (sbus_buf[0] | (sbus_buf[1] << 8)) & 0x07ff; //!< Channel 0
RC_CH1 = ((sbus_buf[1] >> 3) | (sbus_buf[2] << 5)) & 0x07ff;
RC_CH2 = ((sbus_buf[2] >> 6) | (sbus_buf[3] << 2) | (sbus_buf[4] << 10)) &0x07ff; //!< Channel 2
RC_CH3 = ((sbus_buf[4] >> 1) | (sbus_buf[5] << 7)) & 0x07ff; //!< Channel 3
RC_S0 = ((sbus_buf[5] >> 4) & 0x0003); //!< Switch left
RC_S1 = ((sbus_buf[5] >> 4) & 0x000C) >> 2; //!< Switch right
X = sbus_buf[6] | (sbus_buf[7] << 8); //!< Mouse X axis
Y = sbus_buf[8] | (sbus_buf[9] << 8); //!< Mouse Y axis
Z = sbus_buf[10] | (sbus_buf[11] << 8); //!< Mouse Z axis

PRESS_L = sbus_buf[12];								//!< Mouse Left Is Press ?
PRESS_R = sbus_buf[13];								//!< Mouse Right Is Press ?

KEY_V = sbus_buf[14] | (sbus_buf[15] << 8);		//!< KeyBoard value
RC_CH4 = sbus_buf[16] | (sbus_buf[17] << 8);                 //NULL

RC_CH0 -= RC_CH_VALUE_OFFSET;
RC_CH1 -= RC_CH_VALUE_OFFSET;
RC_CH2 -= RC_CH_VALUE_OFFSET;
RC_CH3 -= RC_CH_VALUE_OFFSET;
RC_CH4 -= RC_CH_VALUE_OFFSET;

}
main.c,在这只展示main函数中:
int main(void)
{
/* USER CODE BEGIN 1 /
char DR16_Data[50];
/
USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_I2C2_Init();
MX_TIM6_Init();
MX_USART3_UART_Init();
MX_USART6_UART_Init();

/* Initialize interrupts /
/
USER CODE BEGIN 2 */

USART1_Interrupt();
delay_ms(50);

delay_init();
delay_ms(50);
OLED_init();
delay_ms(50);
OLED_Clear();
delay_ms(50);

/* USER CODE END 2 */

/* Infinite loop /
/
USER CODE BEGIN WHILE /
delay_ms(50);
OLED_Test();
delay_ms(50);
printf(“Hello World!\n”);
delay_ms(50);
OLED_Clear();
MX_NVIC_Init();
while (1)
{
/
USER CODE END WHILE */

/* USER CODE BEGIN 3 */

#if 0
if(UsartType.RX_flag) // Receive flag
{
UsartType.RX_flag=0; // clean flag
HAL_UART_Transmit(&huart1, UsartType.RX_pData, UsartType.RX_Size, 0xFFFF);
}
Get_DR16_Data();
delay_ms(500);
#endif
Get_DR16_Data();
Translate_DR16();

		sprintf(DR16_Data,"CH0:%d",RC_CH0);
		OLED_ShowString(0,0,DR16_Data);
		
		sprintf(DR16_Data,"CH1:%d",RC_CH1);
		OLED_ShowString(0,1,DR16_Data);
		
		sprintf(DR16_Data,"CH2:%d",RC_CH2);
		OLED_ShowString(0,2,DR16_Data);
	
		sprintf(DR16_Data,"CH3:%d",RC_CH3);
		OLED_ShowString(0,3,DR16_Data);
		
		sprintf(DR16_Data,"CH4:%d",RC_CH4);
		OLED_ShowString(0,4,DR16_Data);

}
/* USER CODE END 3 */
}
以上代码经过整理测试,可以将DR16接收到的遥控器的数据通过串口或者OLED显示出来,但是DR16接收机的缺点就是虽然占用硬件资源少,但是接收到的信号需要进行滤波处理,否则将会影响正常使用,不过滤波的前提是先将信号读取出来,希望大家多提意见,不喜勿喷。个人代码将会上传到CSDN。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值