Keil MDK STM32系列

配置 PWM 输出

  • 选择芯片
  • System Core -> SYS-> Debug: Serial Wire 防止下次无法烧录
  • System Core -> RCC-> High Speed Clock (HSE): Crystal/Ceramic Resonator 启用外接高速晶振
  • Clock Configuration: (配置为最高84MHz)选择外部晶振, 把HSE和PLLCLK连上, 在HCLK上输入84回车, 软件会自动调节各节点倍数
  • Timers -> TIM2
  • Clock Source: Internel Clock, 使用系统的时钟源
    • Channelx: PWM Generation CHx PWM输出
    • Counter Settings PWM频率 = 84MHz / (Perscaler + 1) / (Counter Period + 1)
      • Perscaler: 0
      • Counter Mode: Up
      • Counter Period: 256
      • Internal Clock Division(CKD): No Division
      • auto-reload preload: Enable - 如果启用, 在修改占空比时会等当前周期执行完再变化
    • Trigger Output
      • Master/Slave Mode (MSM bit): Disable
      • Trigger Event Selection: Reset (UG bit from TIMx_EGR)
  • PWM Generation Channel 1
    • Mode: PWM mode1
    • Pulse: 0
    • Output compare perload: Enable
    • Fast Mode: Disable
    • CH Polarity: High
  • PWM Generation Channel 2
    • ...

PWM 配置, 体现在代码上的变化

  1. stm32f4xx_hal_conf.h 去掉了TIM的注释
#define HAL_TIM_MODULE_ENABLED
  1. stm32f4xx_hal_msp.c 增加了初始化方法HAL_TIM_Base_MspInit(), HAL_TIM_MspPostInit(), HAL_TIM_Base_MspDeInit()
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspInit 0 */ /* USER CODE END TIM2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM2_CLK_ENABLE();
/* USER CODE BEGIN TIM2_MspInit 1 */ /* USER CODE END TIM2_MspInit 1 */
} } void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspPostInit 0 */ /* USER CODE END TIM2_MspPostInit 0 */ __HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM2 GPIO Configuration
PA15 ------> TIM2_CH1
PB3 ------> TIM2_CH2
*/
GPIO_InitStruct.Pin = GPIO_PIN_15;
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); GPIO_InitStruct.Pin = GPIO_PIN_3;
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(GPIOB, &GPIO_InitStruct); /* USER CODE BEGIN TIM2_MspPostInit 1 */ /* USER CODE END TIM2_MspPostInit 1 */
} } /**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspDeInit 0 */ /* USER CODE END TIM2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM2_CLK_DISABLE();
/* USER CODE BEGIN TIM2_MspDeInit 1 */ /* USER CODE END TIM2_MspDeInit 1 */
} }
  1. main.c 对TIM2增加初始化方法, TIM的初始化过程与其它外设是不一样的

    这里Prescaler=0, Period=255, 对应84MHz的SYSCLK, 输出的PWM频率为84MHz/256 = 32.8125KHz, 用于输出音频
TIM_HandleTypeDef htim2;

/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0}; htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 255;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
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;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */ /* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2); }

配置定时器

通过TIMx配置

  • 勾选 Internal Clock
  • 配置下方参数
  • Counter Settings
    • Prescaler: 0
    • Counter Mode: Up
    • Counter Period: 1999 这里和Perscaler组合, 实现(0+1)(1999+1)个时钟的周期
    • Internal Clock Division (CKD): No division
    • auto-reload preload: Disable
  • Trigger Output (TRGO) Parameters
    • Master/Slave Mode (MSM bit): Disable
    • Trigger Envent Selection: Reset
  • NVIC Settings
    • TIM3 global interrupt: Enable

对应代码变化

stm32f4xx_hal_conf.h 启用TIM模块

#define HAL_TIM_MODULE_ENABLED

main.c 除了初始化方法, 还需要添加中断处理方法

static void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
} void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//...
}

stm32f4xx_hal_msp.c 这里会一起处理其他的TIM实例

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
// ...
}
else if(htim_base->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
} } void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM2)
{
//...
}
else if(htim_base->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM3_IRQn);
} }

stm32f4xx_it.h 增加对应的定时中断处理

void TIM3_IRQHandler(void);

stm32f4xx_it.c

/**
* @brief This function handles TIM3 global interrupt.
*/
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim3);
}

Keil MDK STM32系列(七) STM32F4基于HAL的PWM和定时器的更多相关文章

  1. Keil MDK STM32系列(八) STM32F4基于HAL的PWM和定时器输出音频

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  2. Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  3. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  4. Keil MDK STM32系列(四) 基于抽象外设库HAL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  5. Keil MDK STM32系列(六) 基于抽象外设库HAL的ADC模数转换

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  6. Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  7. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  8. Keil MDK STM32系列(五) 使用STM32CubeMX创建项目基础结构

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  9. SQL Server 2008空间数据应用系列七:基于Bing Maps(Silverlight) 的空间数据展现

    原文:SQL Server 2008空间数据应用系列七:基于Bing Maps(Silverlight) 的空间数据展现 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft ...

随机推荐

  1. LuoguB2101 计算矩阵边缘元素之和 题解

    Content 给定一个 \(m\times n\) 的矩阵,求矩阵边缘元素之和. 数据范围:\(1\leqslant m,n\leqslant 100\). Solution 对于新手来说,看到这题 ...

  2. LuoguP6904 [ICPC2015 WF]Amalgamated Artichokes 题解

    Content 已知常数 \(p,a,b,c,d\),我们知道,第 \(k\) 天的股价公式为 \(price_k=p\times(\sin(a\times k+b)+\cos(c\times k+d ...

  3. k8s daemonset controller源码分析

    daemonset controller分析 daemonset controller简介 daemonset controller是kube-controller-manager组件中众多控制器中的 ...

  4. UDP&串口调试助手用法(5)

    note 提供安装包 基于win10开发 已通过win10测试,windows其他平台,没有测试 日志 2021-09-18 1.修复计算校验和错误的现象 2.屏蔽不计算校验和位置的REG验证(后期更 ...

  5. 【LeetCode】92. Reverse Linked List II 解题报告(Python&C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 迭代 递归 日期 题目地址:https://leet ...

  6. B. The Meeting Place Cannot Be Changed

    B. The Meeting Place Cannot Be Changed time limit per test 5 seconds memory limit per test 256 megab ...

  7. 【LeetCode】646. Maximum Length of Pair Chain 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 贪心算法 日期 题目地址:https://leetc ...

  8. Docker 与 K8S学习笔记(七)—— 容器的网络

    本节我们来看看Docker网络,我们这里主要讨论单机docker上的网络.当docker安装后,会自动在服务器中创建三种网络:none.host和bridge,接下来我们分别了解下这三种网络: $ s ...

  9. 记一次引入Elasticsearch的系统架构实战

    前言 我曾经面试安踏的技术岗,当时面试官问了我一个问题:如果你想使用某个新技术但是领导不愿意,你怎么办? 对于该问题我相信大家就算没有面试被问到过,现实工作中同事之间的合作也会遇到. 因此从我的角度重 ...

  10. 使用zTree插件实现可拖拽的树

    在目前接触到的树插件中,我觉得zTree比较简单,也容易上手.有一次业务需求是将某对象分组树上的对象可以随意拖拽,相当于改变了对象的分组,因此我用到了zTree,对其进行了一些列学习.         ...