完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本篇博客不会给出所有的工程文件代码,如果需要可以关注我,并在评论区留下你的邮箱看到之后会立马发送工程文件
首先我们最先关注位置版的pid控制: int Position_PID (int Encoder,int Target) { float Position_KP=8,Position_KI=0.001,Position_KD=500; static float Bias,Pwm,Integral_bias,Last_Bias; Bias=Encoder-Target; //计算偏差 Integral_bias+=Bias; //求出偏差的积分 Pwm=Position_KP*Bias+Position_KI*Integral_bias+Position_KD*(Bias-Last_Bias); //位置式PID控制器 Last_Bias=Bias; //保存上一次偏差 // printf("%d %dn",Moto1,Encoder); return Pwm; //增量输出 } 这是一段非常经典的pid控制代码,我们利用电机的编码器读数,读取出对应的读数也就是我们输入的encoder值,注意因为我们是位置控制的pid所以encoder的值在每次读取的时候千万不要清0 如果清0之后就相当于每次读取的不是累计位移而是速度(单位时间内的位移),我相信聪明的你一定很快就明白了吧。 我们这里给出编码器读取的相关代码 int Read_Encoder(u8 TIMX)//选取定时器 { int Encoder_TIM; switch(TIMX) { case 2: Encoder_TIM= (short)TIM2 -> CNT;break; //读取编码器的数据并不清零速度(我们这里只要对一个轮子进行位置pid控制所以第一读取不清0,下面两段读取就是速度pid相关的代码) case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break; //读取编码器据数据并清零 case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break; //读取编码器的数据并清零 default: Encoder_TIM=0; } return Encoder_TIM; } 我们要实现的目标是轮子卡死(或者被掰过来之后会回到原位),所以我们将目标位置设置为0(编码器的读数)这里我们将编码器读数的控制设置在了定时器的在中断之中,大约为每5ms触发一次 void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断 { TIM3->SR&=~(1<<0); //===清除定时器1中断标志位 Encoder=Read_Encoder(2); //===读取编码器的位置数据 初始值是10000,详见encoder.c 和encoder.h //===LED闪烁;指示单片机正常运行 Moto1=Position_PID(Encoder,0); //===位置PID控制器 Xianfu_Pwm(); //===PWM限幅 Set_Pwm(Moto1); //===赋值给PWM寄存器 } } 下面给出定时器配置相关代码 void TIM3_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能TIM3时钟 TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断 TIM_Cmd(TIM3,ENABLE); //使能定时器3 NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1 NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); } 做完这一切基本就是对于编码器读取,和pwm输出的配置了 void MiniBalance_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //TIM1时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟 GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1); //GPIOA8复用为定时器1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_TIM1); //GPIOA11复用为定时器1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11; //GPIO GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);//初始化定时器1 //初始化TIM1 Channel1 PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 TIM_OC4Init(TIM1, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能 TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能TIM1在CCR1上的预装载寄存器 TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能TIM1在CCR4上的预装载寄存器 TIM_ARRPreloadConfig(TIM1,ENABLE);//ARPE使能 PWMA=0;PWMB=0; TIM_Cmd(TIM1, ENABLE); //使能TIM1 MiniBalance_Motor_Init(); } 编码器设置:这里使用的是定时器2 void Encoder_Init_TIM2(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使用A口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; //PA0 PA1 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM2); //复用为TIM2 编码器接口 GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_TIM2); //复用为TIM2 编码器接口 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // No prescaling //不分频 TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //选择时钟分频:不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器 TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3 TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 0; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM2->CNT = 0; TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); } 下面给出主函数 int main(void) { u32 t=0; uart_init(115200); delay_init(84); MiniBalance_Motor_Init(); MiniBalance_PWM_Init(7199,0); Encoder_Init_TIM2(); TIM3_Int_Init(5-1,8400-1);//时间是5ms // op=0; while(1){ // AIN2=1;AIN1=0; printf("t:%d %d %drn",PWMA,Encoder,op); delay_ms(50); t++; } } 然后基本上就是大功告成啦!本次所有代码均通过实际测试,编译没有问题可以正常使用。 |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2955 浏览 16 评论
3455 浏览 1 评论
8987 浏览 16 评论
4050 浏览 18 评论
1102浏览 3评论
570浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2301浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1857浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 05:50 , Processed in 0.969368 second(s), Total 50, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号