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

调用STM32 MCSDK库 API调节电机速度

[复制链接]
CM_STM32 发布时间:2026-7-17 00:52

在上一节中我们调用STM32 MCSDK的API获取了观测器,测量得到2208电机的转速值,并同AS5600编码器返回的速度值进行比对,验证了观测器在中高速运行状态下的灵敏度和准确性。这一节我们将使用板载电位器,尝试完成速度调节功能,并将目标速度显示到ST7735 LCD屏幕上。

工程创建、电机参数的测定、屏幕驱动和硬件连接在前面几篇文章都已经提及,此处不再赘述。

e1a7f2f0-e5e3-4325-b5c8-ac93b5728b84.png

1.引脚分配

查看IHM16M1开发板原理图,可以发现电位器SPEED网络连接到STM32G431的PC2引脚,因此我们在CubeMX中将PC2配置为ADC1_IN8通道,并设置ADC1_IN8为单端输入模式。

因为ADC1同样用于电机母线电压、电流等等的测量,故最好不要修改ADC已经配置好的参数,直接使用即可。

0e339169-eb3b-4c18-a1f1-5178cd4dfec9.png

f179776b-85d3-4875-b2c3-3fa789efe934.png

2.MCSDK API介绍

MCSDK的API在mc_api.h/.c中提供。下面介绍的是本文中将调用的接口。

①启停接口:

bool MC_StartMotor1 (void)

启动电机1的启动程序。

bool MC_StopMotor1 (void)

启动电机1的停止程序。

②状态接口:

int16_t MC_GetMecSpeedReferenceMotor1 (void)

返回电机1的当前机械转子转速参考,以SPEED_UNIT定义的单位表示。

关于SPEED_UNIT有如下解释: 转速单位用于与应用程序的接口。 这个符号定义了API函数用于其速度参数的单位中1赫兹的值。 例如,如果选择的单位是RPM,则SPEED_UNIT被定义为60,因为1 Hz等于60 RPM。默认的单位是U_01HZ,由Workbench在项目的初始生成中设置。由于此符号是在用户节中定义的,因此用户设置的自定义值将在整个项目再生过程中持续存在。 电机控制工作台计算的调速PID参数适用于01Hz的转速。电机控制子系统内部缩放它们以适应实际的速度单位。 此符号不应设置为文字数值。相反,应该将其设置为为此目的预定义的符号之一,例如U_RPM, U_01HZ,…有关详细信息,请参阅SpeedUnit。

int16_t MC_GetMecSpeedAverageMotor1 (void)

返回电机1最后一次计算的平均机械转子转速,用SPEED_UNIT定义的单位表示。

MCI_State_t MC_GetSTMStateMotor1 (void)

返回电机1状态机的当前状态。

uint16_t MC_GetCurrentFaultsMotor1 (void)

返回一个位字段,显示电机1上的所有当前故障。

③修改速度参数接口:

void MC_ProgramSpeedRampMotor1 (int16_t hFinalSpeed, uint16_t hDurationms)

修改电机1的目标速度。

如果电机1的状态机处于RUN状态,则立即执行。可以使用MC_GetCommandStateMotor1() 检查命令的状态。如果应用程序使用无传感器电机控制技术,则不能反转旋转方向。如果hFinalSpeed参数的符号与当前速度的符号不同,则当转速即将达到0rpm时,将不会完成速度斜坡并发生速度反馈错误(MC_SPEED_FDBK)。

其他的函数接口可以自行查阅。

3.程序分析及编写

①原理分析

STM32G431的ADC模数转换器将模拟信号转换为12位数字值,范围是0~4095。在MCSDK的FOC框架中,ADC1和ADC2被主控制器占用,其高频任务通过注入通道实时采样三相电流信号,用于驱动电流反馈控制环。

最开始编写代码直接调用HAL原生函数,每 20ms 直接改ADC1通道去读电位器,导致和MCSDK的ADC任务抢资源,启动过后卡住并直接报错。为了避免这类资源竞争,MCSDK提供了RCM(Regular Conversion Manager)组件来允许用户访问ADC。RCM通过注册机制让用户代码提交转换请求,然后在FOC的高频任务中,利用FOC的安全时间窗口来执行这些常规转换,电位器读取就能在不破坏FOC运行的前提下安全进行。改用RCM而不是 HAL_ADC_ConfigChannel() 之后,电位器读取功能不再抢占FOC任务的资源,程序顺利运行。

我们可以查看RCM的头文件regular_conversion_manager.h的内容:

一个结构体定义,包含了执行转换时需要的所有参数,注册ADC通道时需要先定义好一个 RegConv_t:

typedef struct
{
  ADC_TypeDef *regADC;    /*!< ADC peripheral used for the conversion */
  uint32_t samplingTime;  /*!< ADC sampling time used for the conversion */
  uint8_t channel;        /*!< ADC channel used for the conversion */
  uint16_t data;          /*!< ADC converted value */
  uint8_t id;             /*!< index of the conversion in RCM array */
} RegConv_t;

typedef void (*RCM_exec_cb_t)(RegConv_t *regConv, uint16_t data, void *UserData);

用于注册规则转换的函数:

bool RCM_RegisterRegConv(RegConv_t *regConv);

用于在 HF 任务内部启动转换的非阻塞函数:

void RCM_ExecNextConv(void);

用于回读已经开始的规则转换的非阻塞函数:

void RCM_ReadOngoingConv(void);

用于执行已经注册的规则转换的函数:

uint16_t RCM_ExecRegularConv(RegConv_t *regConv);

用于读取存储在数据结构中的规则转换结果的函数:

static inline uint16_t RCM_GetRegularConv(const RegConv_t *regConv)
{
#ifdef NULL_PTR_CHECK_REG_CON_MNG
  return ((MC_NULL == regConv) ? 0U : regConv->data);
#else
  return (regConv->data);
#endif
}

用于等待规则转换结果的函数:

void RCM_WaitForConv(void);

因为FOC任务中已经有规律地执行RCM转换,所以以上接口只需要调用 RCM_RegisterRegConv(RegConv_t regConv) 注册RCM,以及 RCM_GetRegularConv(const RegConv_t regConv) 读取RCM的结果即可。

注意到ADC1数据设置为左对齐,在计算的时候应该右移4位,否则计算得到的数据会是实际值的4倍。

42aec892-c193-4040-9ac9-94b88b887202.png

②程序编写

定义以下变量以及结构体:

//ADC采集及目标速度计算的定时
static uint32_t pot_update_time = 0;
static const uint32_t POT_UPDATE_INTERVAL = 20; // 20ms

static uint16_t pot_raw_latest = 0xFFFF; //原始的16位数据
static int16_t pot_target_rpm_latest = 0; //计算后的速度值
static bool pot_regconv_registered = false; //注册RCM的返回值,bool类型

//用于注册RCM的结构体
static RegConv_t PotRegConv =
{
  .regADC = ADC1,
  .channel = MC_ADC_CHANNEL_8,
  .samplingTime = LL_ADC_SAMPLINGTIME_47CYCLES_5,
  .data = 0U
};

在显示刷新函数中加入目标速度的刷新,同样,当检测到目标速度发生改变时才刷新显示:

static void Display_UpdateMotorInfo(void)
{
//……
//显示上加入目标速度                                                             
  if (pot_target_rpm_latest != last_target_rpm)
  {
    snprintf(line_buf, sizeof(line_buf), "%4d rpm", pot_target_rpm_latest);
    ST7735_ShowString(56, 88, BLACK, WHITE, line_buf);
    last_target_rpm = (uint16_t)pot_target_rpm_latest;
  }
}

速度更新函数,主要负责读取ADC1_IN8、计算ADC映射的速度值,并通过 MC_ProgramSpeedRampMotor1_F()接口将浮点数速度值更新到电机1的状态机中。

加入了保护机制:电机状态不为RUN的时候不更新速度曲线的终值,RCM未注册的时候也不更新速度曲线的终值。

计算方面,因为ADC的12位数据设置为左对齐,所以需要先右移4位进行右对齐;将0~4095的计数值映射到0~最大速度值,最大速度调用pmsm_motor_parameter.h里的MOTOR_MAX_SPEED_RPM宏定义,保证与MCSDK的设置统一。

最后调用MC_ProgramSpeedRampMotor1_F((float_t)target_rpm, 50U)上传速度值,加减速时间设定为50ms。

static void Pot_UpdateSpeedCommand(void)
{
  MCI_State_t motor_state = MC_GetSTMStateMotor1();

  /* Avoid buffering speed ramps before RUN, otherwise startup target can be overridden to 0 rpm. */
  if (motor_state != RUN)
  {
    last_pot_target_rpm = INT16_MIN;
    return;
  }

  if (!pot_regconv_registered)
  {
    return;
  }

  uint16_t pot_raw = RCM_GetRegularConv(&PotRegConv);
  uint16_t pot_raw_12b = (uint16_t)(pot_raw >> 4);

  /* ADC is configured as left-aligned 12-bit, convert back to 0..4095 first. */
  /* Map 0..4095 to 0..MOTOR_MAX_SPEED_RPM */
  int16_t target_rpm = (int16_t)(((uint32_t)pot_raw_12b * MOTOR_MAX_SPEED_RPM) / 4095U);

  pot_raw_latest = pot_raw;
  pot_target_rpm_latest = target_rpm;

  if (target_rpm != last_pot_target_rpm)
  {
    MC_ProgramSpeedRampMotor1_F((float_t)target_rpm, 50U);
    last_pot_target_rpm = target_rpm;
  }
}

在主函数的初始化阶段,需要先完成RCM的注册,保证电位器的正常使用:

pot_regconv_registered = RCM_RegisterRegConv(&PotRegConv);

在while循环中需要定时调用Pot_UpdateSpeedCommand()任务:

  while (1)
  {
    if (HAL_GetTick() - encoder_update_time >= ENCODER_UPDATE_INTERVAL)
    {
      Encoder_UpdateFromAS5600();
      encoder_update_time = HAL_GetTick();
    }

    if (HAL_GetTick() - pot_update_time >= POT_UPDATE_INTERVAL)
    {
      Pot_UpdateSpeedCommand();
      pot_update_time = HAL_GetTick();
    }

    if (lcd_init_done && (HAL_GetTick() - display_update_time >= DISPLAY_UPDATE_INTERVAL))
    {
      Display_UpdateMotorInfo();
      display_update_time = HAL_GetTick();
    }
  }

代码已经上传到Github上:Github仓库:https://github.com/Chiando-1100/IHM16M1_Display

收藏 评论0 发布时间:2026-7-17 00:52

举报

0个回答

所属标签

ST 电机控制

意法半导体提供完整的电机控制解决方案,包括合适的电子器件,诸如集成式智能功率模块和系统级封装、单片式电机驱动器、快速高效的功率开关、具有电压暂态保护功能的可控硅、以及功能强大且安全的微控制器等。以及提供完整的生态系统(包括一系列评估板、参考设计、固件和开发工具),以简化和加速设计流程。


最新内容

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版