00. 目录

文章目录

  • 00. 目录
  • 01. PWM简介
  • 02. 硬件设计
  • 03. 配置步骤
  • 04. 程序示例
  • 05. 结果验证
  • 06. 附录
  • 07. 声明

01. PWM简介

脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制,PWM 原理如图 14.1.1 所示:

图 14.1.1 就是一个简单的 PWM 原理示意图。图中,我们假定定时器工作在向上计数 PWM模式,且当 CNT<CCRx 时,输出 0,当 CNT>=CCRx 时输出 1。那么就可以得到如上的 PWM示意图:当 CNT 值小于 CCRx 的时候,IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。改变 CCRx 的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM 输出的频率,这就是 PWM 输出的原理。

STM32F4 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出!这里我们仅使用 TIM14 的 CH1 产生一路 PWM 输出。

02. 硬件设计

用到的硬件资源有:

1) 指示灯 DS0
2) 定时器 TIM14
这两个我们前面都已经介绍了,因为 TIM14_CH1 可以通过 PF9 输出 PWM,而 DS0 就是直接在 PF9 上面的,所以电路上并没有任何变化。

03. 配置步骤

3.1 开启 TIM14 和 和 GPIO 时钟,配置 PF9 选择复用功能 AF9 (TIM14)输出。

要使用 TIM14,我们必须先开启 TIM14 的时钟。这里我们还要配置 PF9 为复用(AF9)输出,才可以实现 TIM14_CH1 的 PWM 经过 PF9输出。 库函数使能 TIM14 时钟的方法是:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //TIM14 时钟使能

我们还要使能 GPIOF 的时钟。然后我们要配置 PF9 引脚映射至 AF9,复用为定时器 14,调用的函数为:

GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9 复用为定时器 14

这里还需要说明一下,对于定时器通道的引脚关系,大家可以查看 STM32F4 对应的数据手册,比如我们 PWM 实验,我们使用的是定时器 14 的通道 1,对应的引脚 PF9 可以从数据手册表中查看:

3.2 初始化 TIM14, 设置 TIM14 的 ARR 和 和 PSC 等参数。

在开启了 TIM14 的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来控制输出 PWM的周期。当 PWM 周期太慢(低于 50Hz)的时候,我们就会明显感觉到闪烁了。因此,PWM周期在这里不宜设置的太小。这在库函数是通过 TIM_TimeBaseInit 函数实现的,

TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx 的

3.3 设置 TIM14_CH1 的 PWM 模式 ,能 使能 TIM14 的 CH1 输出。

我们要设置 TIM14_CH1 为 PWM 模式(默认是冻结的),因为我们的 DS0 是低电平亮,而我们希望当 CCR1 的值小的时候,DS0 就暗,CCR1 值大的时候,DS0 就亮,所以我们要通过配置 TIM14_CCMR1 的相关位来控制 TIM14_CH1 的模式。在库函数中,PWM 通道设置是通过函数 TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我们使用的是通道 1,所以使用的函数是 TIM_OC1Init()。

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

TIM_OCInitTypeDef类型结构体

typedef struct
{uint16_t TIM_OCMode;uint16_t TIM_OutputState;uint16_t TIM_OutputNState; */uint16_t TIM_Pulse;uint16_t TIM_OCPolarity;uint16_t TIM_OCNPolarity;uint16_t TIM_OCIdleState;uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;

这里我们讲解一下与我们要求相关的几个成员变量:
参数 TIM_OCMode 设置模式是 PWM 还是输出比较,这里我们是 PWM 模式。
参数 TIM_OutputState 用来设置比较输出使能,也就是使能 PWM 输出到端口。
参数 TIM_OCPolarity 用来设置极性是高还是低。
其他的参数 TIM_OutputNState,TIM_OCNPolarity,TIM_OCIdleState 和 TIM_OCNIdleState 是高级定时器才用到的。

TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择模式 PWM
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性低
TIM_OC1Init(TIM14, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 4OC1

3.4 使能 TIM14 。

在完成以上设置了之后,我们需要使能 TIM14。使能 TIM14 的方法前面已经讲解过:

TIM_Cmd(TIM14, ENABLE); //使能 TIM14

3.5 修改 TIM14_CCR1 来控制占空比。

在经过以上设置之后,PWM 其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改 TIM14_CCR1 则可以控制 CH1 的输出占空比。继而控制 DS0 的亮度。在库函数中,修改 TIM14_CCR1 占空比的函数是:

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare2);

04. 程序示例

pwm.h

#ifndef __PWM_H__
#define __PWM_H__#include "sys.h"//定时器初始化
void TIM14_PWM_Init(u32 arr, u16 psc);#endif /*__PWM_H__*/

pwm.c

#include "pwm.h"//定时器初始化
void TIM14_PWM_Init(u32 arr, u16 psc)
{GPIO_InitTypeDef GPIO_Init_Struct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_OCInitTypeDef TIM_OCIInitStruct;//使能定时器TIM14时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);//使能GPIO时钟 GPIOFRCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//GPIOF选择位复用功能 GPIOF  PF9GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);//初始化GPIOGPIO_Init_Struct.GPIO_Pin = GPIO_Pin_9;GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_AF;GPIO_Init_Struct.GPIO_OType = GPIO_OType_PP;GPIO_Init_Struct.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init_Struct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOF, &GPIO_Init_Struct);//初始化定时器14TIM_TimeBaseInitStruct.TIM_Period = arr;TIM_TimeBaseInitStruct.TIM_Prescaler = psc;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM14, &TIM_TimeBaseInitStruct);//设置TIM14_CH1为PWM模式TIM_OCIInitStruct.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCIInitStruct.TIM_OutputState = TIM_OutputState_Enable;TIM_OCIInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC1Init(TIM14, &TIM_OCIInitStruct);//使能TIM14在CCR1上的预装载寄存器TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);//ARPE使能TIM_ARRPreloadConfig(TIM14, ENABLE);//使能TIM14TIM_Cmd(TIM14, ENABLE);}

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "iwdg.h"
#include "wwdg.h"
#include "timer.h"
#include "pwm.h"int main(void)
{ u16 led0Value = 0;u8 dir = 1;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);delay_init(168);TIM14_PWM_Init(500 - 1, 84 - 1);while(1){delay_ms(10);if (dir){led0Value++;}else{led0Value--;}if (led0Value > 300){dir = 0;}if (0 == led0Value){dir = 1;}TIM_SetCompare1(TIM14, led0Value);}}

05. 结果验证

我们将看 DS0 不停的由暗变到亮,然后又从亮变到暗。

06. 附录

6.1 【STM32】STM32系列教程汇总

网址:【STM32】STM32系列教程汇总

07. 声明

该教程参考了正点原子的《STM32 F4 开发指南》

【STM32】PWM程序相关推荐

  1. stm32 PWM互补输出

    stm32高级定时器例子-stm32 PWM互补输出 定时器初始化结构体 TIM_TimeBaseInitTypeDef 时基结构体,用于定时器基础参数设置,与TIM_TimeBaseInit函数配合 ...

  2. 【学习记录】 STM32 PWM输出实验

    STM32 PWM工作过程 以通道1为例: CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值. CCMR1: OC1M[2:0]位: 对于PWM方式下,用于设置PWM模式1[110]或 ...

  3. STM32 UART2程序--端口重映射

    STM32 UART2程序 2012-12-04 16:26:05 分类: LINUX USART1程序很多,看看USART2程序.注意红色部分,首先要使能相关端口的时钟. 因为USART2可以映射成 ...

  4. STM32 PWM输出实验

    定时器用来产生PWM输出: STM32 的定时器除了 TIM6 和 7.其他的定时器都可以用来产生 PWM 输出.其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出.而通 ...

  5. STM32 PWM控制舵机

    目录 舵机简介 舵机工作原理 什么是PWM 硬件连线 代码 实现结果 总结 舵机简介 舵机是指在自动驾驶仪中操纵飞机舵面(操纵面)转动的一种执行部件.分有:①电动舵机,由电动机.传动部件和离合器组成. ...

  6. 嵌入式作业使用MDK编译stm32简单程序

    目录 一.MDK和stm32介绍 1.什么是stm32 2.什么是MDK 二.环境配置 1.准备工作 2.安装keil软件 3.keil的环境设置 三.stm32程序编译 1.新建工程 2.新建mai ...

  7. STM32下载程序至SRAM——基于正点原子精英STM32F103ZET6开发板

    STM32下载程序至SRAM--基于正点原子精英STM32F103ZET6开发板 如题,由于STM32的FLASH烧写寿命在1万次左右,对于本人这样的改一行代码都想下载到开发板中测试的强迫症患者,真是 ...

  8. Vscode开发STM32单片机程序

    STM32单片机非常强大,大多数教程都是使用 keil 编译器,keil 是收费的而 gcc 是开源免费的.这里介绍一些使用 gcc + vscode 开发单片机程序的经验.(这里不解释 gcc 是什 ...

  9. ch340串口驱动_如何使用串口来给STM32下载程序

    前言 第一次学习STM32的时候,不知道有调试器这个东西,所以一直是通过串口来给STM32下载程序,下载速度也还算可以,一般是几秒钟完成.后来用了调试器,可以直接在Keil环境下进行下载,而且还可以进 ...

  10. STM32 PWM周期与频率的计算

    文章目录 STM32 PWM周期与频率的计算 频率的计算 占空比的计算 笔记仅供自学,用来回看复习,不一定适合你,如有错误请指出. STM32 PWM周期与频率的计算 TIM_TimeBaseInit ...

最新文章

  1. nginx服务器的负载均衡和动静分离(未完)
  2. Spark源码分析 – SparkEnv
  3. android user-agent iso-8859-1,微信网页授权,错误40163,ios正确,安卓错误?
  4. Django startproject的问题
  5. 从涂鸦到发布 —— 理解API的设计过程
  6. VTK:几何对象之Point
  7. 关于重写session实现的时候可能会导至nginx 502的问题
  8. 嵌入式C语言编程——.h文件与.c文件
  9. Java进阶07 嵌套类
  10. Python 模块之科学计算 Pandas
  11. c语言树莓派音乐播放器,使用web端来控制我的树莓派播放音乐
  12. 近日的思绪(外三首)
  13. 二叉树的三种遍历(递归,栈)
  14. 如何读入一个多行的txt文件,给每行的数据加双引号并保存为一行输出
  15. (一)SpringMVC学习笔记-概述
  16. idea中HTML可以打debug吗,你真的会用idea进行debug吗?idea实用debug教程
  17. 吾儿秘史--趣事糗事大杂烩第二季(2014.6.2-)-更新到2014年9月8日
  18. 如何恢复计算机隐藏的文件夹,win10系统隐藏或取消隐藏文件夹的还原方案
  19. BoomBeach海水效果实现
  20. 罗振宇2021“时间的朋友·长大以后”跨年演讲全文无删减整理,核心观点、大纲提炼

热门文章

  1. 微软官方的SqlHelper
  2. c语言入门中冒泡排序的例题,选择排序和冒泡排序例题解析(c语言)
  3. 压力测试和负载测试区别_如何理解与区分软件性能测试、负载测试、稳定性测试、压力测试...
  4. 求最大、次大和第3大的值
  5. mysql数据库在什么上运行_mysql – 在所有数据库上运行SQL查询
  6. java中常量有初始化值吗,java的变量和常量
  7. 【2012百度之星/资格赛】J:百度的新大厦
  8. [分治] Jzoj P5807 简单的区间
  9. Linux下使用NTFS格式移动硬盘
  10. FFmpegh.264解码