|
用到了編碼器,步進電機,含pid的調(diào)節(jié),與大家分享!
所有資料51hei提供下載:
倒立擺調(diào)試-全部成功.rar
(317.32 KB, 下載次數(shù): 83)
2017-8-10 23:33 上傳
點擊文件名下載附件
簡易倒立擺的調(diào)試
單片機源程序如下:
- /********************************************************
-
- 說明:本工程模板包含MPU6050,OLED,TIM2作為定時器使用時間片,
- TIM3作4路PWM輸出并計算輸出的脈沖個數(shù),使用PC15作為LED,
- 使用PE1,PE2,PE3,PE4做外部中斷的按鍵輸入。
-
- 作者:汕頭大學(xué)電子系max團隊
- ********************************************************/
- #include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "math.h"
- #include "led.h" //LED:PC15
- #include "TIM4.h" //PB6和PB7為編碼器通道
- #include "TIM2.h" //定時器2作為時間片
- #include "pwm.h" //定時器3做PWM輸出,并計算輸出脈沖個數(shù);PB0,PB1,PA6,PA7
- //#include "OLED_I2C.h" //SCL:PB10 SDA:PB11
- #include "delay_1.h"
- #include "key.h" //按鍵:PE1,PE2,PE3,PE4
- #include "ADC.h" //AD1:通道1 PC0
- #include "DMA.h"
- #define N 10
- float Kp = 160;
- float Kd = 5;
- float Ki = 1.2;
- float Kp_b = 0; //編碼器Kp
- float Ki_b = 0; //編碼器Kd
- int Go = 0.0;
- float err = 0;
- float jifen_shangxian = 1000; //積分限幅
- float Ju_Li_Max = 10000; //積分限幅
- // ADC1轉(zhuǎn)換的電壓值通過MDA方式傳到SRAM
- extern __IO uint16_t ADC_ConvertedValue;
- // 局部變量,用于保存轉(zhuǎn)換計算后的電壓值
- float ADC_ConvertedValueLocal,Angle,Angle_err,Angle_Last,Angle_jifen;
- extern uint8_t SendBuff[SIZE];
- int PWM_OUT = 0,PWM_WEIYI ,PWM_ANGLE;
- u8 time = 2; //定時器2計?
- int Time_EN = 500;
- int Time_Go = 0;
- int Time_D = 10;
- u8 Key_Flag = 0;//按鍵返回1234
- int Count_TIM4 ; //脈沖數(shù)取值
- int Wei_Yi; //更新脈沖數(shù)
- int Wei_Yi_Last = 0;//上一次的位移數(shù)值
- int Speed; //電機的速度
- int Ju_Li = 0;//速度的積分
- int Wei_Yi_flag=0;
- int ZhouQi = 0;
- u8 i = 0,j = 0;
- float Lvbo[N] = {0};
- int Mode1_Flag = 0,Mode4_Flag = 0;
- /***************DMA打印函數(shù)****************/
- /****
- shu1:3位,shu2:5位,shu3:3位,shu4:4位,shu5:9位
- *****/
- void DMA_Send(int start,int Shu1,int Shu2 ,int Shu3,int Shu4,int Shu5) //start:數(shù)組的起始位置 shu:變量
- {
- if(Shu1 < 0)
- {
- Shu1 = -Shu1;
- SendBuff[start] = '-';
- SendBuff[start+1] = Shu1/100 + 0x30;
- SendBuff[start+2] = Shu1%100/10 + 0x30;
- SendBuff[start+3] = Shu1%10 + 0x30;
- SendBuff[start+4] = ' ';
- }
- else
- {
- SendBuff[start] = '+';
- SendBuff[start+1] = Shu1/100 + 0x30;
- SendBuff[start+2] = Shu1%100/10 + 0x30;
- SendBuff[start+3] = Shu1%10 + 0x30;
- SendBuff[start+4] = ' ';
- }
- if(Shu2<0)
- {
- Shu2 = -Shu2;
- SendBuff[start+5] = '-';
- SendBuff[start+6] = Shu2/10000 + 0x30;
- SendBuff[start+7] = Shu2%10000/1000 + 0x30;
- SendBuff[start+8] = Shu2%1000/100 + 0x30;
- SendBuff[start+9] = Shu2%100/10 + 0x30;
- SendBuff[start+10] = Shu2%10 + 0x30;
- SendBuff[start+11] = ' ';
- }
- else
- {
- SendBuff[start+5] = '+';
- SendBuff[start+6] = Shu2/10000 + 0x30;
- SendBuff[start+7] = Shu2%10000/1000 + 0x30;
- SendBuff[start+8] = Shu2%1000/100 + 0x30;
- SendBuff[start+9] = Shu2%100/10 + 0x30;
- SendBuff[start+10] = Shu2%10 + 0x30;
- SendBuff[start+11] = ' ';
- }
-
- if(Shu3 < 0)
- {
- Shu3 = -Shu3;
- SendBuff[start+12] = '-';
- SendBuff[start+13] = Shu3/100 + 0x30;
- SendBuff[start+14] = Shu3%100/10 + 0x30;
- SendBuff[start+15] = Shu3%10 + 0x30;
- SendBuff[start+16] = ' ';
- }
- else
- {
- SendBuff[start+12] = '+';
- SendBuff[start+13] = Shu3/100 + 0x30;
- SendBuff[start+14] = Shu3%100/10 + 0x30;
- SendBuff[start+15] = Shu3%10 + 0x30;
- SendBuff[start+16] = ' ';
- }
-
- if(Shu4 < 0)
- {
- Shu4 = -Shu4;
- SendBuff[start+17] = '-';
- SendBuff[start+18] = Shu4/1000 + 0x30;
- SendBuff[start+19] = Shu4%1000/100 + 0x30;
- SendBuff[start+20] = Shu4%100/10 + 0x30;
- SendBuff[start+21] = Shu4%10 + 0x30;
- SendBuff[start+22] = ' ';
- }
- else
- {
- SendBuff[start+17] = '+';
- SendBuff[start+18] = Shu4/1000 + 0x30;
- SendBuff[start+19] = Shu4%1000/100 + 0x30;
- SendBuff[start+20] = Shu4%100/10 + 0x30;
- SendBuff[start+21] = Shu4%10 + 0x30;
- SendBuff[start+22] = ' ';
- }
- if(Shu5 < 0)
- {
- Shu5 = -Shu5;
- SendBuff[start+23] = '-';
- SendBuff[start+24] = Shu5/100000000 + 0x30;
- SendBuff[start+25] = Shu5%100000000/10000000 + 0x30;
- SendBuff[start+26] = Shu5%10000000/1000000 + 0x30;
- SendBuff[start+27] = Shu5%1000000/100000 + 0x30;
- SendBuff[start+28] = Shu5%100000/10000 + 0x30;
- SendBuff[start+29] = Shu5%10000/1000 + 0x30;
- SendBuff[start+30] = Shu5%1000/100 + 0x30;
- SendBuff[start+31] = Shu5%100/10 + 0x30;
- SendBuff[start+32] = Shu5%10 + 0x30;
- SendBuff[start+33] = ' ';
- }
- else
- {
- SendBuff[start+23] = '+';
- SendBuff[start+24] = Shu5/100000000 + 0x30;
- SendBuff[start+25] = Shu5%100000000/10000000 + 0x30;
- SendBuff[start+26] = Shu5%10000000/1000000 + 0x30;
- SendBuff[start+27] = Shu5%1000000/100000 + 0x30;
- SendBuff[start+28] = Shu5%100000/10000 + 0x30;
- SendBuff[start+29] = Shu5%10000/1000 + 0x30;
- SendBuff[start+30] = Shu5%1000/100 + 0x30;
- SendBuff[start+31] = Shu5%100/10 + 0x30;
- SendBuff[start+32] = Shu5%10 + 0x30;
- SendBuff[start+33] = ' ';
- }
-
- SendBuff[start+34]= '\n';
- }
- /*************電機控制:正轉(zhuǎn)***************/
- void Motor_Zheng(int pwm)
- {
- TIM_SetCompare1(TIM3,pwm);
- GPIO_ResetBits(GPIOC, GPIO_Pin_4);
- }
- /*************電機控制:反轉(zhuǎn)**************/
- void Motor_Fan(int pwm)
- {
- TIM_SetCompare1(TIM3,1000-pwm);
- GPIO_SetBits(GPIOC, GPIO_Pin_4);
- }
- int main(void)
- {
- // u8 i = 0,j = 0;
- delay_init(); //延時函數(shù)初始化
- NVIC_Configuration(); //設(shè)置NVIC中斷分組2:2位搶占優(yōu)先級,2位響應(yīng)優(yōu)先級
- uart_init(115200); //串口初始化為9600
-
- printf("***********************\r\n");
- USART1_DMA_Config();
- LED_GPIO_Config(); //LED初始化 :PC15
- TIM2_Init(); //定時器2初始化
- TIM3_PWM_Init();//定時器3PWM輸出初始化
- Time4_Config(); //TIM4編碼器模式
- ADC1_Init(); //AD初始化 PC0
- /*****************按鍵初始化****************/
- KEY_Init();//IO初始化
- EXTIX_Init();//外部中斷初始化
-
- printf("111111111111111111111111\r\n");
-
- printf("333333333333333333333333333\r\n");
- USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //串口1的DMA使能
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); //開啟定時器TIM2
-
- TIM_SetCounter(TIM4, 5050); //TIM4編碼器計數(shù)初始值
-
- while(1)
- {
- Count_TIM4 = (TIM4 -> CNT) - 5050; //定時器4脈沖計數(shù),編碼器輸入,初始為5500
-
- Wei_Yi = 5000*ZhouQi + Count_TIM4; //就算出位移
-
-
- if((TIM4 -> CNT) >= 10050)
- {
- (TIM4 -> CNT) = 5050;
- ZhouQi ++; //轉(zhuǎn)的圈數(shù)++
- }
- else if((TIM4 -> CNT) <= 50)
- {
- (TIM4 -> CNT) = 5050;
- ZhouQi--; //轉(zhuǎn)的圈數(shù)--
- }
-
- /********遞推均值濾波********/
- Lvbo[i++] =(ADC_ConvertedValue - 2048)*0.0879 + err; // 讀取轉(zhuǎn)換的AD值(int)
- if(i == N)
- {
- i = 0;
- }
-
- for(j = 0;j<N;j++)
- {
- ADC_ConvertedValueLocal = ADC_ConvertedValueLocal + Lvbo[j];
- }
-
- /*****按鍵4按下后給偏移角Go,其他狀態(tài)不要偏移*********/
- if(Key_Flag != 4)
- {
- Angle = ADC_ConvertedValueLocal /10;
- }
- else
- {
- Angle = ADC_ConvertedValueLocal /10+Go;
- }
- ADC_ConvertedValueLocal = 0;
-
- /**********狀態(tài)0關(guān)閉電機*******/
- if(Key_Flag ==0)
- {
- GPIO_ResetBits(GPIOC, GPIO_Pin_5);
- }
- else if(Key_Flag == 1) //按鍵1,基本題第一二題,完成圓周運動
- {
- GPIO_SetBits(GPIOC, GPIO_Pin_5);
- switch(Mode1_Flag)
- {
- case 0:{Motor_Zheng(800);}break;
- case 1:{Motor_Fan(900);}break;
- case 2:{Motor_Zheng(950);}break;
- case 3:{Motor_Fan(950);}break;
- case 4:{Motor_Zheng(800);}break;
- case 5:{Motor_Zheng(0);Key_Flag =0;}break;
- }
- }
-
-
- else if(Key_Flag == 3) //按鍵3,擺擺動至+-35度進入狀態(tài)6,進行PID調(diào)節(jié)
- {
- GPIO_SetBits(GPIOC, GPIO_Pin_5);
- switch(Mode1_Flag)
- {
- case 0:{Motor_Zheng(800);}break;
- case 1:{Motor_Fan(900);}break;
- case 2:{Motor_Zheng(180);}break; //200
- case 3:{
- Motor_Zheng(0);
- if(Angle>-35&& Angle<35)
- {
- Key_Flag = 6;
- }
- else
- {
- Key_Flag =0;
- }
- }break;
- }
- }
- LED1_TOGGLE ;
- DMA_Send(0,Angle,Count_TIM4,Angle_err,Speed,Ju_Li);//Angle_jifen
- LED1_TOGGLE ;
- }
- }
- /*******************中斷函數(shù)*******************/
- void TIM2_IRQHandler(void)
- {
- if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
- {
- time--;
-
- if(time <= 0)
- {
- time = 2;
- if(Key_Flag == 2) //狀態(tài)2的PID控制
- {
- Angle_err = Angle-Angle_Last;
-
- Angle_Last = Angle;
-
- Speed = Wei_Yi - Wei_Yi_Last;
-
- Wei_Yi_Last = Wei_Yi;
-
- Ju_Li += Speed;
- if(Ju_Li > Ju_Li_Max)
- {
- Ju_Li = Ju_Li_Max ;
- }
- if(Ju_Li < -Ju_Li_Max)
- {
- Ju_Li = -Ju_Li_Max ;
- }
-
-
- PWM_WEIYI = -Speed*Kp_b -Ju_Li*Ki_b ;
-
- PWM_ANGLE = (Angle)*Kp + Angle_err*Kd;
-
- PWM_OUT = PWM_ANGLE + PWM_WEIYI;
-
- if(PWM_OUT < 0)
- {
- if(PWM_OUT<=-1000)
- {
- PWM_OUT=-1000;
- }
- Motor_Zheng(-PWM_OUT);
- }
- else
- {
- if(PWM_OUT>=1000)
- {
- PWM_OUT=1000;
- }
- Motor_Fan(PWM_OUT);
- }
- if(Angle >= 45 || Angle <=-45)
- {
- GPIO_ResetBits(GPIOC, GPIO_Pin_5);
- Motor_Fan(0);
- Key_Flag = 0;
- PWM_OUT = 0;
- Angle_jifen=0;
- Wei_Yi_flag=0;
- }
- }
-
- if(Key_Flag == 6) //狀態(tài)6的PID控制,和狀態(tài)2一樣,可以適當(dāng)微調(diào)
- {
- Angle_err = Angle-Angle_Last;
-
- Angle_Last = Angle;
-
- Speed = Wei_Yi - Wei_Yi_Last;
-
- Wei_Yi_Last = Wei_Yi;
-
- Ju_Li += Speed;
- if(Ju_Li > Ju_Li_Max)
- {
- Ju_Li = Ju_Li_Max ;
- }
- if(Ju_Li < -Ju_Li_Max)
- {
- Ju_Li = -Ju_Li_Max ;
- }
-
-
- PWM_WEIYI = -Speed*Kp_b -Ju_Li*Ki_b ;
-
- PWM_ANGLE = (Angle)*Kp + Angle_err*Kd;
-
- PWM_OUT = PWM_ANGLE + PWM_WEIYI;
-
- if(PWM_OUT < 0)
- {
- if(PWM_OUT<=-1000)
- {
- PWM_OUT=-1000;
- }
- Motor_Zheng(-PWM_OUT);
- }
- else
- {
- if(PWM_OUT>=1000)
- {
- PWM_OUT=1000;
- }
- Motor_Fan(PWM_OUT);
- }
- if(Angle >= 45 || Angle <=-45)
- {
- GPIO_ResetBits(GPIOC, GPIO_Pin_5);
- Motor_Fan(0);
- Key_Flag = 0;
- PWM_OUT = 0;
- Angle_jifen=0;
- Wei_Yi_flag=0;
- }
- }
-
-
- if(Key_Flag == 4) //狀態(tài)4:給一個偏移角后進行同樣的PID控制,系統(tǒng)會往偏移方向擺動
- {
- Angle_err = Angle-Angle_Last;
-
- Angle_Last = Angle;
-
- Speed = Wei_Yi - Wei_Yi_Last;
-
- Wei_Yi_Last = Wei_Yi;
-
- Ju_Li += Speed;
- if(Ju_Li > Ju_Li_Max)
- {
- Ju_Li = Ju_Li_Max ;
- }
- if(Ju_Li < -Ju_Li_Max)
- {
- Ju_Li = -Ju_Li_Max ;
- }
-
-
- PWM_WEIYI = -Speed*Kp_b -Ju_Li*Ki_b ;
-
- PWM_ANGLE = (Angle)*Kp + Angle_err*Kd;
-
- PWM_OUT = PWM_ANGLE + PWM_WEIYI;
-
- if(PWM_OUT < 0)
- {
- if(PWM_OUT<=-1000)
- {
- PWM_OUT=-1000;
- }
- Motor_Zheng(-PWM_OUT);
- }
- else
- {
- if(PWM_OUT>=1000)
- {
- PWM_OUT=1000;
- }
- Motor_Fan(PWM_OUT);
- }
- if(Angle >= 45 || Angle <=-45)
- {
- GPIO_ResetBits(GPIOC, GPIO_Pin_5);
- Motor_Fan(0);
- Key_Flag = 0;
- PWM_OUT = 0;
- Angle_jifen=0;
- Wei_Yi_flag=0;
- }
- }
-
- }
- if(Key_Flag == 1) //按鍵1按下后,控制擺動的時間
- {
- Time_EN --;
- if(Time_EN <=0 && Mode1_Flag <5)
- {
- Time_EN =500;
- Mode1_Flag ++;
- if(Mode1_Flag >= 5)
- {
- Mode1_Flag = 5;
- }
- }
- }
-
- if(Key_Flag == 3)
- {
- Time_EN --;
- if(Time_EN <=0 && Mode1_Flag <3)
- {
- Time_EN =500;
- Mode1_Flag ++;
- if(Mode1_Flag >= 3)
- {
- Mode1_Flag = 3;
- }
- }
- }
-
- if(Key_Flag == 4)
- {
- Time_Go--;
- if(Time_Go <= 0)
- {
- Time_Go = 0;
- Go = 0;
- Key_Flag = 2;
- }
- }
- TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
- }
- }
- //外部中斷0服務(wù)程序
- void EXTI1_IRQHandler(void)
- {
- delay_ms(10);//消抖
-
- if(KEY3==1) //WK_UP按鍵1
- {
- Key_Flag = 1;
- Time_EN = 500;
- Mode1_Flag = 0;
- }
- EXTI_ClearITPendingBit(EXTI_Line1); //清除LINE0上的中斷標(biāo)志位
- }
-
- //外部中斷2服務(wù)程序
- void EXTI2_IRQHandler(void)
- {
- delay_ms(10);//消抖
- if(KEY2==0) //按鍵KEY2
- {
- Kp = 160;//200
- Kd = 1.5; //10
- Kp_b = 0.2;//5 0.475
- Ki_b = 2;
- Ju_Li_Max=200;
- Speed=0;
- Key_Flag = 2;
- GPIO_SetBits(GPIOC, GPIO_Pin_5);
- Ju_Li = 0;
- }
- EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE2上的中斷標(biāo)志位
- }
- //外部中斷3服務(wù)程序
- void EXTI3_IRQHandler(void)
- {
- delay_ms(10);//消抖
- if(KEY1==0) //按鍵KEY3
- {
- Kp = 160;//200
- Kd = 1.5; //10
- Kp_b = 0.2;//5 0.475
- Ki_b = 2;
- Ju_Li_Max=200;
- Speed=0;
- GPIO_SetBits(GPIOC, GPIO_Pin_5);
- Key_Flag = 3;
- Time_EN = 500;
- Mode1_Flag = 0;
- Ju_Li = 0;
- }
- EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中斷標(biāo)志位
- }
- void EXTI4_IRQHandler(void)
- {
- delay_ms(10);//消抖
- if(KEY0==0) //按鍵KEY4
- {
- Kp = 160;//200
- Kd = 1.5; //10
- Kp_b = 0.2;//5 0.475
- Ki_b = 2;
- Ju_Li_Max=200;
- Speed=0;
- Key_Flag = 4;
- GPIO_SetBits(GPIOC, GPIO_Pin_5);
- Ju_Li = 0;
- Time_Go = 3500;
- Go = 3.0;
- }
- EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中斷標(biāo)志位
- }
復(fù)制代碼
|
|