STM32基于HAL库的PWM

作者: lissettecarlr | 来源:发表于2019-04-16 19:14 被阅读0次

1 裸机

1.1工程建立

使用STM32CubeMX来生成工程,基本使用也可见链接

  • 选择外部时钟


    image.png
  • 选择SW调试


    image.png
  • 串口1作为打印


    image.png
  • 配置时钟,8M外部输入,32M系统时钟


    image.png
  • 选择PA2为PWM的通道


    image.png
  • 配置对于的时钟TIM2,选择通道3


    image.png
  • 配置该PWM通道,系统时钟32M


    image.png
  • 生产工程的配置


    image.png
    image.png
  • 最后生成的工程(GENERATE CODE)

1.2 分析生产的代码

主函数中初始化了GPIO和TIM,前者仅仅打开了GPIO的时钟,主要初始化在TIM中。

//main.h
  MX_GPIO_Init();
  MX_TIM2_Init();

在tim.c则进行了对于通道引脚初始化和定时器PWM初始化

//初始化PA2对于定时器TIM2的CH3
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(timHandle->Instance==TIM2)
  {
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }
}

定时器初始化的时候将进行时钟配置,这决定了PWM的频率,Prescaler表示分频数,表示如果最终分频到TIM的时钟是32M,那么实际使用时钟则是32/Prescaler。Period代表定时器计数达到多少后重新装填,对于PWM来说就代表了一个周期,所以PWM的频率就等于48M/Prescaler/Period。Pulse就对应占空比了,他代表当前计数,占空比 = Pulse/Period

void MX_TIM2_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 32-1;//分频
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;//向上计数
  htim2.Init.Period = 1000-1;//阈值
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;//PWM初始计数值  0/1000
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim2);

}

之后的启动和占空比修改就需要自己调用stm32l1xx_hal.time.c中的函数来执行了

函数 说明
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel) 启动对应通道的PWM
HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel) 停止对应通道的PWM
说明
__HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE) 配置对于通道占空比

下面是在tim.c中添加的函数

void USR_TIM_PWM_OpenTim2Ch3()
{
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
}

void USR_TIM_PWM_CloseTim2Ch3()
{
  HAL_TIM_PWM_Stop(&htim2,TIM_CHANNEL_3);
}

//duty == 0~1000
void USR_TIM_PWM_SetCompare(uint16_t duty)
{
   if(duty >1000) //这里1000是因为计数阈值被设置成了1千
     {
          duty=1000;
     }
     __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, duty);
   
}

最后在主函数中调用进行测试
先添加打印定向,使其能够printf输出

#include "stdio.h"
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}

然后启动PWM,设置占空比50%

 USR_TIM_PWM_OpenTim2Ch3();
USR_TIM_PWM_SetCompare(500); //50%

1.3 STM32L系列定时器通道对应关系

引脚号 定时器通道
PA0 TIM2_CH1_ETR
PA1 TIM2_CH2
PA2 TIM2_CH3
PA3 TIM2_CH4
PA6 TIM3_CH1
PA7 TIM3_CH2
PB0 TIM3_CH3
PB1 TIM3_CH4
PB6 TIM4_CH1
PB7 TIM4_CH2
PB8 TIM4_CH3
PB9 TIM4_CH4

2 RT-thread

2.1 相关文件导入

这里不使用scons,而是手动添加,第一步是加入HAL库文件
stm32l1xx_hal_gpio.c
stm32l1xx_hal_gpio_ex.c
stm32l1xx_hal_tim.c
stm32l1xx_hal_time_ex.c
然后在stm32l1xx_hal_conf.h中打开宏定义,关于这里,如果是使用cube生成的工程,这些是根据配置自动生成的。

#define HAL_GPIO_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED

第二步,引入rtthread的PWM框架,该文件位于rt-thread-master\components\drivers\misc的rt_drv_pwm.c,无需修改,也没有头文件。底层驱动将会根据该框架来实现。
第三步是添加PWM的底层驱动,这部分使用STM系列新品是无需编写的,在libraries/HAL_Drivers中drv_pwm.c,该文件有一个pwm_config.h用来基本配置,里面可以看出设备名和定时器之间的关系,例

#ifdef BSP_USING_PWM2
#ifndef PWM2_CONFIG
#define PWM2_CONFIG                             \
    {                                           \
       .tim_handle.Instance     = TIM2,         \
       .name                    = "pwm2",       \
       .channel                 = 0             \
    }
#endif /* PWM2_CONFIG */
#endif /* BSP_USING_PWM2 */

关于设备的注册是在rtconfig.h中用宏来决定的,例如需要初始化定时器3的PWM,则需要定义

#define BSP_USING_PWM
#define BSP_USING_PWM3

实际上该宏决定了stm32_pwm_obj数组的内容,在stm32_pwm_init函数中,会根据该数组来注册PWM设备。
文件末尾能够看到初始化被自启动,也表明pwm3这个设备我们可以直接find了

INIT_DEVICE_EXPORT(stm32_pwm_init);

3 下载

裸机代码9zqy
rt_thread代码

相关文章

网友评论

    本文标题:STM32基于HAL库的PWM

    本文链接:https://www.haomeiwen.com/subject/pikrvqtx.html