基于HAL库的STM32F103定时器主从模式输出固定数量的PWM脉冲

1 硬件和软件平台

  • 硬件:自制STM32F103C8T6
  • 软件:STM32CubeMX 6.1.0
  • 软件:Keil V5.28.0.0
  • 硬件包:STM32Cube_FW_F1 V1.8.3

2 定时器介绍

STM32的定时器可以通过另外一个定时器的某一个条件被触发而启动,即同步的工作方式。发出触发信号的定时器工作于主模式(Master),接受触发信号而启动的定时器工作于从模式(Slave)。它们之间通过TIM内部触发连接(ITR)。使用不同的主从定时器,使用的ITR不同,根据参考手册(版本ENV20)可以知道对应的ITR。


图1 参考手册中的高级定时器内部触发连接

图2 参考手册中的通用定时器内部触发连接

3 CubeMX配置

不再介绍CubeMX创建工程的方法。

3.1 设置时钟

在RCC中配置高速时钟,选择外部晶振。


图3 高速时钟的配置

在Clock Configuration中选择HSE,并配置HCLK为72MHz。


图4 Clock Configuration 配置

3.2 设置仿真模式

在SYS设置仿真模式,此处我使用的是SW,根据情况自行选择。


图5 Debug配置

3.3 设置主定时器(Master)

此处我使用TIM2作为Master,通道2输出PWM。TIM1为Slave。在CubeMX中选择TIM2,配置主定时器。 Channel2选择PWM Generation CH2。


图6 Master TIM模式配置

预分频系数为71(设置值不能大于65535),计数器周期为9,这两个配置控制PWM输出的频率。由于我们时钟是72MHz,此处设置的PWM频率为100kHz。


图7 Master TIM参数配置

图8 PWM频率计算公式

设置Pulse为5,该值和计数器周期共同控制PWM的占空比,此处为50%。
图9 PWM占空比计算公式

使能主从模式,触发事件选择Update Event。禁用输出比较预加载。输出极性Low。

3.4 设置从定时器(Slave)

此处我选择TIM1为Slave。由图1可知,TIM2为Master,TIM1为Slave时,使用ITR1。在CubeMX中选择TIM1。设置Slave Mode为Gated Mode,触发源选择ITR1(根据自己使用的定时器选择),时钟源选择内部时钟。


图10 Slave TIM模式配置

参数设置基本是保持默认。


图11 Slave TIM参数配置

使能从定时器的中断。此处我使用的是高级定时器作为Slave,如果是通用定时器,只需使能定时器全局中断即可。
图12 Slave TIM中断配置

CubeMX配置完成,点击GENERATE CODE生成代码。

4 代码

CubeMX已经帮我们生成了初始化代码,无需修改。
主定时器(此处是TIM2)初始化代码:

/* TIM2 init function */
void MX_TIM2_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 9;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  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 = 5;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  __HAL_TIM_DISABLE_OCxPRELOAD(&htim2, TIM_CHANNEL_2);
  HAL_TIM_MspPostInit(&htim2);

}

从定时器(此处是TIM1)初始化代码:

/* TIM1 init function */
void MX_TIM1_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  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;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  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_ITR1;
  if (HAL_TIM_SlaveConfigSynchro(&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();
  }

}

在main.c中定义标志位以指示PWM是否处于输出状态。

/* USER CODE BEGIN PV */
uint8_t PWM_OK = 0;
/* USER CODE END PV */

在main函数初始化完成后添加以下代码。

  /* USER CODE BEGIN 2 */
    HAL_TIM_Base_Start_IT(&htim1);
    HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
    __HAL_TIM_SET_AUTORELOAD(&htim1, 0);
  /* USER CODE END 2 */

在stm32f1xx_it.c中添加外部变量引用和中断回调函数,也可以添加到其他文件中,根据自己习惯来。由于我们使能了TIM1的中断,此处CubeMX会自动添加TIM1的引用,只需手动添加TIM2的引用即可。

/* USER CODE BEGIN PV */
extern uint8_t PWM_OK;
/* USER CODE END PV */

/* USER CODE BEGIN EV */
extern TIM_HandleTypeDef htim2;
/* USER CODE END EV */

在中断回调函数中清除中断标志位,并停止PWM。

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim == (&htim1))
    {
        if(__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_CC1) != RESET)
        {
            __HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_CC1);
            HAL_TIM_PWM_Stop_IT(&htim2, TIM_CHANNEL_2);
            HAL_TIM_Base_Stop_IT(&htim1);
        }
        PWM_OK = 1;
    }
}
/* USER CODE END 1 */

在main.c中封装PWM输出函数,并在main.h中声明。

/**
  * @brief  The application outputs a specified number of pulses.
    * @param    num is the number of pulses.
  */
void OutPwm(uint32_t num)
{
    if(PWM_OK == 1)
    {
        PWM_OK = 0;
        __HAL_TIM_SET_AUTORELOAD(&htim1, num - 1);
        HAL_TIM_Base_Start_IT(&htim1);
        HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
    }
}

在while(1)中输出10个脉冲并延迟40ms。

  while (1)
  {
        HAL_Delay(40);
        OutPwm(10);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

5 测试结果

因为我的硬件中使用了缓冲器将PWM的电平提高到了5V,因此测量结果都是5Vpp。
可以看到,每40ms有脉冲输出。


图13 PWM脉冲输出

放大细节可以看到得到100kHz的10个脉冲,波形还不错。


图14 PWM输出细节
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容