STM32F405 FOC 使用Timer 触发 ADC采集

1. ADC采集模式

根据STM32F405数据手册,可以看到ADC block diagram,ADC主要有两种触发模式:

  1. regular conversion mode:常规通道
  2. injected conversion mode:注入通道
    在这里插入图片描述
    在这里插入图片描述

2. 高级Timer模式

这里我们用到的是高级定时器的TRGO功能
在这里插入图片描述
在这里插入图片描述

3. ADC1 连续采集

连续采集有两种实现方式:

3.1 DMA软件触发

转换完成中断中,再次启动DMA转换

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    printf("%d \t %d \t %d \t %d \r\n",adc1_value[0], adc1_value[1], adc1_value[2], adc1_value[3]);
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc1_value, ADC_CHNNELS);
}

3.2 DMA+TIM触发

DMA+TIM触发,由TIM trigger event触发DMA采集,只需要在main函数中启动一次DMA采集即可
参考 STM32CubeMX | HAL库的ADC多通道数据采集(轮训、DMA、DMA+TIM)、读取内部传感器温度)配置,但是发现只能启动一次DMA,测试发现需要将ADC1的DMA continuous request设置为enable
在这里插入图片描述
在这里插入图片描述

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  MX_ADC1_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
    printf("init finished \r\n");
    HAL_Delay(100);

    HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rcv_buff, sizeof(rcv_buff));
    HAL_TIM_Base_Start(&htim3);
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_Value, ADC_CHNNELS);


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
      commander_run();
      HAL_Delay(500);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

4. ADC 注入模式采集

  1. 启动TIM1,默认设置占空比50%
    在这里插入图片描述

  2. 启动ADC中断,注入模式
    __HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_JEOC);
    HAL_ADCEx_InjectedStart(&hadc1);

    /*启动TIM1 */
    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_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
    /*启动ADC1,regular conversion DMA模式*/
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc1_value, ADC_CHNNELS);
    /*启动ADC1,Enable the ADC end of conversion interrupt.*/
    __HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_JEOC);
    HAL_ADCEx_InjectedStart(&hadc1);
  1. 在ADC注入中断回调函数中采集,并通过PC4引脚查看是否有输出请添加图片描述
    这里设置TIM1的Repetition Counter = 1, 每2次计数周期触发一次Trigger out event。通道2-PWM-CH1(24KHz),通道1-PC4脚(12KHz)。
    可以看到PWM-CH1通道周期24KHz,一个计数周期3500,每2个计数周期(7000),触发一次Trigger out event,中断内PC4转换电平。
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    m0_phB = hadc->Instance->JDR1;
    m0_phC = hadc->Instance->JDR2;
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_4);
}

PS:小问题,这里是PWM1通道高电平打开时,触发ADC转换。实际FOC中需要下管为高时采样。需要把PWM CH polarity和PWM CHN polarity设置为low。但是这样设置会导致FOC计算出来的Ta,Tb,Tc参数都需要调整

5. 最终使用方法

采用TIM1的Channel4作为Trigger Event,以此来触发ADC采样。而不用第2节中的Timer update Event。
在这里插入图片描述
在这里插入图片描述
ADC设置不用改变,仍然使用注入模式,Trigger source 选择Timer1 Trigger out event

在这里插入图片描述

参考:

  1. STM32 定时器触发 ADC 多通道采集,DMA搬运至内存
  2. STM32CubeMX | HAL库的ADC多通道数据采集(轮训、DMA、DMA+TIM)、读取内部传感器温度
  3. 野火STM32电机系列(六)Cubemx配置ADC规则和注入通道
  4. 电机FOC控制(三)STM32 CUBEMX 配置ADC采样
  5. 电机FOC控制(二)STM32 CUBEMX 配置三相PWM互补输出
  • 29
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用HAL库在STM32F405上实现FOC(Field Oriented Control)的TIM(定时器)初始化代码示例: ```c // 定义定时器句柄 TIM_HandleTypeDef htim1; // 定义FPU控制状态类型 typedef enum { FPU_CONTROL_CORRECTLY_INITIALIZED = 0U, // FPU控制状态正确初始化 FPU_CONTROL_NOT_INITIALIZED = 1U // FPU控制状态未初始化 } FPU_CONTROL_Type; // 初始化FPU控制状态 static FPU_CONTROL_Type FPU_GetControlStatus(void) { uint32_t result = FPU_CONTROL_NOT_INITIALIZED; uint32_t regValue = 0U; regValue = FPU->FPCCR; if ((regValue & (uint32_t)FPU_FPCCR_ASPEN_Msk) && (regValue & (uint32_t)FPU_FPCCR_LSPEN_Msk)) { result = FPU_CONTROL_CORRECTLY_INITIALIZED; } return ((FPU_CONTROL_Type)result); } // 初始化TIM1 void MX_TIM1_Init(void) { // 初始化FPU控制状态 if (FPU_GetControlStatus() == FPU_CONTROL_NOT_INITIALIZED) { // 打开FPU __FPU_ENABLE(); // 打开浮点数运算单元 __FPU_SET_FP_ROUNDING_MODE(FPU_ROUND_NEAREST); __FPU_SET_FP_EXCEPTION_MASK(FPU_IEEE_Msk); } // 定义TIM1初始化参数 TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; htim1.Init.Period = 8399; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 1; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim1) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC4REF; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { Error_Handler(); } sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; sBreakDeadTimeConfig.DeadTime = 0; sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) { Error_Handler(); } // 定义PWM通道初始化参数 TIM_OC_InitTypeDef sConfigOC = {0}; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; // 初始化PWM通道1 if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } // 初始化PWM通道2 if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } // 初始化PWM通道3 if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) { Error_Handler(); } // 初始化PWM通道4 if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } // 启动TIM1 if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } } ``` 此代码示例初始化了一个带有4个PWM通道的TIM1,用于驱动FOC控制的三相电机。在初始化过程中,首先通过FPU_GetControlStatus()函数初始化FPU控制状态,然后使用HAL_TIM库初始化TIM1和4个PWM通道。最后启动TIM1和4个PWM通道以产生PWM输出信号。 需要注意的是,TIM1的定时器模式被设置为“中央对齐模式1(CENTERALIGNED1)”,并且重复计数器的值被设置为1。这是因为FOC控制需要使用中央对齐模式,并且PWM输出频率需要与电机转速成正比。在FOC控制中,重复计数器的值通常为1或2,以使PWM输出的周期与电机旋转一周的周期一致。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值