#include "control.h"
/**************************************************************************
**************************************************************************/
int Target_position=11000; //初始值是10000,目标值是11000
int TIM1_UP_IRQHandler(void)
{
if(TIM1->SR&0X0001)//5ms定时中断
{
TIM1->SR&=~(1<<0); //===清除定时器1中断标志位
Encoder=Read_Encoder(2); //===读取编码器的位置数据 初始值是10000,详见encoder.c 和encoder.h
Led_Flash(100); //===LED闪烁;指示单片机正常运行
Xianfu_Pwm(); //===PWM限幅
Moto1=Position_PI(Encoder,Target_position); //===位置PI控制器
Set_Pwm(Moto1); //===赋值给PWM寄存器
}
return 0;
}
/**************************************************************************
函数功能:赋值给PWM寄存器
入口参数:PWM
返回 值:无
**************************************************************************/
void Set_Pwm(int moto1)
{
if(moto1<0) AIN2=1, AIN1=0;
else AIN2=0, AIN1=1;
PWMA=myabs(moto1);
}
/**************************************************************************
函数功能:限制PWM赋值
入口参数:无
返回 值:无
**************************************************************************/
void Xianfu_Pwm(void)
{
int Amplitude=7100; //===PWM满幅是7200 限制在7100
if(Moto1<-Amplitude) Moto1=-Amplitude;
if(Moto1>Amplitude) Moto1=Amplitude;
}
/**************************************************************************
函数功能:绝对值函数
入口参数:int
返回 值:unsigned int
**************************************************************************/
int myabs(int a)
{
int temp;
if(a<0) temp=-a;
else temp=a;
return temp;
}
/**************************************************************************
函数功能:位置式PI控制器
入口参数:编码器测量位置信息,目标位置
返回 值:电机PWM
根据位置式离散PID公式
pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]
e(k)代表本次偏差
e(k-1)代表上一次的偏差
∑e(k)代表e(k)以及之前的偏差的累积和;其中k为1,2,,k;
pwm代表输出
在我们的位置控制闭环系统里面,只使用PI控制
pwm=Kp*e(k)+Ki*∑e(k)
**************************************************************************/
int Position_PI (int Encoder,int Target)
{
float Kp=15,Ki=0.01;
static int Bias,Pwm,Integral_bias;
Bias=Encoder-Target; //计算偏差
Integral_bias+=Bias; //求出偏差的积分
Pwm=Kp*Bias+Ki*Integral_bias; //位置式PI控制器
return Pwm; //增量输出
```
```c
#include "encoder.h"
/**************************************************************************
**************************************************************************/
/**************************************************************************
函数功能:把TIM2初始化为编码器接口模式
入口参数:无
返回 值:无
**************************************************************************/
void Encoder_Init_TIM2(void)
{
RCC->APB1ENR|=1<<0; //TIM2时钟使能
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0XFFFFFF00;//PA0 PA1
GPIOA->CRL|=0X00000044;//浮空输入
/* 把定时器初始化为编码器模式 */
TIM2->PSC = 0x0;//预分频器
TIM2->ARR = ENCODER_TIM_PERIOD-1;//设定计数器自动重装值
TIM2->CCMR1 |= 1<<0; //输入模式,IC1FP1映射到TI1上
TIM2->CCMR1 |= 1<<8; //输入模式,IC2FP2映射到TI2上
TIM2->CCER |= 0<<1; //IC1不反向
TIM2->CCER |= 0<<5; //IC2不反向
TIM2->SMCR |= 3<<0; //SMS='011' 所有的输入均在上升沿和下降沿有效
TIM2->CNT = COUNTER_RESET;
TIM2->CR1 |= 0x01; //CEN=1,使能定时器
}
/**************************************************************************
函数功能:把TIM4初始化为编码器接口模式
入口参数:无
返回 值:无
**************************************************************************/
void Encoder_Init_TIM4(void)
{
RCC->APB1ENR|=1<<2; //TIM4时钟使能
RCC->APB2ENR|=1<<3; //使能PORTb时钟
GPIOB->CRL&=0X00FFFFFF;//PB6 PB7
GPIOB->CRL|=0X44000000;//浮空输入
/* 把定时器初始化为编码器模式 */
TIM4->PSC = 0x0;//预分频器
TIM4->ARR = ENCODER_TIM_PERIOD-1;//设定计数器自动重装值
TIM4->CCMR1 |= 1<<0; //输入模式,IC1FP1映射到TI1上
TIM4->CCMR1 |= 1<<8; //输入模式,IC2FP2映射到TI2上
TIM4->CCER |= 0<<1; //IC1不反向
TIM4->CCER |= 0<<5; //IC2不反向
TIM4->SMCR |= 3<<0; //SMS='011' 所有的输入均在上升沿和下降沿有效
TIM4->CR1 |= 0x01; //CEN=1,使能定时器
}
/**************************************************************************
函数功能:单位时间读取编码器计数
入口参数:定时器
返回 值:速度值
**************************************************************************/
int Read_Encoder(u8 TIMX)
{
int Encoder_TIM;
switch(TIMX)
{
case 2: Encoder_TIM= (short)TIM2 -> CNT; break;
case 3: Encoder_TIM= (short)TIM3 -> CNT; break;
case 4: Encoder_TIM= (short)TIM4 -> CNT; break;
default: Encoder_TIM=0;
}
return Encoder_TIM;
}
#include "motor.h"
void MiniBalance_Motor_Init(void)
{
RCC->APB2ENR|=1<<3; //PORTB时钟使能
GPIOB->CRH&=0X0000FFFF; //PORTB12 13 14 15推挽输出
GPIOB->CRH|=0X22220000; //PORTB12 13 14 15推挽输出
}
void MiniBalance_PWM_Init(u16 arr,u16 psc)
{
MiniBalance_Motor_Init(); //初始化电机控制所需IO
RCC->APB1ENR|=1<<1; //TIM3时钟使能
RCC->APB2ENR|=1<<3; //PORTB时钟使能
GPIOB->CRL&=0XFFFFFF00; //PORTB0 1复用输出
GPIOB->CRL|=0X000000BB; //PORTB0 1复用输出
TIM3->ARR=arr;//设定计数器自动重装值
TIM3->PSC=psc;//预分频器不分频
TIM3->CCMR2|=6<<12;//CH4 PWM1模式
TIM3->CCMR2|=6<<4; //CH3 PWM1模式
TIM3->CCMR2|=1<<11;//CH4预装载使能
TIM3->CCMR2|=1<<3; //CH3预装载使能
TIM3->CCER|=1<<12; //CH4输出使能
TIM3->CCER|=1<<8; //CH3输出使能
TIM3->CR1=0x8000; //ARPE使能
TIM3->CR1|=0x01; //使能定时器3
}
#include "key.h"
/**************************************************************************
函数功能:按键初始化
入口参数:无
返回 值:无
**************************************************************************/
void KEY_Init(void)
{
RCC->APB2ENR|=1<<3; //使能PORTB时钟
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00800000;//PB5 上拉输入
GPIOB->ODR|=1<<5; //PB5 上拉
}
/**************************************************************************
函数功能:按键扫描
入口参数:双击等待时间
返回 值:按键状态 0:无动作 1:单击 2:双击
**************************************************************************/
u8 click_N_Double (u8 time)
{
static u8 flag_key,count_key,double_key;
static u16 count_single;
if(0==KEY&&0==flag_key) flag_key=1;
if(0==count_key)
{
if(flag_key==1)
{
double_key++;
count_key=1;
}
if(double_key==2)
{
double_key=0;
count_single=0;
return 2;//双击执行的指令
}
}
if(1==KEY) flag_key=0,count_key=0;
if(1==double_key)
{
if(++count_single>time)
{
double_key=0;
count_single=0;
return 1;//单击执行的指令
}
}
return 0;
}
/**************************************************************************
函数功能:按键扫描
入口参数:无
返回 值:按键状态 0:无动作 1:单击
**************************************************************************/
u8 click(void)
{
static u8 flag_key=1;//按键按松开标志
if(flag_key&&KEY==0)
{
flag_key=0;
return 1; // 按键按下
}
else if(1==KEY) flag_key=1;
return 0;//无按键按下
}
key.h
#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
#define KEY PBin(5)
void KEY_Init(void); //按键初始化
u8 click_N_Double (u8 time); //单击按键扫描和双击按键扫描
u8 click(void); //单击按键扫描
#endif