/** ****************************(C) COPYRIGHT 2019 DJI**************************** * @file remote_control.c/h * @brief 遥控器处理,遥控器是通过类似SBUS的协议传输,利用DMA传输方式节约CPU * 资源,利用串口空闲中断来拉起处理函数,同时提供一些掉线重启DMA,串口 * 的方式保证热插拔的稳定性。 * @note 该任务是通过串口中断启动,不是freeRTOS任务 * @history * Version Date Author Modification * V1.0.0 Dec-01-2019 RM 1. 完成 * @verbatim ============================================================================== ============================================================================== @endverbatim ****************************(C) COPYRIGHT 2019 DJI**************************** */ #include "remote_control.h" #include "main.h" #include "calc_lib.h" extern UART_HandleTypeDef huart3; extern DMA_HandleTypeDef hdma_usart3_rx; #if DT7==1 uint8_t dbus_buf[DBUS_BUFLEN]; RC_ctrl_t rc_ctrl = rc_Init;//所有数据初始化 // 使用 DMA 接收 UART 数据的函数 static int uart_receive_dma_no_it(UART_HandleTypeDef* huart, uint8_t* pData, uint32_t Size) { uint32_t tmp1 = huart->RxState; if (tmp1 == HAL_UART_STATE_READY) { if ((pData == NULL) || (Size == 0)) { return HAL_ERROR; } huart->pRxBuffPtr = pData; huart->RxXferSize = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; HAL_DMA_Start(huart->hdmarx, (uint32_t)&huart->Instance->DR, (uint32_t)pData, Size); SET_BIT(huart->Instance->CR3, USART_CR3_DMAR); return HAL_OK; } return HAL_BUSY; } // DBUS 串口初始化 void dbus_uart_init(void) { __HAL_UART_CLEAR_IDLEFLAG(&DBUS_HUART); __HAL_UART_ENABLE_IT(&DBUS_HUART, UART_IT_IDLE); uart_receive_dma_no_it(&DBUS_HUART, dbus_buf, DBUS_MAX_LEN); } // 串口中断处理函数 void USART3_IRQHandler(void) { uart_receive_handler(&huart3);//调用之前定义的函数,传入DBUS串口的地址,以处理接收事件 } // 遥控器数据解码函数 void rc_callback_handler(RC_ctrl_t *rc_ctrl, uint8_t *buff) { rc_ctrl->ch0 = (buff[0] | (buff[1] << 8)) & 0x07FF; rc_ctrl->ch0 -= 1024; rc_ctrl->ch1 = (buff[1] >> 3 | buff[2] << 5) & 0x07FF; rc_ctrl->ch1 -= 1024; rc_ctrl->ch2 = (buff[2] >> 6 | buff[3] << 2 | buff[4] << 10) & 0x07FF; rc_ctrl->ch2 -= 1024; rc_ctrl->ch3 = (buff[4] >> 1 | buff[5] << 7) & 0x07FF; rc_ctrl->ch3 -= 1024; rc_ctrl->roll = (buff[16] | (buff[17] << 8)) & 0x07FF; rc_ctrl->roll -= 1024; rc_ctrl->sw1 = ((buff[5] >> 4) & 0x000C) >> 2; rc_ctrl->sw2 = (buff[5] >> 4) & 0x0003; // if ((abs(rc_ctrl->ch0) > 660) || (abs(rc_ctrl->ch1) > 660) || (abs(rc_ctrl->ch2) > 660) || (abs(rc_ctrl->ch3) > 660)) // { // memset(rc_ctrl, 0, sizeof(RC_ctrl_t)); // } } // 计算 DMA 剩余的数据长度 uint16_t dma_current_data_counter(DMA_Stream_TypeDef *dma_stream) { return ((uint16_t)(dma_stream->NDTR)); } // 处理 UART 空闲中断,处理接收到的数据 static void uart_rx_idle_callback(UART_HandleTypeDef* huart) { __HAL_UART_CLEAR_IDLEFLAG(huart); if (huart == &DBUS_HUART) { __HAL_DMA_DISABLE(huart->hdmarx); if ((DBUS_MAX_LEN - dma_current_data_counter(huart->hdmarx->Instance)) == DBUS_BUFLEN) { rc_callback_handler(&rc_ctrl, dbus_buf); } __HAL_DMA_SET_COUNTER(huart->hdmarx, DBUS_MAX_LEN); __HAL_DMA_ENABLE(huart->hdmarx); } } // 检查 UART 接收状态,处理空闲状态 void uart_receive_handler(UART_HandleTypeDef *huart) { if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(huart, UART_IT_IDLE)) { uart_rx_idle_callback(huart); } } // int map(int x, int in_min, int in_max, int out_min, int out_max) //映射函数 // { // return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; // } /* s1 s2 1/3/2 1/3/2 660 660 | | | | -660 -- --ch[2]660 -660 -- --ch[0]660 | | | | ch[3] ch[1] -660 -660 */ #else static void sbus_to_rc(volatile const uint8_t *sbus_buf, RC_ctrl_t *rc_ctrl); void RC_init(uint8_t *rx1_buf, uint8_t *rx2_buf, uint16_t dma_buf_num); RC_ctrl_t rc_ctrl; static uint8_t sbus_rx_buf[2][RC_FRAME_LENGTH]; uint8_t remote_ready = 0;//遥控器准备完成 //串口dma双缓冲区初始化 //串口中断 void remote_control_init(void) { RC_init(sbus_rx_buf[0], sbus_rx_buf[1], RC_FRAME_LENGTH); } static uint16_t this_time_rx_len = 0; //////////////////////////////////////// void USART3_IRQHandler(void) { //have received data if(huart3.Instance->SR & UART_FLAG_RXNE) { //如果是接收中断则通过读取dr寄存器清零 __HAL_UART_CLEAR_FEFLAG(&huart3); } else if(USART3->SR & UART_FLAG_IDLE) { //使用清除pe标志位的函数是因为pe idle等几个中断都是靠先读取sr再读取dr清零的 __HAL_UART_CLEAR_PEFLAG(&huart3); if( (hdma_usart3_rx.Instance->CR & DMA_SxCR_CT) == RESET) { //current memory buffer used is memory0 //disable dma to change dma register __HAL_DMA_DISABLE(&hdma_usart3_rx); //get received data length, length = set_data_length - remain_length this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR; //reset set_data_length hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM; //change memory0 to memory1 hdma_usart3_rx.Instance->CR |= DMA_SxCR_CT; //enable dma __HAL_DMA_ENABLE(&hdma_usart3_rx); if(this_time_rx_len ==RC_FRAME_LENGTH) { sbus_to_rc(sbus_rx_buf[0], &rc_ctrl); } } else { __HAL_DMA_DISABLE(&hdma_usart3_rx); this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR; hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM; //change memory1 to memory0 DMA1_Stream1->CR &= ~(DMA_SxCR_CT); __HAL_DMA_ENABLE(&hdma_usart3_rx); if(this_time_rx_len ==RC_FRAME_LENGTH) { sbus_to_rc(sbus_rx_buf[1], &rc_ctrl); } } } } 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(huart3.Instance->CR3, USART_CR3_DMAR); //enable idle interrupt __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE); //disable dma, to change the dma register __HAL_DMA_DISABLE(&hdma_usart3_rx); while(hdma_usart3_rx.Instance->CR & DMA_SxCR_EN) { __HAL_DMA_DISABLE(&hdma_usart3_rx); } hdma_usart3_rx.Instance->PAR = (uint32_t) & (USART3->DR); //memory buffer 1 hdma_usart3_rx.Instance->M0AR = (uint32_t)(rx1_buf); //momory buffer 2 hdma_usart3_rx.Instance->M1AR = (uint32_t)(rx2_buf); //data length hdma_usart3_rx.Instance->NDTR = dma_buf_num; //enable double memory buffer SET_BIT(hdma_usart3_rx.Instance->CR, DMA_SxCR_DBM); //enable dma __HAL_DMA_ENABLE(&hdma_usart3_rx); } 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->ch[0] = (sbus_buf[1] | (sbus_buf[2] << 8)) & 0x07ff; //Channel 1 rc_ctrl->ch[1] = ((sbus_buf[2] >> 3) | (sbus_buf[3] << 5)) & 0x07ff; //Channel 2 rc_ctrl->ch[2] = ((sbus_buf[3] >> 6) | (sbus_buf[4] << 2) | //Channel 3 (sbus_buf[5] << 10)) &0x07ff; rc_ctrl->ch[3] = ((sbus_buf[5] >> 1) | (sbus_buf[6] << 7)) & 0x07ff; //Channel 4 rc_ctrl->sw[0] = ((int16_t)sbus_buf[6] >> 4 | ((int16_t)sbus_buf[7] << 4 )) & 0x07FF; //Channel 5 rc_ctrl->sw[1] = ((int16_t)sbus_buf[7] >> 7 | ((int16_t)sbus_buf[8] << 1 ) | (int16_t)sbus_buf[9] << 9 ) & 0x07FF; //Channel 6 rc_ctrl->sw[2] = ((int16_t)sbus_buf[9] >> 2 | ((int16_t)sbus_buf[10] << 6 )) & 0x07FF;; //Channel 7 rc_ctrl->sw[3] = ((int16_t)sbus_buf[10] >> 5 | ((int16_t)sbus_buf[11] << 3 )) & 0x07FF; //Channel 8 rc_ctrl->sw[4] = ((int16_t)sbus_buf[12] << 0 | ((int16_t)sbus_buf[13] << 8 )) & 0x07FF; //Channel 9 rc_ctrl->sw[5] = ((int16_t)sbus_buf[13] >> 3 | ((int16_t)sbus_buf[14] << 5 )) & 0x07FF; //Channel 10 rc_ctrl->sw[6] = ((int16_t)sbus_buf[14] >> 6 | ((int16_t)sbus_buf[15] << 2 ) | (int16_t)sbus_buf[16] << 10 ) & 0x07FF; //Channel 11 rc_ctrl->sw[7] = ((int16_t)sbus_buf[16] >> 1 | ((int16_t)sbus_buf[17] << 7 )) & 0x07FF; //Channel 12 rc_ctrl->sw[2] = map(rc_ctrl->sw[2],306,1694,1694,306); rc_ctrl->sw[3] = map(rc_ctrl->sw[3],306,1694,1694,306); rc_ctrl->ch[1] = map(rc_ctrl->ch[1],-693,694,-700,700); //x rc_ctrl->ch[0] = map(rc_ctrl->ch[0],-694,693,-700,700); //y //死区(-30,30) if(rc_ctrl->ch[0]>-14&&rc_ctrl->ch[0]<6) rc_ctrl->ch[0]=0; if(rc_ctrl->ch[1]>-30&&rc_ctrl->ch[1]<-10) rc_ctrl->ch[1]=0; if(rc_ctrl->ch[2]>=0&&rc_ctrl->ch[2]<=7) rc_ctrl->ch[2]=7; if(rc_ctrl->ch[3]>-22&&rc_ctrl->ch[3]<-2) rc_ctrl->ch[3]=0; remote_ready = 1; } #endif /* 306 306 sw[] sw[7] 1694 1694 306 306 sw[6] sw[4] 1694 1694 306 306 306 306 sw[0] sw[2] sw[1]:306-1694 sw[5]:306-1694 sw[]1000 sw[3] 1694 1694 1694 1694 710 688 1425 | | | | 54 -616------ch[3]770 -354---------ch[0] 339 0 | | | | ch[2] ch[1] _699 38 */