#include "stm32f10x.h" #include #include #include "USART.h" #include "stm32f10x_it.h" #include "ENcoder.h" //系统时钟管理 void RCC_Configuration(void); //系统中断管理 void NVIC_Configuration(void); //通用IO口配置 void GPIO_Configuration(void); void DMA_Configuration(void); void AD1_Configuration(void); void TIM_Configuration(void); /***********************************************/ #define ADC1_DR_Address ((u32)0x4001244C) ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; vu16 ADCConvertedValue; /***********************************************/ u16 CCRX_Val = 100; //捕获/比较 寄存器初始值 /*************************************************/ //声明两个全局变量,此变量已经在外部C文件中定义和初始化了 extern s16 hRot_Speed; //平均速度(全局变量),注意:此变量在ENcoder.c中定义和初始化的 extern u16 hSpeedMeas_Timebase_500us; //定义计算速度时的采样最小时间(500us)/(9+1)*500US=10MS,注意:此变量在ENcoder.c中定义和初始化的 u16 count=10; s32 POS = 0 ; /************************************************************/ typedef struct PID { s16 setPoint; // 设定目标 Desired Value s16 LastValue; //每次的控制输出量 double Kp; // 比例常数 Proportional Const double Ki; // 积分常数 Integral Const double Kd; // 微分常数 Derivative Const s16 ek_1; // Error[-1] s16 ek_2; // Error[-2] s32 SumError; // Sums of Errors s16 dError; } PID; PID sPID; // PID Control Structure s16 rOUT; //PID cPID; //电流PID //s16 cOUT; //电流输出值 // PID pPID; //位置PID s16 pOUT; //位置输出值 /************************************************************/ typedef struct { s16 setpoint; s16 ek_1; //Error[-1] s16 ek_2; //Error[-2] }Fuzzy; Fuzzy sFUZZY; s16 fOUT; /*************************************************************/ s16 SetPoint; s16 p_SetPoint; s16 OUT; s16 mark=0; //配置系统时钟,使能各外设时钟 void RCC_Configuration(void) { ///******************** 使用内部时钟处理 程序************************************/ // RCC_DeInit(); //将外设RCC寄存器重设为缺省值 //// RCC_AdjustHSICalibrationValue(0); //内部时钟校准值 // RCC_HSICmd(ENABLE); //使能内部时钟 // while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET) {}//判断内部8MHz振荡器(内部时钟)是否就绪 // FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // /*预取指缓存使能 // FLASH_PrefetchBuffer用来选择FLASH预取指缓存的模式。 // 如果需关闭则使用FLASH_PrefetchBuffer_Disable // */ // FLASH_SetLatency(FLASH_Latency_2); // /*设置代码延时值 // FLASH_Latency用来设置FLASH存储器延时时钟周期数。 // FLASH_Latency_2 2为 延时周期 // 可以使用以下参数FLASH_Latency_0 0延时周期 // FLASH_Latency_1 1延时周期 // FLASH_Latency_2 2延时周期 // */ // RCC_HCLKConfig(RCC_SYSCLK_Div1); // /* // 设置AHB时钟(HCLK) // RCC_SYSCLK_Div1 // AHB时钟 = 系统时钟 // RCC_SYSCLK_Div2 // AHB时钟 = 系统时钟 / 2 // RCC_SYSCLK_Div4 // AHB时钟 = 系统时钟 / 4 // RCC_SYSCLK_Div8 // AHB时钟 = 系统时钟 / 8 // RCC_SYSCLK_Div16 // AHB时钟 = 系统时钟 / 16 // RCC_SYSCLK_Div64 // AHB时钟 = 系统时钟 / 64 // RCC_SYSCLK_Div128 // AHB时钟 = 系统时钟 / 128 // RCC_SYSCLK_Div256 // AHB时钟 = 系统时钟 / 256 // RCC_SYSCLK_Div512 // AHB时钟 = 系统时钟 / 512 // */ // RCC_PCLK2Config(RCC_HCLK_Div2); // /*设置高速AHB 时钟(PCLK2) // RCC_HCLK_Div2 APB1 时钟 = HCLK / 2 // RCC_HCLK_Div1 // APB2时钟 = HCLK // RCC_HCLK_Div2 // APB2时钟 = HCLK / 2 // RCC_HCLK_Div4 // APB2时钟 = HCLK / 4 // RCC_HCLK_Div8 // APB2时钟 = HCLK / 8 // RCC_HCLK_Div16 // APB2时钟 = HCLK / 16 // */ // RCC_PCLK1Config(RCC_HCLK_Div2); // /*设置低速 AHB 时钟(PCLK1) // RCC_HCLK_Div2 APB1 时钟 = HCLK / 2 // RCC_HCLK_Div1 // APB1时钟 = HCLK // RCC_HCLK_Div2 // APB1时钟 = HCLK / 2 // RCC_HCLK_Div4 // APB1时钟 = HCLK / 4 // RCC_HCLK_Div8 // APB1时钟 = HCLK / 8 // RCC_HCLK_Div16 // APB1时钟 = HCLK / 16用户可通过多个预分频器 // 配置AHB、高速APB(APB2)和低速APB(APB1)域 // 的频率。AHB和APB2域的最大频率是72MHZ? // PB1域的最大允许频率是36MHZ。 // SDIO接口的时钟频率固定为HCLK/2。 // RCC通过AHB时钟8分频后供给Cortex系统定时 // 器的(SysTick)外部时钟。通过对SysTick控制与状态寄 // 存器的设置,可选择上述时钟或Cortex AHB时钟 // 作为SysTick时钟。ADC时钟由高速APB2时钟经2、4、 // 6或8分频后获得。 // */ // RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16); // /* PLLCLK = 8MHz * 9 = 72 MHz // 设置 PLL 时钟源及倍频系数 // RCC_PLLSource 描述 // RCC_PLLSource_HSI_Div2 // PLL的输入时钟 = HSI时钟频率除以2 // RCC_PLLSource_HSE_Div1 // PLL的输入时钟 = HSE 时钟频率 // RCC_PLLSource_HSE_Div2 // PLL的输入时钟 = HSE 时钟频率除以2 // RCC_PLLMul // 描述 // RCC_PLLMul_2 PLL输入时钟 x 2 // RCC_PLLMul_3 PLL输入时钟 x 3 // RCC_PLLMul_4 PLL输入时钟 x 4 // RCC_PLLMul_5 PLL输入时钟 x 5 // RCC_PLLMul_6 PLL输入时钟 x 6 // RCC_PLLMul_7 PLL输入时钟 x 7 // RCC_PLLMul_8 PLL输入时钟 x 8 // RCC_PLLMul_9 PLL输入时钟 x 9 // RCC_PLLMul_10 PLL输入时钟 x 10 // RCC_PLLMul_11 PLL输入时钟 x 11 // RCC_PLLMul_12 PLL输入时钟 x 12 // RCC_PLLMul_13 PLL输入时钟 x 13 // RCC_PLLMul_14 PLL输入时钟 x 14 // RCC_PLLMul_15 PLL输入时钟 x 15 // RCC_PLLMul_16 PLL输入时钟 x 16 // 警告:必须正确设置软件, // 使PLL输出时钟频率不超过72 MHz // 当HSI被用于作为PLL时钟的输入时, // 系统时钟的最大频率不得超过64MHz。 */ // RCC_PLLCmd(ENABLE); //使能或者失能 PLL,关闭使用DISABLE // // while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}//等待指定的 RCC 标志位设置成功 等待PLL初始化成功 // /* // RCC_FLAG值 // RCC_FLAG 描述 // RCC_FLAG_HSIRDY HSI晶振就绪 // RCC_FLAG_HSERDY HSE晶振就绪 // RCC_FLAG_PLLRDY PLL就绪 // RCC_FLAG_LSERDY LSI晶振就绪 // RCC_FLAG_LSIRDY LSE晶振就绪 // RCC_FLAG_PINRST 管脚复位 // RCC_FLAG_PORRST POR/PDR复位 // RCC_FLAG_SFTRST 软件复位 // RCC_FLAG_IWDGRST IWDG复位 // RCC_FLAG_WWDGRST WWDG复位 // */ // RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // // /*设置系统时钟(SYSCLK) 设置PLL为系统时钟? // RCC_SYSCLKSource 描述 // RCC_SYSCLKSource_HSI 选择HSI作为系统时钟 // RCC_SYSCLKSource_HSE 选择HSE作为系统时钟 // RCC_SYSCLKSource_PLLCLK 选择PLL作为系统时钟 // */ // while(RCC_GetSYSCLKSource() != 0x08){}//* Wait till PLL is used as system clock source 等待校验成功*/ // /*等待PLL成功用作于系统时钟的时钟源 // 返回用作系统时钟的时钟源 // 0x00:HSI作为系统时钟 // 0x04:HSE作为系统时钟 // 0x08:PLL作为系统时钟 // */ // RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA // |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC // |RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1 // |RCC_APB2Periph_AFIO | RCC_APB2Periph_SPI1 // |RCC_APB2Periph_TIM1 // , ENABLE ); // // RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 |RCC_APB1Periph_TIM3 // |RCC_APB1Periph_TIM2 // , ENABLE ); // RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // /* // RCC_AHB2Periph 描述 // RCC_APB2Periph_AFIO 功能复用IO时钟 // RCC_APB2Periph_GPIOA GPIOA时钟 // RCC_APB2Periph_GPIOB GPIOB时钟 // RCC_APB2Periph_GPIOC GPIOC时钟 // RCC_APB2Periph_GPIOD GPIOD时钟 // RCC_APB2Periph_GPIOE GPIOE时钟 // RCC_APB2Periph_ADC1 ADC1时钟 // RCC_APB2Periph_ADC2 ADC2时钟 // RCC_APB2Periph_TIM1 TIM1时钟 // RCC_APB2Periph_SPI1 SPI1时钟 // RCC_APB2Periph_USART1 USART1时钟 // RCC_APB2Periph_ALL 全部APB2外设时钟 // */ ///*********************使用内部时钟处理 程序***********************************/ /**********外部时钟设置处理************************************************/ /* 这里是重置了RCC的设置,类似寄存器复位 */ RCC_DeInit(); /* 使能外部高速晶振 */ RCC_HSEConfig(RCC_HSE_ON); /* 等待高速晶振稳定 */ // HSEStartUpStatus = RCC_WaitForHSEStartUp(); if (RCC_WaitForHSEStartUp() == SUCCESS) { /* 使能flash预读取缓冲区 */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 令Flash处于等待状态,2是针对高频时钟的,这两句跟RCC没直接关系,可以暂且略过 */ FLASH_SetLatency(FLASH_Latency_2); /* HCLK = SYSCLK 设置高速总线时钟=系统时钟*/ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* PCLK2 = HCLK 设置低速总线2时钟=高速总线时钟*/ RCC_PCLK2Config(RCC_HCLK_Div1); /* PCLK1 = HCLK/2 设置低速总线1的时钟=高速时钟的二分频*/ RCC_PCLK1Config(RCC_HCLK_Div2); /* ADCCLK = PCLK2/6 设置ADC外设时钟=低速总线2时钟的六分频*/ RCC_ADCCLKConfig(RCC_PCLK2_Div6); /* Set PLL clock output to 72MHz using HSE (8MHz) as entry clock */ //上面这句例程中缺失了,但却很关键 /* 利用锁相环讲外部8Mhz晶振9倍频到72Mhz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* Enable PLL 使能锁相环*/ RCC_PLLCmd(ENABLE); /* Wait till PLL is ready 等待锁相环输出稳定*/ while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {} /* Select PLL as system clock source 将锁相环输出设置为系统时钟 */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* Wait till PLL is used as system clock source 等待校验成功*/ while (RCC_GetSYSCLKSource() != 0x08) {} } RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1 |RCC_APB2Periph_AFIO | RCC_APB2Periph_SPI1 |RCC_APB2Periph_TIM1 , ENABLE ); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 |RCC_APB1Periph_TIM3 |RCC_APB1Periph_TIM2 , ENABLE ); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* RCC_AHB2Periph 描述 RCC_APB2Periph_AFIO 功能复用IO时钟 RCC_APB2Periph_GPIOA GPIOA时钟 RCC_APB2Periph_GPIOB GPIOB时钟 RCC_APB2Periph_GPIOC GPIOC时钟 RCC_APB2Periph_GPIOD GPIOD时钟 RCC_APB2Periph_GPIOE GPIOE时钟 RCC_APB2Periph_ADC1 ADC1时钟 RCC_APB2Periph_ADC2 ADC2时钟 RCC_APB2Periph_TIM1 TIM1时钟 RCC_APB2Periph_SPI1 SPI1时钟 RCC_APB2Periph_USART1 USART1时钟 RCC_APB2Periph_ALL 全部APB2外设时钟 */ /**********外部时钟设置处理**************************************************/ } //void RCC_Configuration(void) //{ // //将外设 RCC寄存器重设为缺省值 // RCC_DeInit(); // RCC_HSICmd(ENABLE); // // // FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // FLASH_SetLatency(FLASH_Latency_2); // RCC_HCLKConfig(RCC_SYSCLK_Div1); // RCC_PCLK2Config(RCC_HCLK_Div1); // RCC_PCLK1Config(RCC_HCLK_Div2); // //设置 PLL 时钟源及倍频系数 // RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_9); // //使能或者失能 PLL,这个参数可以取:ENABLE或者DISABLE // RCC_PLLCmd(ENABLE);//如果PLL被用于系统时钟,那么它不能被失能 // //等待指定的 RCC 标志位设置成功 等待PLL初始化成功 // while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) // { // } // //设置系统时钟(SYSCLK) 设置PLL为系统时钟源 // RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // //等待PLL成功用作于系统时钟的时钟源 // // 0x00:HSI 作为系统时钟 // // 0x04:HSE作为系统时钟 // // 0x08:PLL作为系统时钟 // while(RCC_GetSYSCLKSource() != 0x08) // { // } // // RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA // |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC // |RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE // |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO // |RCC_APB2Periph_SPI1, ENABLE ); // // RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL ,ENABLE ); // RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 // |RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2 // , ENABLE ); // RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // //} //系统中断管理 void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the NVIC Preemption Priority Bits */ /* 第0组:所有4位用于指定响应优先级 第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级 第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级 第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级 第4组:所有4位用于指定抢占式优先级 NVIC_PriorityGroup_0 => 选择第0组 NVIC_PriorityGroup_1 => 选择第1组 NVIC_PriorityGroup_2 => 选择第2组 NVIC_PriorityGroup_3 => 选择第3组 NVIC_PriorityGroup_4 => 选择第4组 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); #ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else /* VECT_TAB_FLASH */ /* Set the Vector Table base location at 0x08000000 */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); #endif // /* Enable the USARTy Interrupt */ // NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //指定抢占式优先级别0 // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //指定响应优先级别1 // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // NVIC_Init(&NVIC_InitStructure); // NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; //DMA通道1传输完成中断 // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定抢占式优先级别0 // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定响应优先级别1 // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // NVIC_Init(&NVIC_InitStructure); /* Enable the TIM1 cc Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Enable the TIM2 gloabal Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定抢占式优先级别1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定响应优先级别1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_DeInit(GPIOA);GPIO_DeInit(GPIOB);GPIO_DeInit(GPIOC);//将外设 GPIOx 寄存器重设为缺省值 GPIO_AFIODeInit(); //将复用功能(重映射事件控制和 EXTI设置)重设为缺省值 GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//关闭JTAG-DP,关闭SW-DP。使调试的I/O作为普通I/O用。 GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); //定时器2完全映射,,通道1、2映射到PA15、PB3 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //定时器3部分从映射,通道1、2映射到PA4、PB5 //PB0 作为模拟通道7输入引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /******************************************************/ //配置编码器输入口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //QEI_A GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;//QEI_B,QEI_Z GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); /*****************************************************/ //PWM输出 /* Configure PA15 as alternate function push-pull */ // PWM3、PWM4 复用推挽输出,TIM4通道重映射后的Chanel 3、 Chanel 4; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Configure PB3 as alternate function push-pull */ // PWM1、PWM2 复用推挽输出,复用推挽输出,TIM1通道重映射后的Chanel 1、Chanel 4 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } void TIM_Configuration(void) { /*************************************************/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; // TIM_BDTRInitTypeDef TIM_BDTRInitStructure; //TIM1死去设置 /*************************************************/ /*TIM2作为编码器输入接口设置*/ TIM_DeInit(ENCODER_TIMER); //复位定时器 /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = ((4*ENCODER_PPR)-1); //设置编码周期 TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置时钟分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //采样频率Fdts=Fck_int,输入滤波器的采样频率=定时器时钟频率 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(ENCODER_TIMER, &TIM_TimeBaseStructure);// //编码器模式配置 TIM_EncoderInterfaceConfig(ENCODER_TIMER, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_ICStructInit(&TIM_ICInitStructure); //把TIM_ICInitStruct中的每一个参数按缺省值填入(相当于各个与输入配置相关的寄存器配置为初始值) TIM_ICInitStructure.TIM_ICFilter = 6; //输入捕获滤波系数 TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure); // Clear all pending interrupts TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update); //清中断,以免一启用中断后立即产生中断 TIM_ITConfig(ENCODER_TIMER, TIM_IT_Update, ENABLE); //使能TIM更新中断 //Reset counter ENCODER_TIMER->CNT = 0; //复位计数器的值 ENC_Clear_Speed_Buffer(); TIM_Cmd(ENCODER_TIMER, ENABLE); /*******************************************************************/ //TIM1基本计数器设置(设置PWM频率) //频率=TIM1_CLK/(ARR+1) TIM_TimeBaseStructure.TIM_Period = 200-1; //3000000/15k=200 TIM_TimeBaseStructure.TIM_Prescaler = 24-1; //72000000/24=3000000 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //启用ARR的影子寄存器(直到产生更新事件才更改设置) TIM_ARRPreloadConfig(TIM1, ENABLE); //使能ARR预装载缓冲器 //TIM1_OC1模块设置(设置1通道占空比) TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能--OCx信号连接到引脚 // TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = CCRX_Val; //设置初始占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //配置输出极性,OCx高电平有效(默认CCxP为0,高电有效) // TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OC1Init(TIM1, &TIM_OCInitStructure); //启用CCR1寄存器的影子寄存器(直到产生更新事件才更改设置) TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //捕获/比较预装载寄存器1使能 //TIM1_OC4模块设置(设置2通道占空比) TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能--OCx信号连接到引脚 // TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = CCRX_Val; //设置初始占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //配置输出极性,OCx低电平有效(默认CCxP为0,高电有效) // TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OC4Init(TIM1, &TIM_OCInitStructure); //启用CCR4寄存器的影子寄存器(直到产生更新事件才更改设置) TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable); //捕获/比较预装载寄存器4使能 /* //死区设置 TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime = 0x90; //这里调整死区大小0-0xff TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); */ /* TIM IT enable */ TIM_ITConfig(TIM1,TIM_IT_CC1|TIM_IT_CC4, ENABLE); //使能定时器捕获/比较中断通道1和4 //TIM1开启 TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); //TIM1_OC通道输出PWM(一定要加) /*******************************************************************/ /*TIM4 的输出通道1和4,通过重映射后输出极性相反(互补)的PWM波形*/ TIM_DeInit(TIM4); //复位定时器 /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = 899; //PWM周期为20K(18000K/900=20K) TIM_TimeBaseStructure.TIM_Prescaler = 4; //时钟分频系数32,所以定时器时钟为72000000/4=18000K TIM_TimeBaseStructure.TIM_ClockDivision = 0; // TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // TIM_ARRPreloadConfig(TIM4, ENABLE); //使能ARR预装载缓冲器 /* PWM1 Mode configuration: Channel3 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能--OCx信号连接到引脚 TIM_OCInitStructure.TIM_Pulse = 200; //设置初始占空比 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; //配置输出极性,OCx高电平有效(默认CCxP为0,高电有效) TIM_OC3Init(TIM4, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable); //捕获/比较预装载寄存器1使能 /*引脚输出状态 OCx = OCxREF + 极性(CCxP)*/ /* PWM1 Mode configuration: Channel4 */ TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能--OCx信号连接到引脚 TIM_OCInitStructure.TIM_Pulse = 200; //设置初始占空比 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low; //配置输出极性,OCx低电平有效(默认CCxP为0,高电有效) TIM_OC4Init(TIM4, &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable); //捕获/比较预装载寄存器2使能 /*引脚输出状态 OCx = OCxREF + 极性(CCxP)*/ /* TIM IT enable */ TIM_ITConfig(TIM4,TIM_IT_CC3|TIM_IT_CC4, ENABLE); //使能定时器捕获/比较中断通道1和2 /* TIM enable counter */ TIM_Cmd(TIM4, ENABLE); } void DMA_Configuration(void) { /*DMA1 channel1 configuration ----------------------------------------------*/ DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //源地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADCConvertedValue; //目的地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不变(非递增模式) DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //内存地址不变(非递增模式) DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//设定了外设数据宽度 为16 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //设定了内存数据宽度为16 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式开启,Buffer写满后,自动回到初始地址开始传输 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道x拥有高优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x设置为非内存到内存传输 DMA_Init(DMA1_Channel1, &DMA_InitStructure); // DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE); /* Enable DMA1 channel1 */ DMA_Cmd(DMA1_Channel1, ENABLE); } void AD1_Configuration(void) { /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //工作在独立模式还是多AD模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; //工作在扫描模式(多通道)还是单次(单通道)模式 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //工作在连续还是单次模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //是否使用外部触发AD转换 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC 数据向左边对齐还是向右边对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的 ADC 通道的数目,这个数目的取值范围是 1 到16 ADC_Init(ADC1, &ADC_InitStructure); /* ADC1 regular channel8 configuration */ //设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间 ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_7Cycles5); /* Enable ADC1 DMA */ ADC_DMACmd(ADC1, ENABLE); //使能或者失能指定的 ADC 的 DMA请求 /* Enable ADC1 */ ADC_Cmd(ADC1, ENABLE); //使能或者失能指定的 ADC /* Enable ADC1 reset calibaration register */ ADC_ResetCalibration(ADC1); //重置指定的 ADC 的校准寄存器 /* Check the end of ADC1 reset calibration register */ while(ADC_GetResetCalibrationStatus(ADC1)); //获取 ADC 重置校准寄存器的状态,是否校准完成 /* Start ADC1 calibaration */ ADC_StartCalibration(ADC1); //开始指定 ADC 的校准状态 /* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(ADC1)); //获取指定 ADC 的校准程序 /* Start ADC1 Software Conversion */ ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能或者失能指定的 ADC 的软件转换启动功能 } /*==================================================================================================== Initialize PID Structure =====================================================================================================*/ void PIDInit (PID *pp) { memset ( pp,0,sizeof(PID)); } /**********************************************************/ /*输入量P语言值特征点*/ const s16 PFF[4]={0,30,60,90}; //偏差输入值范围 /*输入量D语言值特征点*/ const s16 DFF[4]={0,15,30,45}; //偏差微分输入范围 /*输出量U语言值特征点*/ const s16 UFF[7]={0,15,30,45,60,75,90}; //输出范围 /*采用了调整因子的规则表,大误差时偏重误差,小误差时偏重误差变化*/ /*a0=0.3,a1=0.55,a2=0.74,a3=0.89 */ const s16 rule[7][7]={ //误差变化率 -3,-2,-1, 0, 1, 2, 3 // 误差 {-6,-6,-6,-5,-5,-5,-4,}, // -3 {-5,-4,-4,-3,-2,-2,-1,}, // -2 {-4,-3,-2,-1, 0, 1, 2,}, // -1 {-4,-3,-1, 0, 1, 3, 4,}, // 0 {-2,-1, 0, 1, 2, 3, 4,}, // 1 { 1, 2, 2, 3, 4, 4, 5,}, // 2 { 4, 5, 5, 5, 6, 6, 6}}; // 3 /**********************************************************/ s16 FuzzyCale(s16 P,s16 D) /*模糊运算引擎,输入偏差和偏差微分*/ { #define PMAX 100 //偏差正最大值 #define PMIN -100 //偏差负最大值 #define DMAX 100 //偏差微分正最大值 #define DMIN -100 //偏差微分负最大值 #define FMAX 100 /*输出语言值的满幅值*/ s16 U; /*偏差,偏差微分以及输出值的精确量*/ u16 PF[2],DF[2],UF[4]; /*偏差,偏差微分以及输出值的隶属度*/ s16 Pn,Dn,Un[4]; //分区参数 s32 temp1,temp2; /*隶属度的确定*/ /*根据P,D的指定语言值获得有效隶属度*/ if(P>-PFF[3] && P=PFF[3]) {Pn=3; PF[0]=0;} PF[1]=FMAX-PF[0]; //这个为低一级隶属度 if(D>-DFF[3] && D=DFF[3]) {Dn=3; DF[0]=0;} DF[1]=FMAX-DF[0]; //这个为低一级隶属度 /*使用误差范围优化后的规则表rule[7][7]*/ /*输出值使用13个隶属函数,中心值由UFF[7]指定*/ /*一般都是四个规则有效*/ Un[0]=rule[Pn-1+3][Dn-1+3]; Un[1]=rule[Pn+3][Dn-1+3]; Un[2]=rule[Pn-1+3][Dn+3]; Un[3]=rule[Pn+3][Dn+3]; if(PF[0]<=DF[0])UF[0]=PF[0]; else UF[0]=DF[0]; if(PF[1]<=DF[0])UF[1]=PF[1]; else UF[1]=DF[0]; if(PF[0]<=DF[1])UF[2]=PF[0]; else UF[2]=DF[1]; if(PF[1]<=DF[1])UF[3]=PF[1]; else UF[3]=DF[1]; /*同隶属函数 输出语言值求大*/ { if(Un[0]==Un[1]) { if(UF[0]>UF[1])UF[1]=0; else UF[0]=0; } if(Un[0]==Un[2]) { if(UF[0]>UF[2])UF[2]=0; else UF[0]=0; } if(Un[0]==Un[3]) { if(UF[0]>UF[3])UF[3]=0; else UF[0]=0; } if(Un[1]==Un[2]) { if(UF[1]>UF[2])UF[2]=0; else UF[1]=0; } if(Un[1]==Un[3]) { if(UF[1]>UF[3])UF[3]=0; else UF[1]=0; } if(Un[2]==Un[3]) { if(UF[2]>UF[3])UF[3]=0; else UF[2]=0; } } /*重心法反模糊*/ //加权平均算法 {/*Un[]原值为输出隶属函数标号,转换为隶属函数值*/ if(Un[0]>=0)Un[0]=UFF[Un[0]];else Un[0]=-UFF[-Un[0]]; if(Un[1]>=0)Un[1]=UFF[Un[1]];else Un[1]=-UFF[-Un[1]]; if(Un[2]>=0)Un[2]=UFF[Un[2]];else Un[2]=-UFF[-Un[2]]; if(Un[3]>=0)Un[3]=UFF[Un[3]];else Un[3]=-UFF[-Un[3]]; } temp1=UF[0]*Un[0]+UF[1]*Un[1]+UF[2]*Un[2]+UF[3]*Un[3]; temp2=UF[0]+UF[1]+UF[2]+UF[3]; U=temp1/temp2; return U; } s16 FuzzyControl(Fuzzy *Fuzzy,s16 NextPoint) { s16 ek,eck; s16 temp1; ek = SetPoint - NextPoint; //得到误差值 eck = ek - Fuzzy->ek_1; //得到误差变化值 temp1 = FuzzyCale(ek,eck); //Fuzzy->ek_2 = Fuzzy->ek_1; Fuzzy->ek_1 = ek; //更新两次误差值,备下次计算误差变化使用; return temp1 ; } s16 Fuzzy_Pid(PID* pid,Fuzzy *Fuzzy,s16 NextPoint) { s16 dError1,dError2, Error; s16 ek; s16 temp1; s16 dU; ek = SetPoint - NextPoint; if( ek>=-40 && ek<=40 ) //小误差使用PID 控制 ,位置式控制 { mark = 1; Error = SetPoint - NextPoint; // 偏差 pid->SumError += Error; // 积分 dError1 = pid->ek_1 - pid->ek_2; // 当前微分 pid->ek_2 = pid->ek_1; pid->ek_1 = Error; temp1 = pid->Kp * Error // 比例项 + pid->Ki * (pid->SumError/2) // 积分项 + pid->Kd * dError1 ; // 微分项 if ( temp1 >= 200) temp1 = 190 ; //限幅输出 if ( temp1 <= -200) temp1 = -190; temp1 /=2; // mark = 1; // Error = SetPoint - NextPoint; //求偏差 // // dError1 = Error - pid->ek_1; //偏差变化值 // dError2 = pid->ek_1 - pid->ek_2; // // if((pid->LastValue >= 300 && Error > 0)||(pid->LastValue <= -300 && Error < 0)) //积分分离 // { // dU = ( (s16)( pid->Kp * (Error - pid->ek_1) + pid->Kd * (dError1 - dError2) ) )>>2; // } // // dU = ( (s16)( pid->Kp * (Error - pid->ek_1) + pid->Ki * Error + pid->Kd * (dError1 - dError2) ) )>>2; // // pid->ek_2 = pid->ek_1; //更新误差 // pid->ek_1 = Error; // // temp1 = dU + pid->LastValue; // pid->LastValue = temp1; // // if ( temp1 >= 200) temp1 = 190 ; //限幅输出 // if ( temp1 <= -200) temp1 = -190; // // temp1 /=2; } else //大误差使用模糊控制 { mark = 2; temp1 = FuzzyControl(Fuzzy,NextPoint); } return temp1; } s16 position_PID_Calc( PID *p ,s16 NextPoint) //位置环 { s16 ek; s16 tmpValue; s16 deltaValue = 0; //每次增量都要清零,从新计算 ek = p_SetPoint - NextPoint; // 本次误差 = 参考值 - 反馈值 // 将PID公式离散化后,采用增量式PID控制,更新电机控制输出值 // 遇限削弱积分法,如果进入饱和区,并且积分增加,则不进行积分运算,尽快离开饱和。 // 增量的范围(0~200)*(12+10+10)=64000)线性转换为(0~200),移位数, 在4~7之间为好 if ( ( p->LastValue >=99 && ek>0 ) || ( p->LastValue <= -99 && ek<0 )) //进入饱和区则不再进行积分运算 deltaValue = ((s16)( p->Kp * (ek - p->ek_1) + p->Kd * ( (ek - p->ek_1) - (p->ek_1 - p->ek_2) )))>>6 ; else//不在饱和区,则按正常离散的PID公式计算 deltaValue = ((s16)( p->Kp * (ek - p->ek_1) + p->Ki * ek + p->Kd * ( (ek - p->ek_1) - (p->ek_1 - p->ek_2) )))>>6; // 更新前两次误差 p->ek_2 = p->ek_1; p->ek_1 = ek; tmpValue = p->LastValue + deltaValue; //上一次的控制量+本次计算所得的增量=本次输出控制量。 p->LastValue = tmpValue; //保存这次计算结果,供后面一次使用。 // 返回值 if ( tmpValue >= 99) return 99; if ( tmpValue <= -99) return -99; else return tmpValue; } int main(void) { int i = 1000000; RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); USART1_Configuration(); DMA_Configuration(); AD1_Configuration(); TIM_Configuration(); SysTick_Init(); PIDInit ( &sPID ); // Initialize Structure sPID.Kp = 2.0; // Set PID Coefficients sPID.Ki = 0.6; sPID.Kd = 0.0; sPID.LastValue = 0; SetPoint = -1; //////////////////////////////////// PIDInit ( &pPID ); // Initialize Structure pPID.Kp = 400.0; // Set PID Coefficients pPID.Ki = 3.0; pPID.Kd = 1.0; pPID.LastValue = 0; // 速度为零 p_SetPoint = 10; ////////////////////////////////////// for (;;) { while(i--); i = 1000000; } } void TIM1_CC_IRQHandler(void) { if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET) //中断判断 { TIM_ClearITPendingBit(TIM1, TIM_IT_CC1); //清除中断标志位 TIM_SetCompare1(TIM1,CCRX_Val); } if (TIM_GetITStatus(TIM1, TIM_IT_CC4) != RESET) //中断判断 { TIM_ClearITPendingBit(TIM1, TIM_IT_CC4); //中断判断 TIM_SetCompare4(TIM1,CCRX_Val); } } void SysTick_Handler(void) { if (hSpeedMeas_Timebase_500us !=0) { hSpeedMeas_Timebase_500us--; } else { hSpeedMeas_Timebase_500us = SPEED_SAMPLING_TIME;//速度采样时间 ENC_Calc_Average_Speed(); // rOUT = speed_PID_Calc(&sPID,hRot_Speed); // PID // fOUT = -FuzzyControl(&sFUZZY,hRot_Speed); // fuzzy控制 OUT = -Fuzzy_Pid(&sPID,&sFUZZY,hRot_Speed); // fuzzy控制 // CCRX_Val = (fOUT/2)+100 ; // 改变占空比 // CCRX_Val = fOUT+100 ; // 改变占空比 CCRX_Val = OUT+100 ; //////////////////////////////////////////////////////////////////////// if(count != 0 ) //10hz { POS += hRot_Speed; //速度积分为位置 count--; } else { count = 10; pOUT = position_PID_Calc(&pPID,POS/600); SetPoint = pOUT; //位置环的输出作为速度环的输入 printf("%04d \r\n",POS/600); } //////////////////////////////////////////////////////////////////////// // CCRX_Val = 150 ; // printf("rOUT=%04d hRot_Speed=%04d CCRX_Val=%04d\r\n",rOUT,hRot_Speed,CCRX_Val); printf("%04d %04d %04d %04d\r\n",mark,OUT,hRot_Speed,CCRX_Val); //printf("%04d \r\n",hRot_Speed); } }