HAL STM32G4 +TIM1 3路PWM互补输出+VOFA波形演示
✨最近学习研究无刷电机驱动,虽然之前有使用过,但是在STM32上还没实现过。本文内容参考
欧拉电子
例程,从PWM驱动开始学习。
欧拉电子
相关视频讲解:
STM32G4 FOC开发实战---高级定时器发波
- ✨本篇重点学习,如何配置PWM互补输出,和死区时间计算和设定,如果看了本篇还不会配置和计算死区时间,可以提着99米砍刀来找我。😁
- 📍有关VOFA数据传输协议可以参考《VOFA+上位机三种协议(FireWater,JustFloat,RawData)C语言参考代码》
🛠STM32CubeMX工程配置
-
🌿时钟配置:
-
🌿定时器1(TIM1)配置:
- 🌿计数值:8000、计数方式:采用中心对称方式、时钟分频系数:2
- 🌿死区时间配置:(TIMx timer deadtime register 2 (TIMx_DTR2)(x = 1, 8, 20))
- Dead Time:120,其值对应的二进制值:
B0111 1000
bash
DTGF[7:5] = 0xx => DTF = DTGF[7:0]x tdtg with tdtg = tDTS.
-
- 🔖死区时间换算:
120/160MHz/2=1.5us
- 🔖死区时间换算:
-
✨死区时间参数,需要根据具体使用的MOS型号参数来调整。
-
🔖逻辑分析仪死区时间测量:
- 🌾如果上的
Dead Time
配置为160
,其对应的二进制值:B1010 0000
,
c
DTGF[7:5] = 10x => DTF = (64+DTGF[5:0])xtdtg with Tdtg = 2xtDTS
-
- 🔖
Dead Time
配置为160
,对应的死区时间换算:2*(64+32)/(160MHz/2)=2.4us
- 🔖
- 🌾如果上的
Dead Time
配置为200
,其对应的二进制值:B1100 1000
:
c
DTGF[7:5] = 110 => DTF = (32+DTGF[4:0])xtdtg with Tdtg = 8xtDTS.
-
- 🔖
Dead Time
配置为200
,对应的死区时间换算:8*(32+8)/(160MHz/2)=4us
- 🔖
- 🌾如果上的
Dead Time
配置为230
,其对应的二进制值:B1110 0110
:
c
DTGF[7:5] = 111 => DTF = (32+DTGF[4:0])xtdtg with Tdtg = 16xtDTS
-
- 🔖
Dead Time
配置为230
,对应的死区时间换算:16*(32+6)/(160MHz/2)=7.6us
- 🔖
📙STM32CubeMX串口DMA配置
- 🔖主要时为了使用VOFA串口调试工具,来显示图形数据观测。如果自己有逻辑分析仪的话,这一点可以忽略。
- 🌿配置串口并开启DMA:
- ⚡开启DMA一定要勾选对应中断:
📘业务代码完善
- 🌿重新给定各通道计数值。
- 🌿开启PWM输出。
c
TIM1->CCR1 = 2000;
TIM1->CCR2 = 5000;
TIM1->CCR3 = 4000;
HAL_TIM_Base_Start(&htim1);
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);
- 🌿串口相关的代码,根据个人需求
copy
相应内容:(注意勾选Use microLIB
选项)
c
#include <stdio.h>
#include "usart.h"
#include <string.h>
#include <stdarg.h>
//使用printf()发送数据,需要对printf函数进行重定向,且只能使用USART1。
// 重定向fputc函数,使用printf()发送数据
int fputc(int ch, FILE *f)
{
// 参数1:串口句柄,参数2:要发送的数据;参数3:要发生数据的长度;参数4:超时等待时间
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
return ch;
}
//DMA发送:本项目中使用的方法
// DMA模式
void log_DMA(const char *format, ...)
{
va_list args; // 定义参数列表变量
va_start(args, format); // 从format位置开始接收参数表,放在arg里面
char strBuf[256]; // 定义输出的字符串
vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
va_end(args); // 结束可变参数的使用
// 等待上次的数据发送完成,避免新的数据覆盖正在传输的数据,导致混乱
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
{
// Wait for DMA transfer to complete
}
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)strBuf, strlen(strBuf));
}
//中断式发送:
// 中断模式
void log_IT(const char *format, ...)
{
va_list args; // 定义参数列表变量
va_start(args, format); // 从format位置开始接收参数表,放在arg里面
char strBuf[256]; // 定义输出的字符串
vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
va_end(args); // 结束可变参数的使用
// 等待上次的数据发送完成,避免新的数据覆盖正在传输的数据,导致混乱
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
{
// Wait for transfer to complete
}
HAL_UART_Transmit_IT(&huart1, (uint8_t *)strBuf, strlen(strBuf));
}
//使用sprintf()函数,阻塞式发送:
// 堵塞模式
void log(const char *format, ...)
{
va_list args; // 定义参数列表变量
va_start(args, format); // 从format位置开始接收参数表,放在arg里面
char strBuf[256]; // 定义输出的字符串
vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
va_end(args); // 结束可变参数的使用
HAL_UART_Transmit(&huart1, (uint8_t *)strBuf, strlen(strBuf), HAL_MAX_DELAY);
}
- 🌿main函数代码
c
int main(void)
{
/* USER CODE BEGIN 1 */
float temp[3];
uint8_t TempData[16];
/* 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_TIM1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
// TIM1->PSC = 30000;//VOFA上位机观测,开启
// TIM1->ARR = 10000;
TIM1->CCR1 = 2000;
TIM1->CCR2 = 5000;
TIM1->CCR3 = 4000;
HAL_TIM_Base_Start(&htim1);
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);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if((GPIOC->IDR & GPIO_PIN_0) != 0)
{
temp[0]=1.0f;
}else
{
temp[0]=0.0f;
}
if((GPIOC->IDR & GPIO_PIN_1) != 0)
{
temp[1]=3.0f;
}else
{
temp[1]=2.0f;
}
if((GPIOC->IDR & GPIO_PIN_2) != 0)
{
temp[2]=5.0f;
}else
{
temp[2]=4.0f;
}
TempData[12] = 0x00;//写入结尾数据
TempData[13] = 0x00;
TempData[14] = 0x80;
TempData[15] = 0x7f;
memcpy(TempData,(uint8_t*)temp,sizeof(temp));
// HAL_UART_Transmit(&huart1, (uint8_t *)TempData, 16, 100);
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)TempData, 16);
}
/* USER CODE END 3 */
}
📒串口上位机VOFA配置
- 🍃首先对工程代码修改,调整定时器分频系数以及计数值:
c
TIM1->PSC = 30000;//VOFA上位机观测,开启
TIM1->ARR = 10000;
- 🍃串口上位机VOFA配置:
- 参数配置:
- 🌿打开串口后,添加参数显示到,显示控件中:
- 🔖波形显示:
📚工程源码
c
链接:https://pan.baidu.com/s/19iAekOOqH-2pB3TjZoZFhw?pwd=t2q0
提取码:t2q0