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);//′??ú??3y???Doˉêy 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。
|