#include "stm32f4xx.h" // Device header #include "stm32f4xx_conf.h" #include "Remote.h" #include "UART.h" #include "Warming.h" #include "RefereeSystem.h" uint8_t Remote_RxData0[18];//遥控器DMA数据存储器0 uint8_t Remote_RxData1[18];//遥控器DMA数据存储器1 Remote_Data Remote_RxData;//遥控器接收数据 Remote_Data Remote_LastRxData;//遥控器上一次接收数据 uint8_t Remote_Status;//遥控器连接状态,默认未连接(0) uint8_t Remote_StartFlag=1;//遥控器启动标志位,0-未在启动阶段,1-准备启动,2-第一次接收到数据 /* *函数简介:遥控器初始化 *参数说明:无 *返回类型:无 *备注:默认接收引脚为PC11(USART3-Rx) *备注:采用串口DMA双缓冲接收 *备注:配置定时中断为TIM7 25ms,用来检测遥控器连接情况 *备注:加入独立看门狗,用来在数据接收错误时复位(只在上电的一刻可能数据错误) *备注:独立看门狗时钟为LSI(32kHz),预分频数默认为8,故IWDG时钟4kHz,重装载值为0x0FFF(4095) *备注:喂狗时间(溢出时间)T_OUT=Reload/(LSI/Prescaler)=4095/(32k/8)=1.02375s */ void Remote_Init(void) { /*===============配置时钟===============*/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);//开启时钟 /*===============配置GPIO===============*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//复用推挽 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//默认上拉 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz; GPIO_Init(GPIOC,&GPIO_InitStructure);//初始化USART3-Rx(PC11) GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_USART3);//开启PC11的USART3复用模式 /*===============配置USART和串口接收DMA===============*/ USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate=100000;//配置波特率100k USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//配置无硬件流控制 USART_InitStructure.USART_Mode=USART_Mode_Rx;//配置为接收模式 USART_InitStructure.USART_Parity=USART_Parity_Even;//配置为偶校验 USART_InitStructure.USART_StopBits=USART_StopBits_1;//配置停止位为1 USART_InitStructure.USART_WordLength=USART_WordLength_8b;//配置字长8bit USART_Init(USART3,&USART_InitStructure);//初始化USART3 DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_Channel=DMA_Channel_4;//选择DMA通道4 DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//普通模式(非自动重装) DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//转运方向为外设到存储器 DMA_InitStructure.DMA_BufferSize=18;//数据传输量为18字节 DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh;//最高优先级 DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&(USART3->DR);//外设地址(USART的DR数据接收寄存器) DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//外设突发单次传输 DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设数据长度为1字节(8bits) DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不自增 DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)Remote_RxData0;//存储器地址(遥控器DMA数据存储器0) DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;//存储器突发单次传输 DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//存储器数据长度为1字节(8bits) DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器地址自增 DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//不使用FIFO模式 DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOStatus_1QuarterFull;//设置FIFO阈值为1/4(不使用FIFO模式时,此位无意义) DMA_Init(DMA1_Stream1,&DMA_InitStructure);//初始化数据流1 DMA_DoubleBufferModeConfig(DMA1_Stream1,(uint32_t)Remote_RxData1,DMA_Memory_0);//设置双缓冲搬运从遥控器DMA数据存储器0开始 DMA_DoubleBufferModeCmd(DMA1_Stream1,ENABLE);//使能DMA双缓冲功能 /*===============配置定时器===============*/ TIM_InternalClockConfig(TIM7);//选择时基单元的时钟(TIM7) TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元(配置参数) TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//配置时钟分频为1分频 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//配置计数器模式为向上计数 TIM_TimeBaseInitStructure.TIM_Period=21000-1;//配置自动重装值ARR TIM_TimeBaseInitStructure.TIM_Prescaler=1000-1;//配置分频值PSC,默认定时25ms TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//配置重复计数单元的置为0 TIM_TimeBaseInit(TIM7,&TIM_TimeBaseInitStructure);//初始化TIM7 TIM_ClearFlag(TIM7,TIM_FLAG_Update);//清除配置时基单元产生的中断标志位 /*===============配置接收中断和定时器中断===============*/ USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//打通USART3到NVIC的串口接收中断通道 TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE);//使能TIM7更新中断 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择NVIC分组2(2位抢占优先级,2位响应优先级) NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;//选择USART3中断通道 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级为1 NVIC_Init(&NVIC_InitStructure);//初始化USART3的NVIC NVIC_InitStructure.NVIC_IRQChannel=TIM7_IRQn;//选择中断通道为TIM2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//TIM2的抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//TIM2的响应优先级 NVIC_Init(&NVIC_InitStructure);//初始化NVIC /*===============使能===============*/ DMA_Cmd(DMA1_Stream1,ENABLE);//使能DMA1的数据流1 USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);//使能串口USART3的DMA搬运 USART_Cmd(USART3,ENABLE);//启动USART3 TIM_Cmd(TIM7,ENABLE);//启动定时器 /*===============配置IWDG===============*/ IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_8);//8分频 IWDG_SetReload(0x0FFF);//设置重装载值 IWDG_Enable(); } /* *函数简介:遥控器开启 *参数说明:无 *返回类型:无 *备注:默认开启串口USART3 */ void Remote_ON(void) { USART_Cmd(USART3,ENABLE);//启动USART3 } /* *函数简介:遥控器关闭 *参数说明:无 *返回类型:无 *备注:默认关闭串口USART3 */ void Remote_OFF(void) { USART_Cmd(USART3,DISABLE);//失能USART3 Remote_Status=0;//遥控器连接状态变为未连接 } /* *函数简介:遥控器DMA转运复位 *参数说明:无 *返回类型:无 *备注:无 */ void Remote_TransferReset(void) { while(DMA_GetFlagStatus(DMA1_Stream1,DMA_FLAG_TCIF1)==RESET);//判断接收完成 DMA_ClearFlag(DMA1_Stream1,DMA_FLAG_TCIF1);//清除接收完成标志位 DMA_Cmd(DMA1_Stream1,DISABLE);//失能DMA1的数据流1 while(DMA_GetCmdStatus(DMA1_Stream1)!=DISABLE);//检测DMA1的数据流1为可配置状态 DMA_SetCurrDataCounter(DMA1_Stream1,18);//恢复传输计数器的值 DMA_Cmd(DMA1_Stream1,ENABLE);//使能DMA1的数据流1 } /* *函数简介:遥控器数据处理 *参数说明:无 *返回类型:无 *备注:遥控器接收数据共18Bytes(144bits) */ void Remote_DataProcess(void) { uint8_t *Data;//选择存储器 uint16_t Remote_R_RL_True; if(DMA_GetCurrentMemoryTarget(DMA1_Stream1)==0)Data=Remote_RxData1;//若当前转运位于存储器0,则存储器1数据完整,采用存储器1进行数据处理 else Data=Remote_RxData0;//若当前转运位于存储器1,则存储器0数据完整,采用存储器0进行数据处理 Remote_RxData.Remote_Mouse_KeyLastR=Remote_RxData.Remote_Mouse_KeyR;//获取上一次五个键的状态 Remote_RxData.Remote_KeyLast_Q=Remote_RxData.Remote_Key_Q; Remote_RxData.Remote_KeyLast_E=Remote_RxData.Remote_Key_E; Remote_RxData.Remote_KeyLast_Shift=Remote_RxData.Remote_Key_Shift; Remote_RxData.Remote_KeyLast_Ctrl=Remote_RxData.Remote_Key_Ctrl; //Remote_RxData.Remote_R_RL=(((uint16_t)Data[1]<<8) | Data[0]) & 0x07FF;//B[0:10],11bits Remote_R_RL_True=(((uint16_t)Data[1]<<8) | Data[0]) & 0x07FF;//B[0:10],11bits if(Remote_R_RL_True>1025) Remote_RxData.Remote_R_RL=Remote_R_RL_True-1; else if(Remote_R_RL_True<1023) Remote_RxData.Remote_R_RL=Remote_R_RL_True+1; else Remote_RxData.Remote_R_RL=1024; Remote_RxData.Remote_R_UD=(((uint16_t)Data[2]<<5) | (Data[1]>>3)) & 0x07FF;//B[11:21],11bits Remote_RxData.Remote_L_RL=(((uint16_t)Data[4]<<10) | (((uint16_t)Data[3]<<2) | (Data[2]>>6))) & 0x07FF;//B[22:32],11bits Remote_RxData.Remote_L_UD=(((uint16_t)Data[5]<<7) | (Data[4]>>1)) & 0x07FF;//B[33:43],11bits Remote_RxData.Remote_RS=(Data[5]>>4) & 0x03;//B[44:45],2bits Remote_RxData.Remote_LS=(Data[5]>>6) & 0x03;//B[46:47],2bits Remote_RxData.Remote_Mouse_RL=(int16_t)(((uint16_t)Data[7]<<8) | Data[6]);//B[48:63],16bits Remote_RxData.Remote_Mouse_DU=(int16_t)(((uint16_t)Data[9]<<8) | Data[8]);//B[64:79],16bits Remote_RxData.Remote_Mouse_Wheel=(int16_t)(((uint16_t)Data[11]<<8) | Data[10]);//B[80:95],16bits Remote_RxData.Remote_Mouse_KeyL=Data[12];//B[96:103],8bits Remote_RxData.Remote_Mouse_KeyR=Data[13];//B[104:111],8bits Remote_RxData.Remote_Key_W=Data[14] & 0x01;//B[112:112],1bits Remote_RxData.Remote_Key_S=(Data[14]>>1) & 0x01;//B[113:113],1bits Remote_RxData.Remote_Key_A=(Data[14]>>2) & 0x01;//B[114:114],1bits Remote_RxData.Remote_Key_D=(Data[14]>>3) & 0x01;//B[115:115],1bits Remote_RxData.Remote_Key_Shift=(Data[14]>>4) & 0x01;//B[116:116],1bits Remote_RxData.Remote_Key_Ctrl=(Data[14]>>5) & 0x01;//B[117:117],1bits Remote_RxData.Remote_Key_Q=(Data[14]>>6) & 0x01;//B[118:118],1bits Remote_RxData.Remote_Key_E=(Data[14]>>7) & 0x01;//B[119:119],1bits Remote_RxData.Remote_ThumbWheel=(int16_t)((uint16_t)Data[17]<<8) | Data[16];//B[120:135],16bits if(Remote_RxData.Remote_KeyLast_Q==0 && Remote_RxData.Remote_Key_Q==1)Remote_RxData.Remote_KeyPush_Q=!Remote_RxData.Remote_KeyPush_Q;//检测是否按下 if(Remote_RxData.Remote_KeyLast_E==0 && Remote_RxData.Remote_Key_E==1)Remote_RxData.Remote_KeyPush_E=!Remote_RxData.Remote_KeyPush_E; if(Remote_RxData.Remote_KeyLast_Shift==0 && Remote_RxData.Remote_Key_Shift==1)Remote_RxData.Remote_KeyPush_Shift=!Remote_RxData.Remote_KeyPush_Shift; if(Remote_RxData.Remote_KeyLast_Ctrl==0 && Remote_RxData.Remote_Key_Ctrl==1)Remote_RxData.Remote_KeyPush_Ctrl=!Remote_RxData.Remote_KeyPush_Ctrl; if(Remote_RxData.Remote_Mouse_KeyLastR==0 && Remote_RxData.Remote_Mouse_KeyR==1)Remote_RxData.Remote_Mouse_KeyPushR=1; else Remote_RxData.Remote_Mouse_KeyPushR=0; } /* *函数简介:遥控器接收中断 *参数说明:无 *返回类型:无 *备注:USART的接收中断 */ void USART3_IRQHandler(void) { TIM_SetCounter(TIM7,0); TIM_Cmd(TIM7,DISABLE);//关闭定时器并重置计数值 if(DMA_GetCurrDataCounter(DMA1_Stream1)==18)//转运一次完成,并交换了存储器 { Remote_TransferReset();//复位DMA1的数据流1 Remote_DataProcess();//数据处理 if(Remote_StartFlag==1)//第一次接收数据 { while(Remote_RxData.Remote_R_RL!=1024 || Remote_RxData.Remote_R_UD!=1024 || Remote_RxData.Remote_L_RL!=1024 || Remote_RxData.Remote_L_UD!=1024)//数据错误 Warming_RemoteDataERROR();//数据错误报错,等待看门狗复位 Remote_StartFlag=2; Warming_LEDClean(); } Remote_Status=1;//遥控器已连接 } TIM_Cmd(TIM7,ENABLE);//开启定时 USART_ClearITPendingBit(USART3,USART_IT_RXNE);//清除接收中断标志位 } /* *函数简介:TIM7定时器更新中断函数 *参数说明:无 *返回类型:无 *备注:进入中断即遥控器未连接 */ void TIM7_IRQHandler(void) { if(TIM_GetITStatus(TIM7,TIM_IT_Update)==SET)//检测TIM2更新 { TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除标志位 Warming_RemoteNoCheck();//遥控器未连接报警 RefereeSystem_Status=0;//裁判系统(图传链路)连接状态变为未连接 Remote_Status=0;//遥控器连接状态变为未连接 Remote_StartFlag=1;//遥控器处于准备启动阶段 } }