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

news2024/11/24 10:35:19

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 4800

float 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.28318530718
  if(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 optimized
    return 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 optimized
    return -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 optimized
    return -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 fat
  long 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 precision
  return 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/3
	if(Uref<-0.577)Uref=-0.577;

	if(Uq>0)
	  angle_el =_normalizeAngle(angle_el+_PI_2); //加90度后是参考电压矢量的位置
	else
		angle_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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1804095.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

独立游戏之路 -- TapTap广告收益损失和常见问题

一个操作带来的TapTap广告收益损失 一,收益损失1.1 广告入口1.2 损失对比二,常见问题2.1 有展现量没有预估收益 /eCPM 波动大?2.2 新建正式媒体找不到预约游戏2.3 聚合模式由于没有回传 oaid 无数据2.4 每日观看次数限制是否有限制一,收益损失 1.1 广告入口 TapTap广告联…

针对业务系统的主备容灾实战原理-基础版

1、前言 本文主要在于介绍&#xff1a;通过系统的实时容灾功能模块&#xff0c;针对用户云计算中关键业务系统的主备容灾方案原理。 涉及到的技术能力、运维能力要求偏高&#xff0c;遂本文尽量将容灾原理讲解清楚。需要用到的云计算能力包括&#xff1a;计算机操作系统(Linu…

初入阿里云,上手走一波

初入阿里云&#xff0c;上手走一波 一阶&#xff1a;ECSMysqlDMS安装Mysql初始化MysqlMysql操作DMS管理Mysql 二阶&#xff1a;ECSOSS远程连接ECSOSS控制台其他图片服务 三阶&#xff1a;更多搭配操作 可以说个人在日常使用过程中&#xff0c;操作最多的阿里云产品就是阿里云服…

【el-tooltips改造】Vue实现文本溢出才显示el-tooltip,否则不显示el-tooltips

实现原理&#xff1a; 使用disabled属性控制el-tooltip的content显示与隐藏&#xff1b; 目标&#xff1a; 1行省略、多行省略、可缩放页面内的文本省略都有效。 实现方式&#xff1a; 1、自定义全局指令&#xff0c;tooltipAutoShow.js代码如下&#xff08;参考的el-table中的…

【Python学习路线(课程大纲+Python视频教程+下载地址)_python 教程下载。】

目前Python已经成为最受欢迎的程序设计语言之一。Python的设计哲学是“优雅”、“明确”、“简单”。 学习Python具有多重显著的好处。首先&#xff0c;Python的语法简洁易读&#xff0c;降低了编程的入门门槛&#xff0c;使初学者能够更快地掌握编程的基本概念。其次&#xff…

自定义拦截器

大家好&#xff0c;这里是教授.F 前菜&#xff1a; 拦截器是由springmvc来接管的&#xff0c;过滤器使用服务器来接管的。 ● 自定义拦截器的三个方法[自定义的拦截器必须实现 HandlerInterceptor 接口] 1. preHandle()&#xff1a;这个方法在业务处理器处理请求之前被调用&…

SVG不保持横纵比,完全由设置宽高任意拉伸填充

想要通过变形伸缩 填充元素的方式使用 svg&#xff0c;试了很多办法&#xff0c;终于找到的。 之前试过img形式显示svg虽然合适变形伸缩&#xff0c;但不能设置颜色。下面是正确效果的使用说明。 在源码svg中加 preserveAspectRatio"none" <svg width"…

访问网站时IP被阻止?原因及解决方法

在互联网上&#xff0c;用户可能会面临一个令人困扰的问题——当尝试访问某个特定的网站时&#xff0c;却发现自己的IP地址被该网站屏蔽。 IP地址被网站屏蔽是一个相对常见的现象&#xff0c;而导致这种情况的原因多种多样&#xff0c;包括恶意行为、违规访问等。本文将解释IP地…

Linux环境在非root用户中搭建(java-tomcat-redis)

注: 本文在内网(离线)环境&#xff0c;堡垒机中搭建&#xff0c;服务器不同可能有所差异&#xff0c;仅供参考 本文安装JDK-20.0.1版本&#xff0c;apache-tomcat-10.1.10版本&#xff0c;redis-6.2.15版本 本文服务器IP假设&#xff1a;192.168.88.133 root用户创建子用户并…

vue3 实现自定义指令封装 --- 通俗易懂

1、局部自定义指令 1.1 在<script setup>定义组件内的指令&#xff0c;任何以v开头的驼峰式命名的变量都可以被用作一个自定义指令 <template><div><h3>使用自定义指令</h3><div>########################## start 局部自定义指令</d…

哈希桶封装unordered_map、unordered_set

哈希桶源代码 我们将由下列的哈希桶来模拟封装STL库中的unordered_map和unordered_set 注意&#xff1a;为了实现封装unordered_map和unordered_set&#xff0c;我们需要对下列源码进行优化。 //哈希桶 namespace hashbucket {template<class K,class V>struct HashNo…

【YOLOv7改进系列】简化YOLOv7-tiny池化层,便于引入改进的池化层

〇、前言 相比YOLOv5/v7&#xff0c;除了YOLOv5n外&#xff0c;YOLOv7tiny的参数量较小&#xff0c;效果往往也相较YOLOv5n高上不少&#xff0c;又近来博主打算改进yolov7-tiny文件&#xff0c;但苦于其池化层部位是直接写在yaml中的&#xff0c;修改极为不便&#xff0c;因此…

使用安装包安装tomcat

Apache Tomcat 是一个开源的 Java 服务器&#xff0c;用于运行 Java Servlet、JavaServer Pages (JSP) 和相关的 Java 平台技术。它是一个轻量级的、灵活的容器&#xff0c;用于在 Java 环境中部署和管理 Web 应用程序。 以下是 Tomcat 的一些主要特点和功能&#xff1a; 1.Ser…

QNX 7.0.0开发总结

1 QNX编译 1.1 基本概念 QNX可以直接使用Linux Makefile编译库和二进制&#xff0c;在Makefile文件中指定CCaarch64-unknown-nto-qnx7.0.0-g&#xff0c;或者CCx86_64-pc-nto-qnx7.0.0-g&#xff0c;保存退出后&#xff0c;运行source /qnx_sdk_path/qnxsdp-env.sh&#xff0c;…

Day50 动态规划part09

LC198打家劫舍 偷前一家或者偷前两家和这家&#xff1a;dp[i] Math.max(dp[i-2]nums[i],dp[i-1]);代码 LC213打家劫舍II&#xff08; 未掌握&#xff09; 解题思路&#xff1a;因为成环了&#xff0c;所以首位元素一定是两者只能选择一个或者两者都不选三种情况&#xff1…

Android 11 低电量自动关机失效

Android 11 低电量自动关机 概述 安卓系统设计了低电关机功能&#xff0c;旨在当手机电池电量过低时自动关机&#xff0c;以保护手机硬件和数据安全。该功能由以下几个部分组成&#xff1a; 电池电量监测: 安卓系统通过 BatteryService 组件持续监测电池电量。BatteryService…

展厅设计中的不同区域划分

1、公共区域 公共区域一般来说是不受限制的区域&#xff0c;这种情况下&#xff0c;会使我们想到的区域是大厅、售卖区、视频播放等&#xff0c;这些公共区域的相关设施比较完善&#xff0c;只是需要普通的安全保护设施及警报设备即可。 2、展览区域 展览区域是参观者能够触及到…

创新指南|2024企业如何开启生成式AI创新?从5大应用场景和6步抓手

想要了解如何采用生成式AI来提高企业效率和竞争力&#xff1f;本指南将介绍如何采用生成式AI来实现数字化转型&#xff0c;并打造智能化商业模式。从5大应用场景和6大步骤切入&#xff0c;让您了解如何开启生成式AI创新。立即连线创新专家咨询或观看创新战略方案视频进一步了解…

业务扩张阶段

和之前相比就是服务器的数量增多了 业务系统增多了 每个业务的用户也在增多 采购费用和电费挺多 选课系统一年只用几次&#xff0c;平时不用太浪费服务器的资源&#xff0c;那么怎么才能提高服务器资源的利用率呢 在一个服务器上部署多个不同的业务系统能行吗 不太行&…

基于大模型 Gemma-7B 和 llama_index,轻松实现 NL2SQL

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学. 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总合集&…