HAL STM32F1 通过查表方式实现SVPWM驱动无刷电机测试

2024-06-09 04:04

本文主要是介绍HAL STM32F1 通过查表方式实现SVPWM驱动无刷电机测试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

HAL STM32F1 通过查表方式实现SVPWM驱动无刷电机测试


  • 📍相关篇《基于开源项目HAL STM32F4 +DSP库跑SVPWM开环速度测试》
  • ✨针对STM32F1系列,硬件上没有可用的浮点单元(FPU),为了实现特定函数的浮点运算快速计算,通过查表方式来实现,以空间换速度的方式。
  • 📍硬件电路和项目参考,立创开源广场:https://oshwhub.com/shadow27/tai-yang-neng-wu-ren-chuan
  • 📌 采用6路驱动控制,可以参考个人的相关篇《自制无感无刷电机驱动板》

📘实现核心代码

  • 📑svpwm.c
#include "tim.h"#include "svpwm.h"#include "stdio.h"#define PWM_Period 4800float voltage_power_supply=12; //母线电压12V
float sensor_offset=0;
float zero_electric_angle=0;float _normalizeAngle(float angle)// 标准化角度 [0,2PI]
{float a = fmod(angle, _2PI);                     //fmod()对浮点数取模return a >= 0 ? a : (a + _2PI);
}
//把0~Π/2的正弦值分成200份
const int sine_array[200] = {0,79,158,237,316,395,473,552,631,710,789,867,946,1024,1103,1181,1260,1338,1416,1494,1572,1650,1728,1806,1883,1961,2038,2115,2192,2269,2346,2423,2499,2575,2652,2728,2804,2879,2955,3030,3105,3180,3255,3329,3404,3478,3552,3625,3699,3772,3845,3918,3990,4063,4135,4206,4278,4349,4420,4491,4561,4631,4701,4770,4840,4909,4977,5046,5113,5181,5249,5316,5382,5449,5515,5580,5646,5711,5775,5839,5903,5967,6030,6093,6155,6217,6279,6340,6401,6461,6521,6581,6640,6699,6758,6815,6873,6930,6987,7043,7099,7154,7209,7264,7318,7371,7424,7477,7529,7581,7632,7683,7733,7783,7832,7881,7930,7977,8025,8072,8118,8164,8209,8254,8298,8342,8385,8428,8470,8512,8553,8594,8634,8673,8712,8751,8789,8826,8863,8899,8935,8970,9005,9039,9072,9105,9138,9169,9201,9231,9261,9291,9320,9348,9376,9403,9429,9455,9481,9506,9530,9554,9577,9599,9621,9642,9663,9683,9702,9721,9739,9757,9774,9790,9806,9821,9836,9850,9863,9876,9888,9899,9910,9920,9930,9939,9947,9955,9962,9969,9975,9980,9985,9989,9992,9995,9997,9999,10000,10000};//0~360°的正弦值,函数通过使用固定大小的数组来逼近正弦计算
float _sin(float a){//a的值最大为2Π,即6.28318530718if(a < _PI_2){//a<1.57079632679//return sine_array[(int)(199.0*( a / (_PI/2.0)))];//return sine_array[(int)(126.6873* a)];           // 浮点数组优化return 0.0001*sine_array[_round(126.6873* a)];      // int数组优化}else if(a < _PI){//1.57079632679<=a<3.14159265359// return sine_array[(int)(199.0*(1.0 - (a-_PI/2.0) / (_PI/2.0)))];//return sine_array[398 - (int)(126.6873*a)];          // float array optimizedreturn 0.0001*sine_array[398 - _round(126.6873*a)];     // int array optimized}else if(a < _3PI_2){//3.14159265359<=a<4.71238898038// return -sine_array[(int)(199.0*((a - _PI) / (_PI/2.0)))];//return -sine_array[-398 + (int)(126.6873*a)];           // float array optimizedreturn -0.0001*sine_array[-398 + _round(126.6873*a)];      // int array optimized} else {//4.71238898038<=a<6.28318530718// return -sine_array[(int)(199.0*(1.0 - (a - 3*_PI/2) / (_PI/2.0)))];//return -sine_array[796 - (int)(126.6873*a)];           // float array optimizedreturn -0.0001*sine_array[796 - _round(126.6873*a)];      // int array optimized}
}//0~360°的余弦值,函数逼近余弦计算使用固定大小的数组
float _cos(float a){float a_sin = a + _PI_2;a_sin = a_sin > _2PI ? a_sin - _2PI : a_sin;return _sin(a_sin);
}//近似开根号函数
float _sqrtApprox(float number) {//low in fatlong i;float y;// float x;// const float f = 1.5F; // better precision// x = number * 0.5F;y = number;i = * ( long * ) &y;i = 0x5f375a86 - ( i >> 1 );y = * ( float * ) &i;// y = y * ( f - ( x * y * y ) ); // better precisionreturn number * y;
}// 输入参数0.0f ~ 1.0f,输出3路PWM
//void Set_PWM(float _CCR1, float _CCR2, float _CCR3)
//{
//	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, _CCR1 * PWM_ARR);
//	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, _CCR2 * PWM_ARR);
//	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, _CCR3 * PWM_ARR);
//}//FOC核心函数:输入Ud、Uq和电角度,输出PWM
void setPhaseVoltage(float Uq, float Ud, float angle_el)
{float Uref;uint32_t sector;float T0,T1,T2;float Ta,Tb,Tc;float U_alpha,U_beta;angle_el =_normalizeAngle(angle_el); //电角度标准化在【0,2pi】U_alpha=Ud*_cos(angle_el)-Uq*_sin(angle_el); //反park变换U_beta=Ud*_sin(angle_el)+Uq*_cos(angle_el);Uref=_sqrtApprox(U_alpha*U_alpha + U_beta*U_beta) / voltage_power_supply;if(Uref> 0.577)Uref= 0.577; //六边形的内切圆(SVPWM最大不失真旋转电压矢量赋值)根号3/3if(Uref<-0.577)Uref=-0.577;if(Uq>0)angle_el =_normalizeAngle(angle_el+_PI_2); //加90度后是参考电压矢量的位置elseangle_el =_normalizeAngle(angle_el-_PI_2);sector = (angle_el / _PI_3) + 1; //扇区判断//每个扇区中两个相邻电压矢量Uref作用时间T1 = _SQRT3*sin(sector*_PI_3 - angle_el) * Uref;T2 = _SQRT3*sin(angle_el - (sector-1.0)*_PI_3) * Uref;//零矢量作用时间T0 = 1 - T1 - T2;switch(sector) //计算各相的作用时间{case 1:Ta = T1 + T2 + T0/2;Tb = T2 + T0/2;Tc = T0/2;break;case 2:Ta = T1 +  T0/2;Tb = T1 + T2 + T0/2;Tc = T0/2;break;case 3:Ta = T0/2;Tb = T1 + T2 + T0/2;Tc = T2 + T0/2;break;case 4:Ta = T0/2;Tb = T1+ T0/2;Tc = T1 + T2 + T0/2;break;case 5:Ta = T2 + T0/2;Tb = T0/2;Tc = T1 + T2 + T0/2;break;case 6:Ta = T1 + T2 + T0/2;Tb = T0/2;Tc = T1 + T0/2;break;default:  //其他情况关闭上管,打开下管,即刹车Ta = 0;Tb = 0;Tc = 0;}//printf("[Ta,Tb,Tc]:%f,%f,%f\r\n", Ta, Tb, Tc);__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, Ta*PWM_Period); //输出U相PWM,配置占空比__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2,Tb*PWM_Period);   //输出V相PWM,配置占空比__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, Tc*PWM_Period);  //输出W相PWM,配置占空比}
  • 📄svpwm.h
#ifndef __SVPWM_H__
#define __SVPWM_H__#include <math.h>#define _sign(a) ( ( (a) < 0 )  ?  -1   : ( (a) > 0 ) )
#define _round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define _sqrt(a) (_sqrtApprox(a))
#define _isset(a) ( (a) != (NOT_SET) )#define _2_SQRT3 1.15470053838
#define _SQRT3 1.73205080757
#define _1_SQRT3 0.57735026919
#define _SQRT3_2 0.86602540378
#define _SQRT2 1.41421356237
#define _120_D2R 2.09439510239
#define _PI 3.14159265359
#define _PI_2 1.57079632679
#define _PI_3 1.0471975512
#define _2PI 6.28318530718
#define _3PI_2 4.71238898038
#define _PI_6 0.52359877559//FOC核心函数:输入Ud、Uq和电角度,输出PWM
void setPhaseVoltage(float Uq, float Ud, float angle_el);#endif /* __SVPWM_H__ */
  • 🌿在滴答回调函数中,每隔2毫秒执行一次
void HAL_SYSTICK_Callback(void)
{//  Sys_Tick_Count_1ms();Count++;if (Count >= vtaskms){Count = 0;//Uq和电角度增加值需要自己调,每个电机都不一样setPhaseVoltage(0.5,0.0,angle_el);  //空载的时候尽量让uq<2。Uq越大电机的电流越大,扭力约大angle_el +=0.64;  //估计电角度,电角度增加的越快,电机转的越快。电角度减小则电机反向旋转0.18 0.36 0.54 0.62}
}

🎉在电机能转动的情况下,可以逐步增大电角度(angle_el)数值,以提高转动的速度。在电机能提速的情况下,电流相对会减少。这个速度也不是不限增加的,当程序设定的角度电机执行完,正好与下一次循环设定的角度接近重合时,达到最佳的运转效果。

个人使用2204电机测试,在电角度参数和电机运转步进接近的状态下,空载下运转,电流只有60毫安左右,长时间运转,电机都没有感受发热。

  • 🌿3路PWM驱动波形及参数
    在这里插入图片描述

  • 🌿三相驱动桥,下端电流采样波形
    在这里插入图片描述

📚测试工程

  • 🌿基于3路PWM控制。(EG2133)
    在这里插入图片描述
链接:https://pan.baidu.com/s/1H_5o-4v7Z8x4XBi8RtVU1A?pwd=rcv6 
提取码:rcv6
  • 🌿基于3路互补PWM输出控制。
    在这里插入图片描述
链接:https://pan.baidu.com/s/13mFTlaAbvnjr1eh-rdLQSQ?pwd=2fr7 
提取码:2fr7

这篇关于HAL STM32F1 通过查表方式实现SVPWM驱动无刷电机测试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1044171

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形