前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >PID闭环控制单个电机-应用层-附代码

PID闭环控制单个电机-应用层-附代码

作者头像
发布于 2024-12-07 04:20:00
发布于 2024-12-07 04:20:00
17700
代码可运行
举报
文章被收录于专栏:转自CSDN转自CSDN
运行总次数:0
代码可运行

        PID是基于编码器测速与PWM输出的闭环类控制

         器件:

                一个减速电机

                一个AB相编码器

                TB6612电机控速

                STM32F103C8T6

                一块OLED显示屏

                一块轮胎

        代码内附有接线引脚 

        用的库来源于Bilibili的

        代码内容

除了main和timer 其它的直接用库即可 

 main:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"
#include "Motor.h"
		//定义速度变量

typedef struct
{
	float target_val;   //目标值
	float err;          //偏差值
	float err_last;     //上一个偏差值
	float Kp,Ki,Kd;     //比例、积分、微分系数
	float integral;     //积分值
	float output_val;   //输出值
	float C_out;
}PID;
PID pid;
float PID_realize(float actual_val)
{
	/*计算目标值与实际值的误差*/
	pid.err = pid.target_val - actual_val;
	
	/*积分项*/
	pid.integral += pid.err;

	/*PID算法实现*/
	pid.output_val = pid.Kp * pid.err + pid.Ki * pid.integral + pid.Kd * (pid.err - pid.err_last);

	/*误差传递*/
	pid.err_last = pid.err;
	
	pid.output_val += pid.C_out;
	if(pid.output_val >= 100)
		pid.output_val = 100;
	if(pid.output_val <= -100)
		pid.output_val = -100;
	
	/*返回当前实际值*/
	return pid.output_val;
}


int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Timer_Init();		//定时器初始化
	Encoder_Init();		//编码器初始化
	Motor_Init();
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Ipeed:");		//1行1列显示字符串Speed:
	OLED_ShowString(2, 1, "Opeed:");
	OLED_ShowString(3, 1, "OIpwm:");
	
	pid.C_out=pid.err=pid.err_last=pid.integral= 0;
	
	
	
	pid.Kd= 0.4051;//3
	pid.Ki= 0.0045551;//2
	pid.Kp= 0.0505;//1
	pid.C_out= 0;
	
	pid.target_val= 1000;
	
	
	while (1)
	{
		PID_realize(Speed);
    Motor_SetSpeed(pid.output_val);
		OLED_ShowSignedNum(1, 7, Speed, 5);
		OLED_ShowSignedNum(2, 7, (int)pid.target_val, 5);
		OLED_ShowSignedNum(3, 7, (int)pid.output_val, 5);	//不断刷新显示编码器测得的最新速度
	}
}

/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */

Timer定时中断有更改内容 

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "stm32f10x.h"                  // Device header
#include "Encoder.h"

int16_t Speed;	
/**
  * 函    数:定时中断初始化
  * 参    数:无
  * 返 回 值:无
  */
void Timer_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);			//开启TIM2的时钟
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM4);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1;				//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	
	
	/*中断输出配置*/
	TIM_ClearFlag(TIM4, TIM_FLAG_Update);						//清除定时器更新标志位
																//TIM_TimeBaseInit函数末尾,手动产生了更新事件
																//若不清除此标志位,则开启中断后,会立刻进入一次中断
																//如果不介意此问题,则不清除此标志位也可
	
	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;				//选择配置NVIC的TIM2线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*TIM使能*/
	TIM_Cmd(TIM4, ENABLE);			//使能TIM2,定时器开始运行
}

/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/
void TIM4_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		Speed = Encoder_Get();								//每隔固定时间段读取一次编码器计数增量值,即为速度值
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
电机控制进阶2——PID位置控制
上篇文章电机控制进阶——PID速度控制讲解了电机的速度环控制,可以控制电机快速准确地到达指定速度。
xxpcb
2021/06/24
2.8K0
stm32电机控制之控制两路直流电机!看完你会了吗
小车使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制,这里电机使用PWM驱动,速度控制框图如下:
用户6754675
2019/12/12
3.6K0
分析stm32f103x timer6用不了的原因?
最近在修改别人的代码,程序里面使用了timer7,因为要扩展一些功能,所以准备使用timer6,但是配置了后,发现timer6不能正常运行。
ManInRoad
2020/12/22
4400
分析stm32f103x timer6用不了的原因?
利用STM32F103精确控制步进电机
STM32F103C8T6 42步进电机(42SHDC4040-17B) TB6600电机驱动器升级版
全栈程序员站长
2022/09/05
2.1K0
利用STM32F103精确控制步进电机
电机控制进阶3——PID串级控制(附全套代码下载)
前两篇文章,分别介绍了PID速度控制和PID位置控制,分别用来控制电机以期望的速度持续转动以及以期望的位置(圈数)转动,这里的期望值都只有一个,但是,如果想要以期望的速度转动到期望的位置(启动与停止的加减速过程不考虑),该怎么控制呢?那就要将两者结合起来了,即PID的串级控制来控制电机。
xxpcb
2021/06/24
1.9K0
基于stm32四轮小车简易PID控制
看前需知:作者本人使用的是四个普通的TT电机加编码器+增量式PID,适合PID初学者,但是需要对PID和增量式PID有一定的认知,本篇未有详细介绍,以代码应用为主,大佬勿喷。
全栈程序员站长
2022/09/01
1.6K0
关于STM32空闲中断
有一次做一个东西,为了尽量不占用CPU的处理数据时间,所以就使用DMA接收串口的数据,但是呢问题来了.,,,,,怎么样才能确定接收到了一条完整的数据了,,我们都知道只要打开DMA 那家伙就不停的把接收的数据放到我们指定的地方. 只要接收到一条完整的数据我就该去处理了 关于空闲中断,,,就是说每接收到一条完整的数据就会置位空闲标志位,我们只需要判断空闲标志位是否置一,,就能知道是不是接收到了一条完整的数据 用空闲中断的好处就是,,对于以前我写程序通信都会在数据的后面加上尾,,然后另一个接收的单片机通过判断数据
杨奉武
2018/04/18
9500
关于STM32空闲中断
基于STM32和HC-SR04模块实现超声波测距功能
本文用的单片机是STM32F103C8T6,超声波测距模块是HC-SR04,显示测距结果用的是0.96寸OLED屏模块。
zeruns
2022/11/11
2.4K0
基于STM32和HC-SR04模块实现超声波测距功能
开源项目:使用STM32做一个简易的示波器
该项目是基于正点原子精英板制作的一个简易示波器,可以读取信号的频率和幅值,并可以通过按键改变采样频率和控制屏幕的更新暂停。
AI 电堂
2022/12/08
3.4K0
开源项目:使用STM32做一个简易的示波器
如何用单片机高效处理矩阵按键?
矩阵按键是一种常见的输入设备,广泛应用于嵌入式系统中,如工业控制、消费电子和智能家居等领域。
不脱发的程序猿
2025/03/17
1710
如何用单片机高效处理矩阵按键?
STM32 移植FreeModbus详细过程
modbus是一个非常好的串口协议(当然也能用在网口上),它简洁、规范、强大。可以满足大部分的工业、嵌入式需求。
MCU起航
2020/06/28
6.2K3
【STM32】PWM输出
PWM是“Pulse Width Modulation”的缩写,即脉冲宽度调制,简称脉宽调制。是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单来说,就是对脉冲宽度的控制。
DevFrank
2024/07/24
2120
【STM32】PWM输出
平衡车不用编码器可以吗_编码器结构及工作原理
编码器是一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感器,我们可以通过编码器测量到底位移或者速度信息。编码器从输出数据类型上分,可以分为增量式编码器和绝对式编码器。
全栈程序员站长
2022/11/10
9820
平衡车不用编码器可以吗_编码器结构及工作原理
(十七)STM32——定时器
目录 学习目标 内容 简介 定时器分类 定时器功能介绍 计时器模式 工作过程 内部时钟选择 寄存器 配置 代码 总结  ---- 学习目标         本节内容我们来介绍一下有关定时器的知识,其实这个定时器,和我们日常接触的定时器没有什么区别,都是到了一定的时间就去做指定的事情。和51单片机的定时器也没有很大区别,就是数量和功能明显变多了许多,那我们就开始吧! 内容 简介         STM32F4 的定时器功能十分强大,有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIM
小点点
2022/12/12
1.3K0
(十七)STM32——定时器
电机控制基础1——定时器基础知识与PWM输出原理
单片机开发中,电机的控制与定时器有着密不可分的关系,无论是直流电机,步进电机还是舵机,都会用到定时器,比如最常用的有刷直流电机,会使用定时器产生PWM波来调节转速,通过定时器的正交编码器接口来测量转速等。
xxpcb
2021/02/26
2.1K0
电机控制基础1——定时器基础知识与PWM输出原理
PWM输入输出
输出PWM波的原理是,利用TIM定时器和输出比较,TIM定时器会周期性地线性增长,当计数器的值低于设定的比较值时输出高电平,大于等于比较值时输出低电平。由于是线性增长,高电平时长占整个周期信号时长的比例是固定的,这个比例被称为“占空比”,英文“Duty Cycle”。 在嵌入式系统中,特别是使用定时器来生成PWM信号时,经常使用的是定时器的比较寄存器(Capture/Compare Register,CCR)和自动重载寄存器(Auto-Reload Register,ARR)来控制PWM的占空比。 给定:
WuShF
2024/02/10
1K0
PWM输入输出
OLED显示红外遥控键码
本遥控器的编码是NEC编码,为PWM(脉冲宽度调制)。 发射红外载波的时间固定,通过改变不发射载波的时间来改变占空比。
WuShF
2024/02/17
2150
OLED显示红外遥控键码
单片机入门学习十三 STM32单片机学习十 通用定时器
本篇重点记录的是STM32F1的通用定时器。 STM32F103ZE有8个定时器,其中2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5),2个基本定时器(TIM6、TIM7)。下表是对这8个定时器的详细描述。
用户4645519
2020/09/07
2.2K0
单片机入门学习十三 STM32单片机学习十 通用定时器
电机控制基础3——定时器编码器模式使用与转速计算
上篇电机控制基础——定时器捕获单输入脉冲原理介绍了定时器捕获输入脉冲的原理,那种方式是根据捕获的原理,手动切换上升沿与下降沿捕获,计算脉冲宽度的过程原理比较清晰,但编程操作起来比较麻烦。
xxpcb
2021/03/18
3.1K0
电机控制基础3——定时器编码器模式使用与转速计算
基于STM32设计的出租车计费系统
在城市交通中,出租车是一种常见的交通工具。为了方便乘客和司机之间的交易,出租车计费系统被广泛应用于出租车行业。系统能够自动计算乘客的费用,提供准确、方便的计费服务,并且能够记录乘客的行驶数据,方便后续查询和管理。
DS小龙哥
2023/08/09
4880
基于STM32设计的出租车计费系统
推荐阅读
相关推荐
电机控制进阶2——PID位置控制
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档