不足之处欢迎指出
单片机源程序如下:
- #include "pid.h"
- #include "stm32f10x.h"
- #define pwmout_0 GPIO_SetBits(GPIOB,GPIO_Pin_5)
- #define pwmout_1 GPIO_ResetBits(GPIOB,GPIO_Pin_5)
- PID pid;
- float DIY_Pulse=0;
- void PID_Init()
- {
- pid.sv=60;
- pid.Kp=20;
- pid.T=1;
- pid.Ti=50;
- pid.Td=0;
- pid.pwmcycle=1000;//pwm周期
- pid.OUT0=1;
-
-
- pid.T2=100;
- pid.jiao=100;
- pid.Kp2=20;
- pid.Ti2=0;
- pid.Td2=0;
- }
- void PIDOUT_Init()
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB,PE端口时钟
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //LED0-->PB.5 端口配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
- GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
- GPIO_ResetBits(GPIOB,GPIO_Pin_6); //PB.5 输出高
-
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //LED1-->PE.5 端口配置, 推挽输出
- GPIO_Init(GPIOB, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
- GPIO_SetBits(GPIOB,GPIO_Pin_7); //PE.5 输出高
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //LED1-->PE.5 端口配置, 推挽输出
- GPIO_Init(GPIOB, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
- GPIO_ResetBits(GPIOB,GPIO_Pin_8); //PE.5 输出高
- }
- void PID_Calc() //PID计算
- {
- float DelEk;
- float ti,ki;
- float Iout;
- float Pout;
- float Dout;
- float td;
- float kd;
-
-
- if(pid.C10ms<(pid.T))//计算周期未到
- {
- return ;
- }
- pid.Ek=pid.sv-pid.pv;
- Pout=pid.Kp*pid.Ek; //比例输出
- pid.SEK+=pid.Ek; //历史偏差和
- DelEk=pid.Ek-pid.Ek_1; //相邻两次偏差差值
- ti=pid.T/pid.Ti;
- ki=ti*pid.Kp;
- Iout=pid.SEK*pid.Kp*ti; //积分输出
- td=pid.Td/pid.T;
- kd=pid.Kp*td;
- Dout=DelEk*kd; //微分输出
-
- pid.OUT=Pout+Iout+Dout+pid.OUT0;//本次输出脉宽
-
- if(pid.OUT>pid.pwmcycle)
- {
- pid.OUT=pid.pwmcycle;
- }
- if(pid.OUT<0)
- {
- pid.OUT=0;
- }
- pid.Ek_1=pid.Ek;
-
- pid.pv=encoder;
- encoder=0;
-
- pid.C10ms=0;
- }
- void PID_Calc2() //PID计算
- {
- float DelEk;
- float ti,ki;
- float Iout;
- float Pout;
- float Dout;
- float td;
- float kd;
-
-
- if(pid.C100ms<(pid.T2))//计算周期未到
- {
- return ;
- }
- pid.Ek2=pid.jiao-pid.jpv;
- Pout=pid.Kp2*pid.Ek2; //比例输出
- pid.SEK2+=pid.Ek2; //历史偏差和
- DelEk=pid.Ek2-pid.Ek_12; //相邻两次偏差差值
- ti=pid.T2/pid.Ti2;
- ki=ti*pid.Kp2;
- Iout=pid.SEK2*pid.Kp2*ti; //积分输出
- td=pid.Td2/pid.T2;
- kd=pid.Kp2*td;
- Dout=DelEk*kd; //微分输出
-
- pid.OUT1=Pout+Iout+Dout+pid.OUT0;//本次输出脉宽
-
- if(pid.OUT1>pid.pwmcycle)
- {
- pid.OUT1=pid.pwmcycle;
- }
- if(pid.OUT1<0)
- {
- pid.OUT1=0;
- }
- pid.Ek_12=pid.Ek2;
-
- pid.jpv=jiao;
-
-
- pid.C100ms=0;
- }
- int myabs(int a)
- {
- int temp;
- if(a<0) temp=-a;
- else temp=a;
- return temp;
- }
- //void XCHG_Pid(float Pulse)
- //{
- // TIM_OCInitTypeDef TIM_OCInitStructure;
- //
- // TIM_OCInitStructure.TIM_Pulse = Pulse;
- // TIM_OC2Init(TIM3, &TIM_OCInitStructure);
- //}
- void PID_out(void)
- {
- static u16 pw;
- pw++;
-
- // PID_Calc();
- if(pw>pid.pwmcycle)
- {
- pw=0;
- }
- // if(pid.OUT>0) AIN2=1, AIN1=0;
- // else AIN2=0, AIN1=1;
- if(pw<pid.OUT)
- {
- DIY_Pulse=DIY_Pulse-0.1;
- TIM3->CCR2=DIY_Pulse;
- //XCHG_Pid(DIY_Pulse);
- //pid.jiao++;
- //pwmout_0; //加?
- //PWM1=1;
- }
- else
- {
- DIY_Pulse=DIY_Pulse+0.1;
- TIM3->CCR2=DIY_Pulse;
- //XCHG_Pid(DIY_Pulse);
-
- // pwmout_1; //减速
- //pid.jiao--;
- //PWM1=0;
- }
- }
- void MiniBalance_PWM_Init(u16 arr,u16 psc)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟
-
- GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5
-
- //设置该引脚为复用输出功能,输出TIM2 CH1~ CH4的PWM脉冲波形
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH1 ~TIM_CH4
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
- TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
-
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
- TIM_OCInitStructure.TIM_Pulse =DIY_Pulse; //设置待装入捕获比较寄存器的脉冲值
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
-
- TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
-
- // TIM_CtrlPWMOutputs(TIM2,ENABLE); //MOE 主输出使能
-
- TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH2预装载使能
-
- TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器
- // TIM_CtrlPWMOutputs(TIM3, ENABLE);
- TIM_Cmd(TIM3, ENABLE); //使能TIM2
-
- }
- //int transfer(int encoder)
- //{
- // int temp;
- // temp=encoder;
- // encoder=0; //清零是为了算速度 不清零则是算位置
- // return temp;
- //}
- void MiniBalance_EXTI_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO端口时钟
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //端口配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
- GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIO
-
- Exit_Init();
- }
- void Exit_Init(void)
- {
- EXTI_InitTypeDef EXTI_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- /*====PA.11====*/
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource3);
-
- EXTI_InitStructure.EXTI_Line=EXTI_Line3;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; /*上升沿触发*/
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;
- EXTI_Init(&EXTI_InitStructure); /*根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器*/
- NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; /*抢占优先级2, */
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; /*子优先级1*/
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /*使能外部中断通道*/
- NVIC_Init(&NVIC_InitStructure);
-
-
-
- }
- void EXTI3_IRQHandler()
- {
- if(SET == EXTI_GetITStatus(EXTI_Line3))//PB3 右后A相
- {
-
- // if(RB)
- // {
- encoder++;
- if(pid.OUT1>80) jiao++;
- else jiao--;
- // }
- // else encoder--;
-
- EXTI_ClearITPendingBit(EXTI_Line3);
- }
- }
复制代码- #include "stm32f10x.h"
- #include "pid.h"
- #include "timer.h"
- #include "bsp_key.h"
- #include "bsp_ili9341_lcd.h"
- #include "bsp_spi_flash.h"
- #include "bsp_usart.h"
- #include "delay.h"
- #include <stdio.h>
- extern PID pid;
- static void LCD_Test(void);
- static void Delay ( __IO uint32_t nCount );
- void Printf_Charater(void) ;
- u32 encoder;
- u32 jiao;
- void LED_Init(void)
- {
-
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
- GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
- GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
- }
- int main(void)
- {
- delay_init(); //延时函数初始化
- LED_Init(); //LED端口初始化
- PID_Init();
- PIDOUT_Init();
- ILI9341_Init (); //LCD 初始化
- Key_GPIO_Config();
-
- TIM4_Int_Init(7199,0); //
- MiniBalance_PWM_Init(7199,0); //输出PWM波
- MiniBalance_EXTI_Init();
- ILI9341_GramScan ( 6 );
- while(1)
- {
- LCD_Test();
- PID_Calc();
-
- if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
- {
- pid.sv=pid.sv+10;
- }
- if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON )
- {
- pid.sv=pid.sv-10;
- }
- if( KEY3==0 )
- {
- AIN1=1,AIN2=0;
-
- while(!KEY3);
- }
- if( KEY4==0 )
- {
- AIN1=0,AIN2=1;
- while(!KEY4);
- }
- if( KEY5==0 )
- {
- AIN1=0,AIN2=0;
- while(!KEY5);
- }
-
- if( KEY6==0 )
- {
- jiao=0;
- while(1)
- {
- pid.OUT=0;
- pid.sv=10;
- PID_Calc();
- PID_Calc2();
- LCD_Test();
- if(pid.OUT1>80)
- {
- AIN1=1,AIN2=0;
- }
- else
- AIN1=0,AIN2=1;
-
- if(pid.jpv==pid.jiao)
- {
- AIN1=0,AIN2=0;
- break;
- }
- }
- }
- }
- }
- void LCD_Test(void)
- {
- /*演示显示变量*/
- char sv[100];
- char pv[100];
- char OUT[100];
- char jiao[100];
- char jpv[100];
- char OUT1[100];
- char disbuff[100];
-
- LCD_SetFont(&Font8x16);
- LCD_SetColors(RED,BLACK);
- ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH); /* 清屏,显示全黑 */
- /********显示字符串示例*******/
- ILI9341_DispStringLine_EN_CH(LINE(0),"野火3.2寸LCD参数:");
- ILI9341_DispStringLine_EN_CH(LINE(1),"分辨率:240x320 px");
- ILI9341_DispStringLine_EN_CH(LINE(2),"ILI9341液晶驱动");
-
- /********显示变量示例*******/
- LCD_SetFont(&Font16x24);
- LCD_SetTextColor(GREEN);
- /*使用c标准库把变量转化成字符串*/
- sprintf(sv,"设定速度: %f ",pid.sv);
- sprintf(pv,"实际速度 : %f ",pid.pv);
- sprintf(OUT,"pid输出: %f ",pid.OUT);
- sprintf(jiao,"设定角度: %f ",pid.jiao);
- sprintf(jpv,"实际角度: %f ",pid.jpv);
- sprintf(OUT1,"pid输出: %f ",pid.OUT1);
-
- LCD_ClearLine(LINE(4)); /* 清除单行文字 */
- LCD_ClearLine(LINE(5)); /* 清除单行文字 */
- LCD_ClearLine(LINE(6)); /* 清除单行文字 */
- LCD_ClearLine(LINE(7)); /* 清除单行文字 */
- LCD_ClearLine(LINE(8)); /* 清除单行文字 */
- LCD_ClearLine(LINE(9)); /* 清除单行文字 */
-
- /*然后显示该字符串即可,其它变量也是这样处理*/
- ILI9341_DispStringLine_EN_CH(LINE(4),sv);
- ILI9341_DispStringLine_EN_CH(LINE(5),pv);
- ILI9341_DispStringLine_EN_CH(LINE(6),OUT);
- ILI9341_DispStringLine_EN_CH(LINE(7),jiao);
- ILI9341_DispStringLine_EN_CH(LINE(8),jpv);
- ILI9341_DispStringLine_EN_CH(LINE(9),OUT1);
- }
复制代码
所有资料51hei提供下载:
PID算法.7z
(227.61 KB, 下载次数: 138)
|