STM32自学笔记17-步进电机驱动项目-磁编码器的正常使用

这篇具有很好参考价值的文章主要介绍了STM32自学笔记17-步进电机驱动项目-磁编码器的正常使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

上节有这样一句话:

步进电机旋转角度和编码器输出数据之间的关系通常是非线性的。在校准过程中,可以通过采集一系列已知角度位置的数据点,并拟合出角度与编码器数据之间的关系。这个拟合可以使用曲线拟合算法或其他数学方法来实现。通过拟合,可以建立编码器输出数据与实际相位角之间的非线性转换公式,从而实现更准确的角度测量。

代码是这样实现的,在步进电机旋转的每一步都计算下一步和这一步的传感器读取数值的差,如果这个差值和预期不一致,则认为发生了阶跃,同时把阶跃差值确定。

	uint32_t step_num = 0;  //阶跃次数
	if(encode_cali.dir){    //电机正转
		for(count=0; count<200; count++){
			sub_data = (int32_t)encode_cali.coder_data_f[CycleRem(count+1, 200)] - (int32_t)encode_cali.coder_data_f[CycleRem(count, 200)];
			if(sub_data < 0){   //这个差值是应该大于0的,如果小于0则代表发生了阶跃,即转了超过1圈
				step_num++;  //阶跃次数加1
				encode_cali.rcd_x = count;//使用区间前标
				encode_cali.rcd_y = (2^14-1) - encode_cali.coder_data_f[CycleRem(encode_cali.rcd_x, 200)]; //阶跃差值
			}
		}
		if(step_num != 1){
			encode_cali.error_code = CALI_Error_PhaseStep;  //如果阶跃次数不为1,则报错
			return;
		}
	}
	else{   //反转也是类似的,差值应该小于0,如果大于0则代表发生了阶跃
		for(count=0; count<200; count++){
			sub_data = (int32_t)encode_cali.coder_data_f[CycleRem(count+1, 200)] - (int32_t)encode_cali.coder_data_f[CycleRem(count, 200)];
			if(sub_data > 0){
				step_num++;
				encode_cali.rcd_x = count;//使用区间前标
				encode_cali.rcd_y = (2^14-1) - encode_cali.coder_data_f[CycleRem(encode_cali.rcd_x+1, 200)]; //这里要注意,反转需要把步数+1,即下一步的差值
			}
		}
		if(step_num != 1){
			encode_cali.error_code = CALI_Error_PhaseStep;
			return;
		}
	}

到这里为止,整个编码器的校准过程就完成了。

接下去就是正常使用的过程。

  1. 首先要定义一个编码器状态的枚举类型
typedef enum{
	CALI_Disable = 0x00,						//不校准
	CALI_Forward_Encoder_AutoCali,				//编码器正转自动校准
	CALI_Forward_Measure,						//正向测量
	CALI_Reverse_Ret,							//反向回退
	CALI_Reverse_Gap,							//反向消差
	CALI_Reverse_Measure,						//反向测量
	CALI_Operation,								//解算
}CALI_State;

会把它分为中断过程的回调使用正常回调两个函数来执行。

  1. 首先是中断回调,一般是用户在正常工作时想要进行校准时的操作。来看下代码:
switch(encode_cali.state)  //看现时的编码器状态
	{
		case CALI_Disable:
			if(encode_cali.trigger)  //如果用户开启了校准请求,初始化也会使trigger置1
			{
				REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);   //这一句是和FOC算法相关的,后面再学习
				encode_cali.out_location = Move_Pulse_NUM;	//步进电机转一圈,这个宏定义的值是单圈脉冲数,=200*256,256是单步细分数
				encode_cali.gather_count = 0;	//采集清零
				encode_cali.state = CALI_Forward_Encoder_AutoCali;	  //--->编码器正转自动校准
				encode_cali.error_code = CALI_No_Error; //初始化
				encode_cali.error_data = 0;
			}
		break;
		//编码器正转自动校准
		case CALI_Forward_Encoder_AutoCali:
			encode_cali.out_location += 2;  //每次走2个脉冲,一直走到第二圈
			REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);
			if(encode_cali.out_location == 2 * Move_Pulse_NUM)
			{
				encode_cali.out_location = Move_Pulse_NUM;  //重置到一圈
				encode_cali.state = CALI_Forward_Measure;  //走到第二圈后到下一个状态,正向测量
			}
		break;
		//正向测量
		case CALI_Forward_Measure:
			if((encode_cali.out_location % Move_Divide_NUM) == 0)//每到达采集细分量点采集一次数据
			{
				//开始采集传感器的角度数据
				encode_cali.coder_data_gather[encode_cali.gather_count++] = mt6816.angle_data;
				if(encode_cali.gather_count == Gather_Quantity){
					//记录数据
					encode_cali.coder_data_f[(encode_cali.out_location - Move_Pulse_NUM) / Move_Divide_NUM]
						= CycleDataAverage(encode_cali.coder_data_gather, Gather_Quantity, CALI_Encode_Res);
					//采集计数清零
					encode_cali.gather_count = 0;
					//移动位置
					encode_cali.out_location += 1;  //每次移动1个脉冲
				}
			}
			else{
				//移动位置
				encode_cali.out_location += 1;
			}	
			REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);
		
			if(encode_cali.out_location > (2 * Move_Pulse_NUM)) //如果走的脉冲数超过2圈了,进入下一个状态
			{
				encode_cali.state = CALI_Reverse_Ret;//--->反向回退
			}
		break;
		//反向回退
		case CALI_Reverse_Ret: 
			encode_cali.out_location += 1;
			REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);
			
			if(encode_cali.out_location == (2 * Move_Pulse_NUM + Move_Divide_NUM * 20))  //从第二圈再走20步,到下一个状态
			{
				encode_cali.state = CALI_Reverse_Gap;//--->反向消差
			}
		break;
		//反向消差
		case CALI_Reverse_Gap:
			encode_cali.out_location -= 1;  //每次往回退一个脉冲
			REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);
			
			if(encode_cali.out_location == (2 * Move_Pulse_NUM))  //退回到第二圈
			{
				encode_cali.state = CALI_Reverse_Measure;//--->反向测量
			}
		break;
		//反向测量,和正向测量类似
		case CALI_Reverse_Measure:
			if((encode_cali.out_location % Move_Divide_NUM) == 0)//每到达采集细分量点采集一次数据
			{
				//采集
				encode_cali.coder_data_gather[encode_cali.gather_count++] = mt6816.angle_data;
				if(encode_cali.gather_count == Gather_Quantity){
					//记录数据
					encode_cali.coder_data_r[(encode_cali.out_location - Move_Pulse_NUM) / Move_Divide_NUM]
						= CycleDataAverage(encode_cali.coder_data_gather, Gather_Quantity, CALI_Encode_Res);
					//采集计数清零
					encode_cali.gather_count = 0;
					//移动位置
					encode_cali.out_location -= 1;  回退一个脉冲
				}
			}
			else{
				//移动位置
				encode_cali.out_location -= 1;
			}	
			REIN_HW_Elec_SetDivideElec(encode_cali.out_location, Current_Cali_Current);
			
			if(encode_cali.out_location < Move_Pulse_NUM)
			{
				encode_cali.state = CALI_Operation;//如果退回1圈以内,则进入下一个状态
			}
		break;
		//计算
		case CALI_Operation:
			//进行校准计算中
			REIN_HW_Elec_SetDivideElec(0, 0);
			
		break;
		default:
		break;
	}
}

可以看到,进中断时的操作是走一个流程,把每个状态都走一遍,并把采集的数据记录到coder_data_fcoder_data_r两个数组中。
下面看看主循环中的调用函数,下面代码中Move_Step_NUM是步进电机总步数200,Move_Divide_NUM是每步的细分数256,Move_Pulse_NUM是总的脉冲数,即256*200

void Calibration_Loop_Callback(void)
{
	int32_t		data_i32;  //32位有符号
	uint16_t	data_u16;  //16位无符号数
	
	//必须要是校准计算状态才进入主循环,否则退出
	if(encode_cali.state != CALI_Operation)
		return;
	
	//给电机的4线低电平
	REIN_HW_Elec_SetSleep();

	//传感器数据检查
	Calibration_Data_Check();
	

	if(encode_cali.error_code == CALI_No_Error)
	{
		int32_t step_x, step_y;
		encode_cali.result_num = 0;
		Stockpile_Flash_Data_Empty(&stockpile_quick_cali);		//Flash擦除数据区
		Stockpile_Flash_Data_Begin(&stockpile_quick_cali);		//开始写数据区
		if(encode_cali.dir){  //正转的情况
			for(step_x = encode_cali.rcd_x; step_x < encode_cali.rcd_x + Move_Step_NUM + 1; step_x++)  //从rcd_x的位置整一圈
			{  																						   //可以认为rcd_x是步数,rcd_y是该步数对应的传感器读数				
				data_i32 = CycleSub(	encode_cali.coder_data_f[CycleRem(step_x+1, Move_Step_NUM)],   
															encode_cali.coder_data_f[CycleRem(step_x, Move_Step_NUM)],  
															CALI_Encode_Res);                          //data_i32的值存的是两步之间的传感器的读取数值差值
				if(step_x == encode_cali.rcd_x){//开始边缘
					for(step_y = encode_cali.rcd_y; step_y < data_i32; step_y++){ 
						data_u16 = CycleRem(	Move_Divide_NUM * step_x + Move_Divide_NUM * step_y / data_i32,
																	Move_Pulse_NUM);   //data_u16存值:step_x这一步各个脉冲的传感器读取值
						Stockpile_Flash_Data_Write_Data16(&stockpile_quick_cali, &data_u16, 1);  //分为开始、中间、结尾3个区间获取并存入flash
						encode_cali.result_num++;
					}
				}
				else if(step_x == encode_cali.rcd_x + Move_Step_NUM){//结束边缘
					for(step_y = 0; step_y < encode_cali.rcd_y; step_y++){
						data_u16 = CycleRem(	Move_Divide_NUM * step_x + Move_Divide_NUM * step_y / data_i32,
																	Move_Pulse_NUM);
						Stockpile_Flash_Data_Write_Data16(&stockpile_quick_cali, &data_u16, 1);
						encode_cali.result_num++;
					}
				}
				else{//中间
					for(step_y = 0; step_y < data_i32; step_y++){
						data_u16 = CycleRem(	Move_Divide_NUM * step_x + Move_Divide_NUM * step_y / data_i32,
																	Move_Pulse_NUM);
						Stockpile_Flash_Data_Write_Data16(&stockpile_quick_cali, &data_u16, 1);
						encode_cali.result_num++;
					}
				}
			}
		}
		else  //以下是反转的情况,同样也是把每一步的每个脉冲的传感器数值存入flash
		{
			for(step_x = encode_cali.rcd_x + Move_Step_NUM; step_x > encode_cali.rcd_x - 1; step_x--)   
			{
				data_i32 = CycleSub(	encode_cali.coder_data_f[CycleRem(step_x, Move_Step_NUM)],
															encode_cali.coder_data_f[CycleRem(step_x+1, Move_Step_NUM)],
															CALI_Encode_Res);
				if(step_x == encode_cali.rcd_x+Move_Step_NUM){//开始边缘
					for(step_y = encode_cali.rcd_y; step_y < data_i32; step_y++){
						data_u16 = CycleRem(	Move_Divide_NUM * (step_x+1) - Move_Divide_NUM * step_y / data_i32,
																	Move_Pulse_NUM);
						Stockpile_Flash_Data_Write_Data16(&stockpile_quick_cali, &data_u16, 1);
						encode_cali.result_num++;
					}
				}
				else if(step_x == encode_cali.rcd_x){//结束边缘
					for(step_y = 0; step_y < encode_cali.rcd_y; step_y++){
						data_u16 = CycleRem(	Move_Divide_NUM * (step_x+1) - Move_Divide_NUM * step_y / data_i32,
																	Move_Pulse_NUM);
						Stockpile_Flash_Data_Write_Data16(&stockpile_quick_cali, &data_u16, 1);
						encode_cali.result_num++;
					}
				}
				else{//中间
					for(step_y = 0; step_y < data_i32; step_y++){
						data_u16 = CycleRem(	Move_Divide_NUM * (step_x+1) - Move_Divide_NUM * step_y / data_i32,
																	Move_Pulse_NUM);
						Stockpile_Flash_Data_Write_Data16(&stockpile_quick_cali, &data_u16, 1);
						encode_cali.result_num++;
					}
				}
			}
		}
		Stockpile_Flash_Data_End(&stockpile_quick_cali);	//结束写数据区
		
		if(encode_cali.result_num != CALI_Encode_Res)   //result_num应该等于2^14
			encode_cali.error_code = CALI_Error_Analysis_Quantity; //报解析数据错误
	}

	//确认校准结果
	if(encode_cali.error_code == CALI_No_Error){
		mt6816.rectify_valid = true;  //磁编码器数据确认
	}
	else{
		mt6816.rectify_valid = false;  //不进行数据的存储
		Stockpile_Flash_Data_Empty(&stockpile_quick_cali);	//清除校准区数据
	}
	
	//运动配置覆盖
	motor_control.stall_flag = true;	//这是电机相关的,可以先不看,意思是堵转保护,即校准后禁用运动控制
	
	//清理校准信号
	encode_cali.state = CALI_Disable;
	encode_cali.trigger = false;			//清除校准触发
}

在实际使用时,当有外部事件要求(例如实体按键,或者用户界面按钮),会进入中断回调函数。
主loop程序会调用Calibration_Loop_Callback()

至此为止,磁编码器和电机驱动芯片的驱动基本完成了,接下去就是最核心的FOC算法实现对步进电机的控制。

未完待续文章来源地址https://www.toymoban.com/news/detail-603946.html

到了这里,关于STM32自学笔记17-步进电机驱动项目-磁编码器的正常使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32篇】DRV8425驱动步进电机

    【STM32篇】4988驱动步进电机_hr4988-CSDN博客         在上篇文章中使用了HR4988实现了步进电机的驱动,在实际运用过程,HR4988或者A4988驱动步进电机会存在电机噪音太大的现象。本次将向各位友友介绍一个驱动简单且非常静音的一款步进电机驱动IC。         DRV8424/25 是适

    2024年04月11日
    浏览(46)
  • STM32CubeMX ULN2003步进电机驱动

    一、28BYJ-48 步进电机  28BYJ-48是一款5线单极步进电机,运行电压为5V。 根据数据表,当28BYJ-48电机在全步模式下运行时,每步对应于11.25°的旋转。这意味着每转有32步 (360°/11.25° = 32)。 如上图所示,步距角=5.625°/64 意思就是每64个脉冲步进电机就会转5.625度,因此我们很容易得

    2024年01月18日
    浏览(48)
  • STM32F4驱动42步进电机(采用驱动器)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 stm32f407zgt6芯片,tb6600驱动器 植树机代码,可以驱动四路42步进电机,以下是只驱动1路。 : 红线接B+(TB6600), 蓝线接B-, 绿线接A-, 黑线接A+ 该图片是转载的。根据本文代码:Signal的-统一接开发板的GND(解

    2024年02月03日
    浏览(52)
  • 【STM32】步进电机及其驱动(ULN2003驱动28BYJ-48丨按键控制电机旋转)

    参考文章与课程:   【视频课程】步进电机基础原理和应用——程子华主讲   【视频课程】电机系列教学视频(基于STM32硬件)——野火   【霄耀在努力】STM32驱动步进电机(原理、程序、解决电机只震动不转动问题)   步进控制系统由以下三个部分组成: 控制器

    2023年04月09日
    浏览(38)
  • STM32控制步进电机:基于HAL库定时器中断的闭环步进电机驱动+精准控制脉冲数

    该篇文章中用到的步进电机闭环驱动器为Emm42_V4.0步进电机闭环驱动器。该闭环驱动器自带FOC矢量闭环控制算法,能实现力矩、速度、位置三环控制。 如下图所示,该42步进闭环电机驱动器的A+、A-、B+、B-连接步进电机,通过右侧的使能、脉冲、方向端对步进电机进行驱动控制

    2024年02月01日
    浏览(46)
  • 【STM32】实战3.1—用STM32与TB6600驱动器驱动42步进电机(一)

    目录 0 参考资料出处 1 实验预期效果 2 硬件学习 2.1 TB6600驱动器  2.1.1 通过拨码开关设定细分与电流 2.1.2 共阴共阳接线法 2.2 开关电源(AC转DC变压器) 电源线 2.3 42步进电机 2.3.1 基本知识 2.3.2 转速细分控制 2.3.3 满步、半步、微步驱动原理 3 软件配置与硬件接线 3.1 STM32CubeM

    2024年02月02日
    浏览(45)
  • STM32+A4988拓展板+HAL实现简单42步进电机驱动

    1.A4988及其拓展板简介 2.接线 3.STM32_CUBEMX配置 4.代码详解 ——————————————————————————————————————————— 1.A4988及其拓展板简介 A4988 A4988拓展板     A4988是一款常用的步进电机驱动器,A4988驱动器采用了步进电机的微步技术,能

    2024年01月22日
    浏览(71)
  • stm32使用TB6600驱动器控制42BYGH型步进电机

    stm32使用TB6600驱动器控制42BYGH型步进电机 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 24V电源就是通过电路控制开关进行高速的导通于截至,将直流电转化为高频率的交流电提供给变压

    2024年02月11日
    浏览(38)
  • stm32F103单片机pwm控制伺服驱动器进而控制步进电机

    1.需要一台步进电机,私服驱动器,stm32单片机;先按照说明文档,连接好硬件相关线路,对应好sign+,sign-,puls+,puls-线路,其中sign只是个io口拉高拉低操作,puls是pwm波形输出口,虽然有两根线,但只是需要控制一个IO口输出波形即可; 采用主从模式,TIM1为主定时器,tim3未从定

    2024年02月04日
    浏览(41)
  • 设计分享 | STM32F103RCT6利用ULN2003驱动步进电机正反转

    https://mp.weixin.qq.com/s?__biz=Mzg4Mzc3NDUxOQ==mid=2247484170idx=1sn=3fa68d0fbf30cf614e8779abf38c3e2bchksm=cf430652f8348f44e4b95bb7b22ce7f9f5a86e13f421741aefd08cedb169708309c79566ab1ftoken=1923877603lang=zh_CN#rd https://mp.weixin.qq.com/s?__biz=Mzg4Mzc3NDUxOQ==mid=2247484170idx=1sn=3fa68d0fbf30cf614e8779abf38c3e2bchksm=cf430652f8348f44e4b95bb7b22ce7f9f5a8

    2023年04月17日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包