標(biāo)題:
STM32的PID算法調(diào)節(jié)電機(jī)角度與調(diào)角程序
[打印本頁(yè)]
作者:
a1590567
時(shí)間:
2019-3-12 22:07
標(biāo)題:
STM32的PID算法調(diào)節(jié)電機(jī)角度與調(diào)角程序
不足之處歡迎指出
單片機(jī)源程序如下:
#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端口時(shí)鐘
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); //根據(jù)設(shè)定參數(shù)初始化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計(jì)算
{
float DelEk;
float ti,ki;
float Iout;
float Pout;
float Dout;
float td;
float kd;
if(pid.C10ms<(pid.T))//計(jì)算周期未到
{
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計(jì)算
{
float DelEk;
float ti,ki;
float Iout;
float Pout;
float Dout;
float td;
float kd;
if(pid.C100ms<(pid.T2))//計(jì)算周期未到
{
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外設(shè)和AFIO復(fù)用功能模塊時(shí)鐘
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5
//設(shè)置該引腳為復(fù)用輸出功能,輸出TIM2 CH1~ CH4的PWM脈沖波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH1 ~TIM_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置在下一個(gè)更新事件裝入活動(dòng)的自動(dòng)重裝載寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置用來(lái)作為TIMx時(shí)鐘頻率除數(shù)的預(yù)分頻值 不分頻
TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時(shí)間基數(shù)單位
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //選擇定時(shí)器模式:TIM脈沖寬度調(diào)制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_Pulse =DIY_Pulse; //設(shè)置待裝入捕獲比較寄存器的脈沖值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根據(jù)TIM_OCInitStruct中指定的參數(shù)初始化外設(shè)TIMx
// TIM_CtrlPWMOutputs(TIM2,ENABLE); //MOE 主輸出使能
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH2預(yù)裝載使能
TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的預(yù)裝載寄存器
// 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時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO端口時(shí)鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //根據(jù)設(shè)定參數(shù)初始化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; /*上升沿觸發(fā)*/
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); /*根據(jù)EXTI_InitStruct中指定的參數(shù)初始化外設(shè)EXTI寄存器*/
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; /*搶占優(yōu)先級(jí)2, */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; /*子優(yōu)先級(jí)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);
}
}
復(fù)制代碼
#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端口時(shí)鐘
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); //根據(jù)設(shè)定參數(shù)初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 輸出高
}
int main(void)
{
delay_init(); //延時(shí)函數(shù)初始化
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參數(shù):");
ILI9341_DispStringLine_EN_CH(LINE(1),"分辨率:240x320 px");
ILI9341_DispStringLine_EN_CH(LINE(2),"ILI9341液晶驅(qū)動(dòng)");
/********顯示變量示例*******/
LCD_SetFont(&Font16x24);
LCD_SetTextColor(GREEN);
/*使用c標(biāo)準(zhǔn)庫(kù)把變量轉(zhuǎn)化成字符串*/
sprintf(sv,"設(shè)定速度: %f ",pid.sv);
sprintf(pv,"實(shí)際速度 : %f ",pid.pv);
sprintf(OUT,"pid輸出: %f ",pid.OUT);
sprintf(jiao,"設(shè)定角度: %f ",pid.jiao);
sprintf(jpv,"實(shí)際角度: %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);
}
復(fù)制代碼
所有資料51hei提供下載:
PID算法.7z
(227.61 KB, 下載次數(shù): 138)
2019-3-12 22:25 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
作者:
admin
時(shí)間:
2019-3-12 22:25
本帖需要重新編輯補(bǔ)全電路原理圖,源碼,詳細(xì)說(shuō)明與圖片即可獲得100+黑幣(帖子下方有編輯按鈕)
作者:
ultra夢(mèng)幻雨
時(shí)間:
2019-7-31 18:36
感謝分享
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1