请选择 进入手机版 | 继续访问电脑版

你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【NUCLEO-C031C6】 FOC开环控制

[复制链接]
vecang 发布时间:2024-3-27 00:22

前言

完成的板子还没到,先用了灯哥的驱动模块测试了。驱动板上驱动自带了mos和死去控制,所以暂时不用互补的PWM(cubemx上已完成互补配置,此篇文章里的驱动并未使用到)。先发一张马鞍波:)image.png

软件设置

  • 1、TIM PWM设置
  • image.png
  • PWM配置了3组互补PWM和一个用于采样ADC的PWM. CCR为4800/2,RCR设置为1. TRGO设置为OC4REF。前3组PWM模式为mode1,PWM4模式为mode2。
  • 2、ADC配置
  • image.png
  • image.png
  • ADC配置比较简单,使能DMA循环采样,设置PWM4过来的触发源。
  • 3、NVIC
  • image.png
  • 使能TIM1中断
  • 4、时钟树配置

image.png

5、初始化顺序

image.png

要保证DMA在ADC初始化之前,这里可以调整顺序。

之后便可以生成文件。

驱动代码

这里使用Matlab生成的代码,稍微修改了点。以下是svpwm代码。

  • foc.c
#include "foc.h"

ExtU rtU;
ExtY rtY;

/* Model step function */
void foc_step(void) {
    int sector;
    float T1;
    float rtb_ualpha;
    float rtb_ubeta;

    T1 = sinf(rtU.theta);
    rtb_ubeta = cosf(rtU.theta);
    rtb_ualpha = (float) rtU.ud * rtb_ubeta - (float) rtU.uq * T1;
    rtb_ubeta = (float) rtU.ud * T1 + (float) rtU.uq * rtb_ubeta;

    sector = 0;

    if (rtb_ubeta > 0.0F) {
        sector = 1;
    }

    if ((1.73205078F * rtb_ualpha - rtb_ubeta) / 2.0F > 0.0F) {
        sector += 2;
    }

    if ((-1.73205078F * rtb_ualpha - rtb_ubeta) / 2.0F > 0.0F) {
        sector += 4;
    }

    switch (sector) {
        case 1:
            T1 = (-1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm / rtU.udc);
            rtb_ualpha = (1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm / rtU.udc);
            break;

        case 2:
            T1 = (1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm / rtU.udc);
            rtb_ualpha = -(1.73205078F * rtb_ubeta * rtU.Tpwm / rtU.udc);
            break;

        case 3:
            T1 = -((-1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm / rtU.udc));
            rtb_ualpha = 1.73205078F * rtb_ubeta * rtU.Tpwm / rtU.udc;
            break;

        case 4:
            T1 = -(1.73205078F * rtb_ubeta * rtU.Tpwm / rtU.udc);
            rtb_ualpha = (-1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm / rtU.udc);
            break;

        case 5:
            T1 = 1.73205078F * rtb_ubeta * rtU.Tpwm / rtU.udc;
            rtb_ualpha = -((1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm / rtU.udc));
            break;

        default:
            T1 = -((1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm / rtU.udc));
            rtb_ualpha = -((-1.5F * rtb_ualpha + 0.866025388F * rtb_ubeta) * (rtU.Tpwm /
                                                                              rtU.udc));
            break;
    }

    rtb_ubeta = T1 + rtb_ualpha;
    if (rtb_ubeta > rtU.Tpwm) {
        T1 /= rtb_ubeta;
        rtb_ualpha /= T1 + rtb_ualpha;
    }

    rtb_ubeta = (rtU.Tpwm - (T1 + rtb_ualpha)) / 4.0F;
    T1 = T1 / 2.0F + rtb_ubeta;
    switch (sector) {
        case 1:
            rtY.Tcmp1 = T1;
            rtY.Tcmp2 = rtb_ubeta;
            rtY.Tcmp3 = rtb_ualpha / 2.0F + T1;
            break;

        case 2:
            rtY.Tcmp1 = rtb_ubeta;
            rtY.Tcmp2 = rtb_ualpha / 2.0F + T1;
            rtY.Tcmp3 = T1;
            break;

        case 3:
            rtY.Tcmp1 = rtb_ubeta;
            rtY.Tcmp2 = T1;
            rtY.Tcmp3 = rtb_ualpha / 2.0F + T1;
            break;

        case 4:
            rtY.Tcmp1 = rtb_ualpha / 2.0F + T1;
            rtY.Tcmp2 = T1;
            rtY.Tcmp3 = rtb_ubeta;
            break;

        case 5:
            rtY.Tcmp1 = rtb_ualpha / 2.0F + T1;
            rtY.Tcmp2 = rtb_ubeta;
            rtY.Tcmp3 = T1;
            break;

        case 6:
            rtY.Tcmp1 = T1;
            rtY.Tcmp2 = rtb_ualpha / 2.0F + T1;
            rtY.Tcmp3 = rtb_ubeta;
            break;
    }

    rtY.sector = (float) sector;
}
  • foc.h
#ifndef RTW_HEADER_foc_h_
#define RTW_HEADER_foc_h_
#include <math.h>

typedef struct {
  double ud,uq;
  float theta, udc,Tpwm;
} ExtU;

typedef struct {
  float Tcmp1,Tcmp2,Tcmp3;
  float sector;
} ExtY;

extern ExtU rtU;
extern ExtY rtY;
extern void foc_step(void);

#endif                                 /* RTW_HEADER_foc_h_ */
  • main.c
.....

/* USER CODE BEGIN Includes */
#include "foc.h"
/* USER CODE END Includes */

.....


/* USER CODE BEGIN PV */
#define PI 3.1415926
uint16_t adc1_val_buf1[4] = {0};
extern ExtU rtU;
extern ExtY rtY;
extern DMA_HandleTypeDef hdma_adc1;
void dmaAdcCallback(struct __DMA_HandleTypeDef *hdma);
/* USER CODE END PV */

.....

int main(void)
{
  ....

  /* USER CODE BEGIN Init */
    rtU.ud = 0;
    rtU.uq = 2;
    rtU.Tpwm = 4800;
    rtU.udc = 12;

  ....

  /* USER CODE BEGIN 2 */
    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&adc1_val_buf1,2);
    hdma_adc1.XferCpltCallback = dmaAdcCallback;
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
  /* USER CODE END 2 */

  ....
}
....

/* USER CODE BEGIN 4 */
void dmaAdcCallback(struct __DMA_HandleTypeDef *hdma) {
    rtU.theta += 0.01;
    if (rtU.theta >= 2.0f * PI) {
        rtU.theta -= 2.0f * PI;
    }
    foc_step();
    htim1.Instance->CCR1 = (uint16_t) rtY.Tcmp3;
    htim1.Instance->CCR2 = (uint16_t) rtY.Tcmp2;
    htim1.Instance->CCR3 = (uint16_t) rtY.Tcmp1;
}

/* USER CODE END 4 */
....

调试

使用STM32CubeMonitor,观察输出的PWM。

image.png

至此电机已经旋转起来了^^

存在的问题

image.png

不知道是什么问题,cmake设置是默认的设置。写完这些板子flash就快满了,设置加不下一个串口的功能。。。。不知道是否有大佬知道是什么问题?

image.png
image.png
收藏 评论0 发布时间:2024-3-27 00:22

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版