STM32基于HAL庫(kù)的PWM

1 裸機(jī)

1.1工程建立

使用STM32CubeMX來(lái)生成工程,基本使用也可見(jiàn)鏈接

  • 選擇外部時(shí)鐘


    image.png
  • 選擇SW調(diào)試


    image.png
  • 串口1作為打印


    image.png
  • 配置時(shí)鐘,8M外部輸入,32M系統(tǒng)時(shí)鐘


    image.png
  • 選擇PA2為PWM的通道


    image.png
  • 配置對(duì)于的時(shí)鐘TIM2,選擇通道3


    image.png
  • 配置該P(yáng)WM通道,系統(tǒng)時(shí)鐘32M


    image.png
  • 生產(chǎn)工程的配置


    image.png

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

1.2 分析生產(chǎn)的代碼

主函數(shù)中初始化了GPIO和TIM,前者僅僅打開(kāi)了GPIO的時(shí)鐘,主要初始化在TIM中。

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

在tim.c則進(jìn)行了對(duì)于通道引腳初始化和定時(shí)器PWM初始化

//初始化PA2對(duì)于定時(shí)器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);
  }
}

定時(shí)器初始化的時(shí)候?qū)⑦M(jìn)行時(shí)鐘配置,這決定了PWM的頻率,Prescaler表示分頻數(shù),表示如果最終分頻到TIM的時(shí)鐘是32M,那么實(shí)際使用時(shí)鐘則是32/Prescaler。Period代表定時(shí)器計(jì)數(shù)達(dá)到多少后重新裝填,對(duì)于PWM來(lái)說(shuō)就代表了一個(gè)周期,所以PWM的頻率就等于48M/Prescaler/Period。Pulse就對(duì)應(yīng)占空比了,他代表當(dāng)前計(jì)數(shù),占空比 = 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;//向上計(jì)數(shù)
  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初始計(jì)數(shù)值  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);

}

之后的啟動(dòng)和占空比修改就需要自己調(diào)用stm32l1xx_hal.time.c中的函數(shù)來(lái)執(zhí)行了

函數(shù) 說(shuō)明
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel) 啟動(dòng)對(duì)應(yīng)通道的PWM
HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel) 停止對(duì)應(yīng)通道的PWM
說(shuō)明
__HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE) 配置對(duì)于通道占空比

下面是在tim.c中添加的函數(shù)

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是因?yàn)橛?jì)數(shù)閾值被設(shè)置成了1千
     {
          duty=1000;
     }
     __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, duty);
   
}

最后在主函數(shù)中調(diào)用進(jìn)行測(cè)試
先添加打印定向,使其能夠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;
}

然后啟動(dòng)PWM,設(shè)置占空比50%

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

1.3 STM32L系列定時(shí)器通道對(duì)應(yīng)關(guān)系

引腳號(hào) 定時(shí)器通道
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 相關(guān)文件導(dǎo)入

這里不使用scons,而是手動(dòng)添加,第一步是加入HAL庫(kù)文件
stm32l1xx_hal_gpio.c
stm32l1xx_hal_gpio_ex.c
stm32l1xx_hal_tim.c
stm32l1xx_hal_time_ex.c
然后在stm32l1xx_hal_conf.h中打開(kāi)宏定義,關(guān)于這里,如果是使用cube生成的工程,這些是根據(jù)配置自動(dòng)生成的。

#define HAL_GPIO_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED

第二步,引入rtthread的PWM框架,該文件位于rt-thread-master\components\drivers\misc的rt_drv_pwm.c,無(wú)需修改,也沒(méi)有頭文件。底層驅(qū)動(dòng)將會(huì)根據(jù)該框架來(lái)實(shí)現(xiàn)。
第三步是添加PWM的底層驅(qū)動(dòng),這部分使用STM系列新品是無(wú)需編寫(xiě)的,在libraries/HAL_Drivers中drv_pwm.c,該文件有一個(gè)pwm_config.h用來(lái)基本配置,里面可以看出設(shè)備名和定時(shí)器之間的關(guān)系,例

#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 */

關(guān)于設(shè)備的注冊(cè)是在rtconfig.h中用宏來(lái)決定的,例如需要初始化定時(shí)器3的PWM,則需要定義

#define BSP_USING_PWM
#define BSP_USING_PWM3

實(shí)際上該宏決定了stm32_pwm_obj數(shù)組的內(nèi)容,在stm32_pwm_init函數(shù)中,會(huì)根據(jù)該數(shù)組來(lái)注冊(cè)PWM設(shè)備。
文件末尾能夠看到初始化被自啟動(dòng),也表明pwm3這個(gè)設(shè)備我們可以直接find了

INIT_DEVICE_EXPORT(stm32_pwm_init);

3 下載

裸機(jī)代碼9zqy
rt_thread代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容