/*
2页菜单：1：设定速度、实时速度； 2：母线电压、电流显示。
 KEY1：按键切换速度及电压电流菜单
 KEY2：方向切换按键。电机运行时也可以切换。LED2亮灭表示不同的方向。
 KEY3：电机启停控制，LED3灯亮时，电机处于启动状态； LED3灯来时，电机处于停止状态； 
 电位器调速，切换到速度菜单，可以显示当前设定转速。
 Designed by Cache.lee from UET company
 Tel:18129915976
*/
#include "main.h"
#include "motor.h"
#include "globalv.h"
#include "init.h"
#include "pid.h"
#include "compu.h"
#include "control.h"
//#include "OLED_I2C.h"

unsigned int Menu=0;



//UARTx
#define  DEBUG_USARTx                   CW_UART3
#define  DEBUG_USART_CLK                RCC_APB1_PERIPH_UART3
#define  DEBUG_USART_APBClkENx          RCC_APBPeriphClk_Enable1
#define  DEBUG_USART_BaudRate           115200
#define  DEBUG_USART_UclkFreq           64000000

//UARTx GPIO
#define  DEBUG_USART_GPIO_CLK           RCC_AHB_PERIPH_GPIOB
#define  DEBUG_USART_TX_GPIO_PORT       CW_GPIOB   
#define  DEBUG_USART_TX_GPIO_PIN        GPIO_PIN_6
#define  DEBUG_USART_RX_GPIO_PORT       CW_GPIOB
#define  DEBUG_USART_RX_GPIO_PIN        GPIO_PIN_7

//GPIO AF
#define  DEBUG_USART_AFTX               PB06_AFx_UART3TXD()
#define  DEBUG_USART_AFRX               PB07_AFx_UART3RXD()



#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

	
/**
 * @brief 配置UART
 * 
 */
void UART_Configuration(void)
{
  USART_InitTypeDef USART_InitStructure;

	GPIO_InitTypeDef GPIO_InitStructure;

	//外设时钟使能
  RCC_AHBPeriphClk_Enable(DEBUG_USART_GPIO_CLK, ENABLE);
  DEBUG_USART_APBClkENx(DEBUG_USART_CLK, ENABLE);
	
  //UART TX RX 复用
  DEBUG_USART_AFTX;                     
  DEBUG_USART_AFRX;                     

  GPIO_InitStructure.Pins = DEBUG_USART_TX_GPIO_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
    
  GPIO_InitStructure.Pins = DEBUG_USART_RX_GPIO_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	
  USART_InitStructure.USART_BaudRate = DEBUG_USART_BaudRate;
  USART_InitStructure.USART_Over = USART_Over_16;
  USART_InitStructure.USART_Source = USART_Source_PCLK;
  USART_InitStructure.USART_UclkFreq = DEBUG_USART_UclkFreq;
  USART_InitStructure.USART_StartBit = USART_StartBit_FE;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No ;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(DEBUG_USARTx, &USART_InitStructure); 	
}

/**
 * @brief Retargets the C library printf function to the USART.
 * 
 */
PUTCHAR_PROTOTYPE
{
	
  USART_SendData_8bit(DEBUG_USARTx, (uint8_t)ch);

  while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);

  return ch;
}

/******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


void PowerOnDelay(void)
{
	unsigned int i;
		
	for(i=0;i<60000;i++);
	for(i=0;i<60000;i++);
	for(i=0;i<60000;i++);
	for(i=0;i<60000;i++);
	for(i=0;i<60000;i++);
	for(i=0;i<60000;i++);
	
		KKN=(MAXSPEED-MINSPEED);
	  KKN=KKN/(NMAXVD-NMINVD);
}

unsigned int hte=0;
int main()
{	
	unsigned char DZCount=0;	
  char temp_buff[100],temp_buff1[50];
	
//	unsigned char key_1=0;
	
	PowerOnDelay();
	RCC_Configuration(); //时钟配置
	UART_Configuration();
	GPIOInit(); //GPIO配置
	LEDON();		
	ADC_Configuration(); //AD配置
	PWMtimer_init();
	BTIM_init();		
	Halltimer_init();
				//printf("ADC[0]:%d ADC[1]:%d ADC[2]:%d ADC[3]:%d\r\n",SampleData[0],SampleData[1],SampleData[2],SampleData[3]);			

	PWM_AL_ON;
	PWM_BL_ON;
	PWM_CL_ON;
	TimeCountTemp=0;
	while(TimeCountTemp<50);
	TimeCountTemp=0;
	PWM_AL_OFF;
	PWM_BL_OFF;
	PWM_CL_OFF;	 		
	
//	I2C_init();			//OLED init
//	I2C_OLED_Init();	
//	I2C_OLED_Clear(1);
//	I2C_OLED_UPdata(); 
//	
	printf("Update %s %s\r\n",__DATE__,__TIME__);
	printf("ADC[0]:%d ADC[1]:%d ADC[2]:%d ADC[3]:%d\r\n",SampleData[0],SampleData[1],SampleData[2],SampleData[3]);			


	SampleVI();	//采集电压电流
	startflag=1;
	EnDirCheck();
	
	DIin=0x500;	//偏置电流设定 0.9V-1.1V中间，认为正确
	if(SampleData[1]>1117&&SampleData[1]<=1500)DIin=SampleData[1];	
	else printf("Current read err\r\n");
	if(SampleData[2]>3000|| SampleData[2]<700) printf("Speed read err\r\n");
	if(HALL_Check()==0|| HALL_Check()==7) printf("HALL Read Err\r\n");
	if(CanshuV<30) printf("Votage read err\r\n");
	sprintf(temp_buff1,"Set :%4d RPM  ",SetSpeed);  //输出显示占空比
	sprintf(temp_buff,"Real:%4d RPM  ",RealS);	//显示电机转速
	printf("%s\r\n",temp_buff);
	printf("%s\r\n",temp_buff1);
	sprintf(temp_buff1,"Vbus :%d.%d V  ",CanshuV/10,CanshuV%10);  //输出显示占空比
	sprintf(temp_buff,"I(MA):%d      ",CanshuI);	//显示电机转速
	printf("%s\r\n",temp_buff);
	printf("%s\r\n",temp_buff1);	
	GPIO_WritePin(VOUT_EN_GPIO_PORT,VOUT_EN_GPIO_PIN,GPIO_Pin_SET); //12V输出
	while(1)
	{		
			if(TimeCountCompuSpeed>20) //20MS采集一次速度设定值,并检查HALL是否有误
	       {
					 TimeCountCompuSpeed=0;
					 SampleSpeed();
					 HALL_Check();
	       }
				 
		 if(TimeCountVI>=200)//100MS计算一次电压电流,并作一次实时速度计算
		 {
			 	printf("ADC[0]:%d ADC[1]:%d ADC[2]:%d ADC[3]:%d\r\n",SampleData[0],SampleData[1],SampleData[2],SampleData[3]);			
        
			 TimeCountVI=0;
			 SampleVI();
			 			  
			 RealS=hte*50/MPolePairs;//HALLcount1*10*60/6/MPolePairs; 100MS存储一次霍尔边沿数		
			 
			 if(MOTORSTATE==STATESTARTPID||MOTORSTATE==STATERUNPID)
				 {
						if(RealS==0)
						{
							 DZCount++;
							 if(DZCount>=10)//2S保护
							 { 								
									DZCount=0;ErrorCode=7;//堵转
							 }
						}
						else DZCount=0;
					}			
		 }		
		
		  if(ErrorCode!=0&&MOTORSTATE!=STATEERROR&&MOTORSTATE!=STATEERROROVER)//发生故障
		   {  
				  MOTORSTATE=STATEERROR;
				  printf("ErrorCode=%d\r\n",ErrorCode);
				  GPIO_WritePin(VOUT_EN_GPIO_PORT,VOUT_EN_GPIO_PIN,GPIO_Pin_RESET); //12V输出
    	}		 				
	 

			if(TimeCountkey>=500) //500ms刷新显示
			{
				LEDTOG();
				TimeCountkey=0;
//									if(Menu==0)
//											{
				sprintf(temp_buff1,"Set :%4d RPM  ",SetSpeed);  //输出显示占空比
				sprintf(temp_buff,"Real:%4d RPM  ",RealS);	//显示电机转速
				printf("%s\r\n",temp_buff);
				printf("%s\r\n",temp_buff1);
//											}
//											else
//											{
				sprintf(temp_buff1,"Vbus :%d.%d V  ",CanshuV/10,CanshuV%10);  //输出显示占空比
				sprintf(temp_buff,"I(MA):%d      ",CanshuI);	//显示电机转速
//											}
				printf("%s\r\n",temp_buff);
				printf("%s\r\n",temp_buff1);
			//	printf("MOTORSTATE=%d\r\n",MOTORSTATE);
//				I2C_OLED_ShowString(0,0,temp_buff1);
//				I2C_OLED_ShowString(0,15,temp_buff);	
//				I2C_OLED_UPdata();
			}
			MotorBreak();
			EnDirCheck();
			
		//状态机	
		 switch(MOTORSTATE)
		 {
			 case STATESTARTCHECK:  
				    MotorStartCheck();			      
						break;
			 case STATESTARTPID:
						MotorStartPID();	
			      break;			
			 case STATERUNPID: 
						MotorRunPID();
						break;
			 case STATESTOP: MotorStop();break;
			 case STATEERROR: MotorError();break;
			 case STATEERROROVER: MotorErrorOver();break;
	   }			   			
	}
}


//1ms 定时器
void BTIM1_IRQHandler(void)
{	
  /* USER CODE BEGIN */
 if(BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV))
  {  //1MS timer
    BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV);		
		
		TimeCountTemp++;			
		TimeCountCompuSpeed++; //计算速度
		TimeCountRealSpd++; //瞬时速度
		if(TimeCountAvgSpd>=200){hte=HALLcount1;HALLcount1=0;TimeCountAvgSpd=0;}//用于显示的速度值
		if(TimeCountRealSpd>=20){HALLcountTemp=HALLcount;HALLcount=0;TimeCountRealSpd=0;}
	  TimeCountPID++; //PID
		TimeCountAvgSpd++;	//平均速度
		TimeCountVI++;//计算电压电流
		TimeCountkey++;
	}
  /* USER CODE END */
}


