/*************************** (C) COPYRIGHT 2017 CXHY ****************************
 * 文件名  ：UltrasonicWave.c
 * 描  述  ：HC-SR04超声波驱动代码     
 * 版  本  ：V1.0
 * 作  者  ：XuZhongPing
 * 日  期  ：2017/08/04 
*********************************************************************************/
#include "UltrasonicWave.h"
#include "timer.h"
#include "delay.h"
#include "my_math.h"
#include "data_typedef.h"


#define	TRIG1_PORT      GPIOA										//TRIG所在的IO口       
#define	ECHO1_PORT      GPIOC										//ECHO所在的IO口
#define	TRIG1_PIN      	GPIO_Pin_11   					//TRIG引脚      
#define	ECHO1_PIN       GPIO_Pin_1							//ECHO引脚 
#define ECHO1_PortSource	GPIO_PortSourceGPIOC	//中断源所在IO口
#define ECHO1_PinSource		GPIO_PinSource1				//中断引脚
#define ECHO1_EXTI_Line		EXTI_Line1						//中断线

#define	TRIG2_PORT    	GPIOA										//TRIG所在的IO口      
#define	ECHO2_PORT    	GPIOC										//ECHO所在的IO口
#define	TRIG2_PIN     	GPIO_Pin_12   					//TRIG引脚       
#define	ECHO2_PIN     	GPIO_Pin_0							//ECHO引脚 
#define ECHO2_PortSource	GPIO_PortSourceGPIOC	//中断源所在IO口
#define ECHO2_PinSource		GPIO_PinSource0				//中断引脚
#define ECHO2_EXTI_Line		EXTI_Line0						//中断线

#define	TRIG3_PORT    	GPIOA										//TRIG所在的IO口         
#define	ECHO3_PORT    	GPIOD										//ECHO所在的IO口   
#define	TRIG3_PIN     	GPIO_Pin_15   						//TRIG引脚        
#define	ECHO3_PIN     	GPIO_Pin_0							//ECHO引脚 
#define ECHO3_PortSource	GPIO_PortSourceGPIOD	//中断源所在IO口
#define ECHO3_PinSource		GPIO_PinSource0				//中断引脚
#define ECHO3_EXTI_Line		EXTI_Line0						//中断线

#define	TRIG4_PORT    	GPIOD										//TRIG所在的IO口       
#define	ECHO4_PORT    	GPIOD										//ECHO所在的IO口 
#define	TRIG4_PIN     	GPIO_Pin_1   						//TRIG引脚        
#define	ECHO4_PIN     	GPIO_Pin_3							//ECHO引脚 
#define ECHO4_PortSource	GPIO_PortSourceGPIOD	//中断源所在IO口
#define ECHO4_PinSource		GPIO_PinSource3				//中断引脚
#define ECHO4_EXTI_Line		EXTI_Line3						//中断线   

#define ULT_Data_Size		5

uint8_t distance1 = 255;      								//采用超声波所测得的距离 
uint8_t distance2 = 255;      								//采用超声波所测得的距离 
uint8_t distance3 = 255;      								//采用超声波所测得的距离 
uint8_t distance4 = 255;      								//采用超声波所测得的距离 

uint8_t dataOutState = 0;											//数据是否已经处理完成状态，1：已处理完成可以输出状态、0：尚未处理完成
uint8_t dataOutState1 = 0;										
uint8_t dataOutState2 = 0;

uint8_t succeedFlag;											//接收成功标志
uint16_t counterValue;										//超声波回波时间
// uint8_t ULT_Data[ULT_Data_Size];

static void EXTI_Cmd(uint16_t EXTI_Line, uint8_t NewState);

/*
***********************************************************************
*	函 数 名: UltrasonicWave_Configuration
*	功能说明: 超声波模块的初始化
*	形    参：无
*	返 回 值: 无
***********************************************************************
*/
void UltrasonicWaveInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;	
	EXTI_InitTypeDef EXTI_InitStructure;
 	NVIC_InitTypeDef NVIC_InitStructure;
	
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);	
  
	//NO.1超声波
  GPIO_InitStructure.GPIO_Pin = TRIG1_PIN;					 					//TRIG引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		     		//设为推挽输出模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	         
  GPIO_Init(TRIG1_PORT, &GPIO_InitStructure);	              

  GPIO_InitStructure.GPIO_Pin = ECHO1_PIN;				     				//ECHO引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		 						//设为上拉输入
  GPIO_Init(ECHO1_PORT, &GPIO_InitStructure);						 			
	
	//NO.2超声波
  GPIO_InitStructure.GPIO_Pin = TRIG2_PIN;					 					//TRIG引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		     		//设为推挽输出模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	         
  GPIO_Init(TRIG2_PORT, &GPIO_InitStructure);	              

  GPIO_InitStructure.GPIO_Pin = ECHO2_PIN;				     				//ECHO引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		 						//设为上拉输入
  GPIO_Init(ECHO2_PORT, &GPIO_InitStructure);							
	
	//NO.1超声波中断线初始化配置
 	GPIO_EXTILineConfig(ECHO1_PortSource, ECHO1_PinSource);
	EXTI_InitStructure.EXTI_Line = ECHO1_EXTI_Line;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;			//下降沿触发
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);	
	EXTI_Cmd(ECHO1_EXTI_Line, DISABLE);
	
	//NO.2超声波中断线初始化配置
 	GPIO_EXTILineConfig(ECHO2_PortSource, ECHO2_PinSource);
	EXTI_InitStructure.EXTI_Line = ECHO2_EXTI_Line;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;			//下降沿触发
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);	
	EXTI_Cmd(ECHO2_EXTI_Line, DISABLE);
	
	//中断配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;						//使能检测脚所在的外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;		//抢占优先级2 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;					//子优先级2 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;							//使能外部中断通道
	NVIC_Init(&NVIC_InitStructure); 
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;					//使能检测脚所在的外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;		//抢占优先级2 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;					//子优先级2 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;							//使能外部中断通道
	NVIC_Init(&NVIC_InitStructure); 
}

/*
***********************************************************************
*	函 数 名: EXTI15_10_IRQHandler
*	功能说明: 外部中断服务子程序
*	形    参：无
*	返 回 值: 无
***********************************************************************
*/
void EXTI0_IRQHandler(void)
{          
	counterValue = TIM_GetCounter(TIM4);					//取出回波的定时时间
// 	printf("计时为:%d\r\n", counterValue);
	succeedFlag = 1;															//置接收成功标志
	EXTI_ClearITPendingBit(ECHO2_EXTI_Line);  		//清除NO.1超声波EXTI线路挂起位
}

/*
***********************************************************************
*	函 数 名: EXTI9_5_IRQHandler
*	功能说明: 外部中断服务子程序
*	形    参：无
*	返 回 值: 无
***********************************************************************
*/
void EXTI1_IRQHandler(void)
{          
	counterValue = TIM_GetCounter(TIM4);					//取出回波的定时时间
// 	printf("计时为:%d\r\n", counterValue);
	succeedFlag = 1;															//置接收成功标志
	EXTI_ClearITPendingBit(ECHO1_EXTI_Line);  		//清除NO.3超声波EXTI线路挂起位
}

/*
***********************************************************************
*	函 数 名: EXTI_Cmd
*	功能说明: 外部中断使能/禁能操作
*	形    参：
*           EXTI_Line:外部中断引脚号
*	          NewState :使能ENABLE，禁能DISABLE
*	返 回 值: 无
***********************************************************************
*/
static void EXTI_Cmd(uint16_t EXTI_Line, uint8_t NewState)
{
    EXTI->PR = EXTI_Line;  									//清除EXTI_Line上的中断标志位
    if(NewState){
			EXTI->IMR |= EXTI_Line;								//不屏蔽EXTI_Line上的中断
		}else{
			EXTI->IMR &= ~EXTI_Line;							//屏蔽EXTI_Line上的中断
		}
}

/*
***********************************************************************
*	函 数 名: GetDistance
*	功能说明: 获取一次超声波测距数据
*	形    参：无
*	返 回 值: 所测得的数据
***********************************************************************
*/
uint8_t GetDistance(uint8_t whichOne)
{
	uint8_t value = 255;
	uint16_t TIM_Count = 0;
	
	GPIO_TypeDef *TRIG_PORTx;
	GPIO_TypeDef *ECHO_PORTx;	
	uint16_t TRIG_PINx;
	uint16_t ECHO_PINx;
	uint16_t ECHO_EXTI_LineX;
	
	switch(whichOne)
	{
		case 1:
			TRIG_PORTx = TRIG1_PORT;
			ECHO_PORTx = ECHO1_PORT;
			TRIG_PINx = TRIG1_PIN;
			ECHO_PINx = ECHO1_PIN;
			ECHO_EXTI_LineX = ECHO1_EXTI_Line;
			break;
			
		case 2:
			TRIG_PORTx = TRIG2_PORT;
			ECHO_PORTx = ECHO2_PORT;
			TRIG_PINx = TRIG2_PIN;
			ECHO_PINx = ECHO2_PIN;
			ECHO_EXTI_LineX = ECHO2_EXTI_Line;
			break;
			
		case 3:
			TRIG_PORTx = TRIG3_PORT;
			ECHO_PORTx = ECHO3_PORT;
			TRIG_PINx = TRIG3_PIN;
			ECHO_PINx = ECHO3_PIN;
			ECHO_EXTI_LineX = ECHO3_EXTI_Line;
			break;
			
		case 4:
			TRIG_PORTx = TRIG4_PORT;
			ECHO_PORTx = ECHO4_PORT;
			TRIG_PINx = TRIG4_PIN;
			ECHO_PINx = ECHO4_PIN;
			ECHO_EXTI_LineX = ECHO4_EXTI_Line;
			break;
		
		default:
			break;
	}

	//在TRIG引脚产生一个10us以上的高电平脉冲触发信号来启动发射
	GPIO_SetBits(TRIG_PORTx, TRIG_PINx); 		  	
  delay_us(20);		                      			
  GPIO_ResetBits(TRIG_PORTx, TRIG_PINx);
	while((GPIO_ReadInputDataBit(ECHO_PORTx, ECHO_PINx) == 0) && (TIM_Count<4000))	//等待Echo回波引脚变成高电平
	{
		TIM_Count++;
	}
	if(TIM_Count >= 4000)
	{
		return 255;
	}
	TIM_Count = 0;
	succeedFlag = 0;
	EXTI_Cmd(ECHO_EXTI_LineX, ENABLE);				//打开ECHO_EXTI_Line线上外部中断，监测下沿的到来
	
	TIM_SetCounter(TIM4, 0);									//定时器计数值清0
	TIM_Cmd(TIM4, ENABLE);  									//打开定时，开始定时
	
	while(TIM_Count < 120 && succeedFlag == 0)										//限定等待时间（即12ms大概为2米距离），超出此时间还没有触发外部中断则说明无效
	{
		TIM_Count = TIM_GetCounter(TIM4);
	}
	
	TIM_Cmd(TIM4, DISABLE);										//关闭定时
	EXTI_Cmd(ECHO_EXTI_LineX, DISABLE);				//关闭ECHO_EXTI_Line线上外部中断

// 	printf("TIM_count:%d\r\n", TIM_Count);
	if(succeedFlag == 1)											//判断测距是否成功
	{
// 		printf("\r\nsucceedFlag\r\n");
		value = (float)(counterValue*100)/58;
	}
	counterValue = 0;
	return value;
}

/*
***********************************************************************
*	函 数 名: ULT_DataProcessing
*	功能说明: 对采集到缓存的数据处理（对其进行排序后求平均数）
*	形    参：
*       		*p: 需要处理的数组指针
*						n:  数组的长度 
*	返 回 值: 返回最终处理过后的结果
***********************************************************************
*/
uint8_t ULT_DataProcessing(uint8_t *p, uint16_t n, uint8_t discardVal)
{
	uint8_t retData;
	sort_8(p, n);           											//对存在缓存中的采集数据进行排序
	retData = average_8(p, n, discardVal);				//去掉头和尾后，求平均数
// 	printf("\r\nValue = %d\r\n", retData);
	return retData;
}

/*
***********************************************************************
*	函 数 名: GetDistanceData
*	功能说明: 获取超声波测距
*	形    参：无
*	返 回 值: 返回测距数据
***********************************************************************
*/
uint8_t GetDistanceData(uint8_t num)
{
	uint8_t retData = 0;
	retData = GetDistance(num);
	return retData;
}

/*
***********************************************************************
*	函 数 名: GetDistanceTask
*	功能说明: 获取超声波测距任务
*	形    参：无
*	返 回 值: 数据处理状态  1：已处理完成可以输出、0：尚未处理完成
***********************************************************************
*/
void GetDistanceTask_01(void)
{
	static uint8_t ULT_status = 0x00;
	static uint8_t getDataCnt = 0x00;
	
	static uint8_t newValue = 0x00;
	static uint8_t oleValue = 0x00;
	static uint8_t ULT_Data[ULT_Data_Size];
	
	static timer waitingTimer;
	static uint8_t timer_ok = 0;
	
	if(timer_ok == 0)
	{
		timer_ok = 1;
		timer_set(&waitingTimer, 3);
	}
	
	switch(ULT_status)
	{
		case 0x00:
			if(timer_expired(&waitingTimer))
			{
				newValue = GetDistanceData(1);
// 				printf("\r\nValue = %3.1f cm\r\n",(float)newValue);
				ULT_status = 0x01;
				timer_restart(&waitingTimer);
			}
			break;
		case 0x01:
			if(DifferenceCompare(newValue, oleValue, 5))		//比较新旧值的差值，（当前值 - 之前值）> 设定值时重新采集数据
			{
				getDataCnt = 0;
			}
// 			printf("\r\nCnt = %d, newValue = %d, oleValue = %d\r\n", getDataCnt, newValue, oleValue);
			oleValue = newValue;
			
			ULT_Data[getDataCnt] = newValue;
			getDataCnt++;
			if(ULT_Data_Size == getDataCnt)							//10次数据都相差不大，则认为数据已经稳定可以输出
			{
				getDataCnt = 0;
				ULT_status = 0x02;										//转到数据处理输出
			}else{
				ULT_status = 0x00;	
			}
			break;
			
		case 0x02:
			distance1 = ULT_DataProcessing(ULT_Data, ULT_Data_Size, 0);	
// 			printf("\r\nNo1 ---> %3.1f cm\r\n",(float)distance_01);
			dataOutState1 = 1;
			ULT_status = 0x00;
			break;
			
		default:
			ULT_status = 0x00;
			break;
	}
}

/*
***********************************************************************
*	函 数 名: GetDistanceTask_02
*	功能说明: 获取超声波测距任务
*	形    参：无
*	返 回 值: 数据处理状态  1：已处理完成可以输出、0：尚未处理完成
***********************************************************************
*/
void GetDistanceTask_02(void)
{
	static uint8_t ULT_status = 0x00;
	static uint8_t getDataCnt = 0x00;
	
	static uint8_t newValue = 0x00;
	static uint8_t oleValue = 0x00;
	static uint8_t ULT_Data[ULT_Data_Size];
	
	static timer waitingTimer;
	static uint8_t timer_ok = 0;
	
	if(timer_ok == 0)
	{
		timer_ok = 1;
		timer_set(&waitingTimer, 3);
	}
	
	switch(ULT_status)
	{
		case 0x00:
			if(timer_expired(&waitingTimer))
			{
				newValue = GetDistanceData(2);
// 				printf("\r\nValue = %3.1f cm\r\n",(float)newValue);
				ULT_status = 0x01;
				timer_restart(&waitingTimer);
			}
			break;
		case 0x01:
			if(DifferenceCompare(newValue, oleValue, 5))		//比较新旧值的差值，（当前值 - 之前值）> 设定值时重新采集数据
			{
				getDataCnt = 0;
			}
// 			printf("\r\nCnt = %d, newValue = %d, oleValue = %d\r\n", getDataCnt, newValue, oleValue);
			oleValue = newValue;
			
			ULT_Data[getDataCnt] = newValue;
			getDataCnt++;
			if(ULT_Data_Size == getDataCnt)							//10次数据都相差不大，则认为数据已经稳定可以输出
			{
				getDataCnt = 0;
				ULT_status = 0x02;										//转到数据处理输出
			}else{
				ULT_status = 0x00;	
			}
			break;
			
		case 0x02:
			distance2 = ULT_DataProcessing(ULT_Data, ULT_Data_Size, 0);	
// 			printf("\r\nNo2 ---> %3.1f cm\r\n",(float)distance_02);
			dataOutState2 = 1;												//已经准备好数据，可以输出了，此标志由外部清除
			ULT_status = 0x00;
			break;
			
		default:
			ULT_status = 0x00;
			break;
	}
}

// /*
// ***********************************************************************
// *	函 数 名: GetDistanceTask
// *	功能说明: 获取超声波测距任务
// *	形    参：无
// *	返 回 值: 无
// ***********************************************************************
// */
// void GetDistanceTask(void)
// {
// 	static uint8_t ULT_getDataStatus = 0x00;
// 	
// 	static timer waitingTimer;
// 	static timer responsTimer;
// 	static uint8_t timer_ok = 0;
// 	
// 	if(timer_ok == 0)
// 	{
// 		timer_ok = 1;
// 		timer_set(&waitingTimer, CLOCK_SECOND*2);
// 		timer_set(&responsTimer, 3);
// 	}
// 	
// 	switch(ULT_getDataStatus)
// 	{
// 		case 0x00:
// 			if(timer_expired(&waitingTimer))
// 			{
// 				ULT_getDataStatus = 0x01;
// 			}
// 			break;
// 			
// 		case 0x01:
// 			GetDistanceTask_01();
// 			if(dataOutState1 == 1)			//第一路测距数据采集成功
// 			{
// 				dataOutState1 = 0;
// 				ULT_getDataStatus = 0x02;
// // 				printf("\r\n第1路采集OK\r\n");
// 			}
// 			break;
// 			
// 		case 0x02:
// 			GetDistanceTask_02();
// 			if(dataOutState2 == 1)			//第一路测距数据采集成功
// 			{
// 				dataOutState2 = 0;
// 				ULT_getDataStatus = 0x03;
// // 				printf("\r\n第2路采集OK\r\n");
// 			}
// 			break;
// 			
// 		case 0x03:
// 			getDistance1 = distance1;
// 			getDistance2 = distance2;
// 			printf("\r\n测距：No1 = %3.1f cm, ", (float)distance1);
// 			printf("No2 = %3.1f cm\r\n", (float)distance2);
// // 			printf("No3 = %3.1f cm, ", (float)distance3);
// // 			printf("No4 = %3.1f cm\r\n", (float)distance4);
// 			ULT_getDataStatus = 0x00;
// 			timer_restart(&waitingTimer);
// 			break;
// 	}
// }


/******************** (C) COPYRIGHT 2017 CXHY *****END OF FILE*******************/
