基于STM32F429+HAL库编写的定时器主从门控模式级联输出固定个数PWM脉冲的程序

硬件设备

  42步进电机,步进电机驱动器,正点原子F429开发板

开发软件

   keil5,Cube

综述

  一般要精准的控制电机,就要控制单片机的引脚输出指定个数的PWM波,有多种可实现的方法,其中最好用的方法是用定时器级联输出固定个数PWM脉冲,虽然多用了一个定时器,但大大减少了CPU的处理资源。STM32的每个定时器可以通过另外一个定时器的某一个条件被触发而启动.这里所谓某一个条件可以是定时到时、定时器超时、比较成功等许多条件.这种通过一个定时器触发另一个定时器的工作方式称为定时器的同步,发出触发信号的定时器工作于主模式,接受触发信号而启动的定时器工作于从模式。

Cube配置定时器,主定时器为PWM输出,从定时器为门控模式

1.主定时器为TIM3,其中通道1配置为PWM输出,主模式的更新事件选为触发输入

  

Cube的配置为参考,一切以代码为准

void MX_TIM3_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef          sConfigOC = {0};

  htim3.Instance = TIM3;                                //设置主定时器为TIM3
  htim3.Init.Prescaler = 4-1;                           //设置PWM频率
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;          //设置计数模式为向上计数
  htim3.Init.Period = 100-1;                            //设置占空比
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;    //设置为无分频
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;              //更新事件被选为触发输入
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;       //开启主从模式
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;            //设置PWM模式为PWM1
  sConfigOC.Pulse = 50;                          //设置PWM占空比为50%(50/100)
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;     //设置PWM空闲状态引脚拉低
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }    

  HAL_TIM_MspPostInit(&htim3);                    //设置PA6复用为PWM输出引脚
  HAL_TIM_Base_Stop(&htim3);
}

2.从定时器为TIM4,选为门控模式——触发输入

从为TIM4,主为TIM3,根据下图,所以从模式的触发时钟为ITR2

void MX_TIM4_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};

  htim4.Instance = TIM4;                                   //设置从定时器为TIM4
  htim4.Init.Prescaler =0;                                 //设置从定时器频率为0
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;             //设置计数模式为向上计数
  htim4.Init.Period =0xffff;                               //这个大于0就行
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;       //设置为无分频
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;  //设置为内部时钟触发,即为TIM3
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sSlaveConfig.SlaveMode =  TIM_SLAVEMODE_GATED;              //设置为门触发
  sSlaveConfig.InputTrigger = TIM_TS_ITR2;                    //设置ITR2(tim3)为输入源
  sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;  //设置触发模式为上升沿
  sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;  //设置无预分频
  sSlaveConfig.TriggerFilter = 0x0;                           //设置无滤波

  if (HAL_TIM_SlaveConfigSynchronization(&htim4, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
     HAL_TIM_Base_Stop_IT(&htim4);

}

从定时器的频率一定要设为0,不然输出的PWM会加倍

中断处理函数

  HAL里的中断处理函数要选HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim),当TIM4->CNT的值达到TIM4->ARR的值时触发中断,关闭主从定时器,清零中断标志位SR

void  HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{ 

   FLAG1_OK = 0; 

    if(htim==(&htim4))
    {    

//****************************************************//
            if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_CC1) != RESET)           //判断是否触发中断
        {
             __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_CC1);                    //清除中断标志位

             HAL_TIM_PWM_Stop_IT(&htim3, TIM_CHANNEL_1);                    //关闭主定时器的PWM输出

             HAL_TIM_Base_Stop_IT(&htim4);                                  //关闭从定时器的计数

//****************************************************//                      

        }

    delay_ms(1);
        FLAG1_OK = 1;
    }

}

脉冲输出主函数

   中断函数关闭的,于此要重新开启,有始有终

while(1)
{ 

    if(FLAG1_OK == 1 )     //标志判断
    {        she10

         __HAL_TIM_SET_AUTORELOAD(&htim4,10-1);    //ARR装载要输出的PWM脉冲数 

         HAL_TIM_Base_Start_IT(&htim4);                   //从定时器计数开启

       HAL_TIM_PWM_Start_IT(&htim3, TIM_CHANNEL_1);        //主定时器PWM脉冲输出

    }

}

 分析仪实测波形

很漂亮整洁的10个PWM波,在1MHz以下挺准的,但上去了就多了一两个波,还需要细调。

这个是单定时器的单通道的程序,已经写好单定时器多通道的了,有时间再发。

有不足之处还请各位不吝赐教。

 

原文地址:https://www.cnblogs.com/feiniaoliangtiangao/p/10745691.html

时间: 2024-11-10 13:06:53

基于STM32F429+HAL库编写的定时器主从门控模式级联输出固定个数PWM脉冲的程序的相关文章

一个基于STM32F429 HAL库的学习工程模板

让我们来看看这个模板里面都有些啥: 首先打开里面的STW_STM32F429.ioc文件,看到这个图形界面 在这个工程中,我们占用了一个FMC接口,用于向外拓展了32MB的SDRAM,占用了一个LTDC接口,用于连接一块RGB显示屏,两个定时器TIM6,TIM7,两个串口USART1,USART3(连接WIFI模块) 他们具体的配置以及时钟的配置就不详细说了,我在下面提供了一个链接,有兴趣可以下载后慢慢学习. 一般的模板工程无非就是完成一个跑马灯, 我提供的模板提供了一起其他功能,细节就不介绍了

【STM32H7教程】第36章 STM32H7的LPTIM低功耗定时器基础知识和HAL库API

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第36章       STM32H7的LPTIM低功耗定时器基础知识和HAL库API 本章节为大家讲解LPTIM1 – LPTIM5共计5个定时器的基础知识和对应的HAL库API. 36.1 初学者重要提示 36.2 低功耗定时器基础知识 36.3 低功耗定时器的HAL库用户 36.4 源文件stm32h7xx_hal_lptim.c 36.5 总结 36.1 初学者

STM32,下载HAL库写的代码后J-Link识别不到芯片,必须要按住复位才能下载?

问题描述:最近在学STM32的HAL库,据说可以统一STM32江湖,前途无量.最近一段时间参照STM32CubeMX和原子的资料自己学着建了两个HAL库的工程模板,F4的还好说,F1的出现了一个玄学问题: 芯片为STM32F103C8T6,下进HAL库编写的工程后J-Link就识别不到芯片了,下载也是,只有J-Link读取时按住复位才可以.更神奇的是用标准库的代码却没问题,具体表象就是下进标准库的代码,然后HAL库的代码可以正常下载,但是HAL库的代码一旦下进去,标准库和HAL库的代码就都不能通

HAL库 定时器3 中断 翻转LED

开启定时器3 实现每1s翻转LED,公式 Tout = (ARR+1)*(PSC+1)/TCLK (1)ARR : 自动重装载值 / 计数周期: (2)PSC : 分频系数 : (3)TCLK : 输入时钟 72M 定时器介绍: SMT32F1系列共有8个定时器:(区别)高级定时器(TIM1.TIM8): /16位 / 可产生DMA请求 / 有捕获 和 / 比较通道 / 有互补输出 / 可用于PWM电机控制通用定时器(TIM2.TIM3.TIM4.TIM5): / 16位 / 无捕获基本定时器(

【HAL库每天一例】freemodbus移植

例程下载:资料包括程序.相关说明资料以及软件使用截图 百度云盘:https://pan.baidu.com/s/1slN8rIt 密码:u6m1 360云盘:https://yunpan.cn/OcPiRp3wEcA92u密码 cfb6 (硬石YS-F1Pro开发板HAL库例程持续更新\6. 软件设计之Modbus(HAL库版本)\YSF1_HAL_freemodbus_001. freemodbus移植)/**  ****************************************

STM32 HAL库和LL库的区别

上次开发一个项目,使用一个小容量的STM32 ARM CORTEX核心的单片机,使用STM32CUBEMX自动生成配置代码,正准备编写程序的时候,发现容量竟然有6K多.这个容量在使用大容量FLASH的单片机时不感到什么,可是使用小容量单片机的时候,就明显不够用了. 没有办法,只好打算回去使用原来的StdLib库,前两年不就这么干的嘛,也没什么难的.可是回头找对应库的时候,发现悲剧了,没有这个序列的标准库. 这也难不倒我们老司机!我就从HAL库里面把必须的寄存器语句摘出来,把冗余的有效检验和冲突处

STM32F103 PWM输出实验(HAL库)

1.芯片输出PWM波形打码步骤 1.0主函数 int main(void) { HAL_Init(); //初始化HAL库 Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M delay_init(72); //初始化延时函数 uart_init(115200); //初始化串口 LED_Init(); //初始化LED TIM1_PWM_Init(20000,72); //72分频,即1M . 1000000/20000 = 50 Hz ,即20ms whil

USART与USB接收不定数据方法,标准库、HAL库都适用

很多时候,我们使用串口或USB接收数据时,往往不知道PC端会发多长的数据下来, 为了解决这个不定数据接收问题,在此各提供一个解决思路. 串口数据不定接收: 由于STM32单片机带IDLE中断,所以利用这个中断,可以接收不定长字节的数据, 由于STM32属于ARM单片机,所以这篇文章的方法也适合其他的ARM单片机. IDLE就是串口收到一帧数据后,发生的中断.什么是一帧数据呢?比如说给单片机一 次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以 叫做一包数据. 还有一

HAL库延时、SYCCNT与SYSTICK

HAL库驱动中,由于某些外设的驱动需要使用超时判断(比如I2C.SPI.SDIO等),需要精确延时(精度为1ms),使用的是SysTick,但是在操作系统里面,我们需要使用SysTick来提供系统时基,那么就冲突了,怎么办?答案是利用DWT重新编写HAL库的相关延时和超时函数HAL_InitTick().HAL_GetTick()和HAL_Delay(),这三个函数在HAL库中都是弱定义函数(函数开头带__weak关键字). 在Cortex-M内核里面有一个外设叫DWT(Data  Watchp