首页 > 其他分享 >STM32F4 CubeMax 主从定时器同步 设定脉冲输出控制步进电机

STM32F4 CubeMax 主从定时器同步 设定脉冲输出控制步进电机

时间:2024-04-10 15:24:42浏览次数:22  
标签:定时器 CubeMax TIM Init CODE USER STM32F4 HAL RCC

实验准备

开发板:STM32F411E-DISCO或其它开发板(Firmware Package根据开发板下载)

软件:Keil uVision5、STM32CubeMX(Firmware Package:STM32Cube FW_F4 V1.23.0)

实验原理

  利用CubeMX根据芯片手册配置定时器同步来实现自定义脉冲数PWM输出对电机进行控制。主定时器产生PWM波,从定时器对主定时器发出的脉冲进行计数。  

STM32F4xx定时器内部触发连接

 

       

 

 

CubeMX 时钟配置表

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 96;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}

 

 主定时器TIM5配置(主:TIM5----从:TIM1)   


/**
* @brief TIM5 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM5_Init(void)
{

/* USER CODE BEGIN TIM5_Init 0 */
// TIM_ClockConfigTypeDef sClockSourceConfig;
/* USER CODE END TIM5_Init 0 */

TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};

/* USER CODE BEGIN TIM5_Init 1 */

/* USER CODE END TIM5_Init 1 */
htim5.Instance = TIM5;
htim5.Init.Prescaler = 48-1;
htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
htim5.Init.Period = 400-1;
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 200;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM5_Init 2 */

/* USER CODE END TIM5_Init 2 */
HAL_TIM_MspPostInit(&htim5);

}

从定时器TIM1配置(主:TIM5----从:TIM1) 从定时器TIM1需要开中断NVIC

/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{

/* USER CODE BEGIN TIM1_Init 0 */

/* USER CODE END TIM1_Init 0 */

TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};

/* USER CODE BEGIN TIM1_Init 1 */

/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
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();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED;
sSlaveConfig.InputTrigger = TIM_TS_ITR0;
if (HAL_TIM_SlaveConfigSynchronization(&htim1, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */

/* USER CODE END TIM1_Init 2 */

}

 

主定时器TIM2配置(主:TIM2----从:TIM4)

/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{

/* USER CODE BEGIN TIM2_Init 0 */

/* USER CODE END TIM2_Init 0 */

TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};

/* USER CODE BEGIN TIM2_Init 1 */

/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 48-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 400-1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 200;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */

/* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2);

}

 

从定时器TIM4配置(主:TIM2----从:TIM4)从定时器TIM4需要开中断NVIC

/**
* @brief TIM4 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM4_Init(void)
{

/* USER CODE BEGIN TIM4_Init 0 */

/* USER CODE END TIM4_Init 0 */

TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};

/* USER CODE BEGIN TIM4_Init 1 */

/* USER CODE END TIM4_Init 1 */
htim4.Instance = TIM4;
htim4.Init.Prescaler = 0;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 65535;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED;
sSlaveConfig.InputTrigger = TIM_TS_ITR1;
if (HAL_TIM_SlaveConfigSynchronization(&htim4, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM4_Init 2 */

/* USER CODE END TIM4_Init 2 */

}

 

添加中断回调函数(注意次函数一定要添加在“/* USER CODE BEGIN 4 */”和“/* USER CODE END 4 */”之间,这样cubemx更新代码时不会清除掉)

/* USER CODE BEGIN 4 */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

if(htim==(&htim1))
{
PWM1_OK = 0;
if(__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_CC1) != RESET) //判断是否触发中断
{
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_CC1); //清除中断标志位
HAL_TIM_PWM_Stop_IT(&htim5, TIM_CHANNEL_1); //关闭主定时器的PWM输出
HAL_TIM_Base_Stop_IT(&htim1); //关闭从定时器的计数
}
}
if(htim==(&htim4))
{
PWM2_OK = 0;
if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_CC1) != RESET) //判断是否触发中断
{
__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1); //清除中断标志位
HAL_TIM_PWM_Stop_IT(&htim2, TIM_CHANNEL_1); //关闭主定时器的PWM输出
HAL_TIM_Base_Stop_IT(&htim4); //关闭从定时器的计数
}
}
}


void PWM_out1(uint32_t pulse_data)
{
if(PWM1_OK == 1) //标志判断
{
PWM1_OK = 0;
TIM5->ARR=speed1;
TIM5->CCR1=(speed1>>1);
__HAL_TIM_SET_AUTORELOAD(&htim1,pulse_data-1); //ARR装载要输出的PWM脉冲数
HAL_TIM_Base_Start_IT(&htim1); //从定时器计数开启
HAL_TIM_PWM_Start_IT(&htim5, TIM_CHANNEL_1); //主定时器PWM脉冲输出
}
}
void PWM_out2(uint32_t pulse_data)
{
if(PWM2_OK == 1) //标志判断
{
PWM2_OK = 0;
TIM2->ARR=speed2;
TIM2->CCR1=(speed2>>1);
__HAL_TIM_SET_AUTORELOAD(&htim4,PWM_pulse-1); //ARR装载要输出的PWM脉冲数
HAL_TIM_Base_Start_IT(&htim4); //从定时器计数开启
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_1); //主定时器PWM脉冲输出
}
}

 

/* USER CODE END 4 */

在主函数前 添加私有变量 添加私有函数声明

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t PWM1_OK = 0;
uint8_t PWM2_OK = 0;
uint32_t PWM_pulse = 0;
uint16_t speed1=80; //电机默认速度
uint16_t speed2=80; //电机默认速度
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
void PWM_out1(uint32_t pulse_data);
void PWM_out2(uint32_t pulse_data);

/* USER CODE END PFP */

 

 在主函数 中添加PWM输出函数

/* Infinite loop */
/* USER CODE BEGIN WHILE */
PWM1_OK = 1;
PWM2_OK = 1;
PWM_pulse = 20;
speed1=400; //电机默认速度 数值越大脉冲周期越大 电机速度越慢
speed2=400; //电机默认速度 数值越大脉冲周期越大 电机速度越慢
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
PWM_out1(PWM_pulse);
PWM_out2(PWM_pulse);

}
/* USER CODE END 3 */

 

 

 

 引脚输出脉冲观察(PA0、PA5)

 

标签:定时器,CubeMax,TIM,Init,CODE,USER,STM32F4,HAL,RCC
From: https://www.cnblogs.com/RXZS-Magic/p/16821577.html

相关文章

  • (学习日记)2024.04.11:UCOSIII第三十九节:软件定时器
    写在前面:由于时间的不足与学习的碎片化,写博客变得有些奢侈。但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。既然如此不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜......
  • Swoole 源码分析之 Timer 定时器模块
    原文首发链接:Swoole源码分析之Timer定时器模块大家好,我是码农先森。引言Swoole中的毫秒精度的定时器。底层基于epoll_wait和setitimer实现,数据结构使用最小堆,可支持添加大量定时器。在同步IO进程中使用setitimer和信号实现,如Manager和TaskWorker进程,在异步IO......
  • Timer定时器———创建定时器实例
    1.编写时间写入日志文件的脚本vimsystem.sh#!/bin/bashecho`date`>>/root/system.txtcatsystem.sh2.给脚本增加可执行权限chmod+xsystem.sh3.执行刚刚编写的脚本.system.sh4.查看日志文件,脚本执行成功catsystem.txt5.创建一个boot_backup.service文件,......
  • 第5章 定时器/计数器
    第5章定时器/计数器定时/计数器的功能MCS-51单片机内共有两个可编程的定时/计数器T0和T1。它们都是十六位加法计数器结构,分别由TH0、TL0和TH1、TL1四个8位计数器组成,每个定时/计数器都具有定时和计数两种功能。计数功能对外来脉冲进行计数。计数脉冲的输入端来自单片机的两......
  • 初探STM32f407VET6
    一、买到了板子,自己分析引脚功能我在某宝上买到一块stm32f407vet6的板子,图便宜,结果遇上了个态度差的客服。没有说明,没有资料。不能退换,只能自己想办法分析引脚在嘉里创找到了芯片原理图(LQFP-100封装),想着看走线猜引脚,结果拿着放大镜找了许久没有进展。这板子上有许多过孔,走线......
  • 02-基于STM32F407MAC与DP83848实现以太网通讯六(IPerf网络速度测试)
    一、IPerf2网络测试工具Iperf2是一个用于测试网络带宽的工具。它是Iperf的旧版本,专注于提供基本的带宽测量功能。通过在客户端和服务器之间发送测试数据流并测量其性能,用户可以评估网络连接的速度和稳定性。Iperf2提供了一种简单而有效的方式来评估网络性能。IPerf3已经发布了,但......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(十五)AXI Timer 用户定时器中断控制LED
    前面的中断学习中我们学了按键,GPIO,Timer,是时候把它们整合到一起了。今天我们混合使用PS/PL部分的资源,建立一个比较大的系统。板子:zc702。实现功能如下:1.通过串口打印信息询问你要按SW5还是SW7;2.当正确的按键被按下,定时器启动,关闭ledDS23;3.当定时器溢出后触发中断,开启DS23,......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(十三)私有定时器中断
    私有定时器属于PS部分,定时器可以帮我们计数、计时,有效的控制模块的时序。这一次实验我们认识定时器并使用定时器产生中断。CPU的私有中断(PPI)CPU的私有中断(PPI),5个:全局定时器,私有看门狗定时器,私有定时器以及来自PL的FIQ/IRQ。它们的触发类型都是固定不变的,并且来自P......
  • 如何用Python制作具备音效的定时器
        很多时候都需要应用到定时器,特别是参加各种比赛的时候,记录每个队员使用的时间,如何用python制作定时器,且看以下代码,主要分四个小案例,分别是页面版本的无音效定时器、应用程序版本的无音效定时器、页面版本的有音效定时器和应用程序版本的有音效定时器。(有音效的意思......
  • 19. 通用定时器
    一、通用定时器简介  STM32F407有10个通用定时器(TIM2~TIM5和TIM9~TIM14)。这些定时器彼此完全独立,不共享任何资源。其主要特性如下:16位递增、递减、中心对齐计数器(计数值:0~65535),16位可编程预分频器(预分频系数:1~65536),用于对计数器时钟频率进行分频,还可以触发DAC......