实验程序已经发布到百度网盘,本文末有链接可以自取
STM32定时器查看这篇博客STM32定时器
stm32f103数据手册
一、利用固件库模板点灯(附模板及案例程序
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调试。是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。广泛应用在从测量、通信到功率控制与变换的许多领域中。
例如上图中,图b)是微处理输出的数字信号,实际上他接到电机等功率设备上时,效果相当于图a)。这就是PWM调制。例如输出占空比为50%,频率为10Hz的脉冲,高电平为3.3V.则其输出的模拟效果相当于输出一个1.65V的高电平。
脉冲调制有两个重要的参数,第一个就是输出频率,频率越高,则模拟的效果越好
。第二个就是占空比。占空比就是改变输出模拟效果的电压大小。占空比越大则模拟出的电压越大
。
STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样, STM32 最多可以同时产生 30 路 PWM 输出!这里我们仅利用 TIM2 的CH2 产生一路 PWM 输出。如果要产生多路输出,大家可以根据我们的代码稍作修改即可。
我们首先通过对 PWM 相关的寄存器进行讲解,大家了解了定时器 TIM2 的 PWM 原理之后,我们再讲解怎么使用库函数产生 PWM 输出。
要使 STM32 的通用定时器 TIMx 产生 PWM 输出,除了上一章介绍的寄存器外,七、stm32-TIM定时器(通用定时器中断),我们还会用到 3 个寄存器 ,来控制 PWM 的。这三个寄存器分别是 :捕获/比较模式寄存器
(TIMx_CCMR1/2)、捕获/比较使能寄存器
(TIMx_CCER)、捕获/比较寄存器
(TIMx_CCR1~4)。
接下来我们简单介绍一下这三个寄存器。
该寄存器总共有 2 个, TIMx _CCMR1 和TIMx _CCMR2。 TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。
该寄存器的有些位在不同模式下,功能不一样,所以我们把寄存器分了2层,上面一层对应输出而下面的则对应输入。这里我们需要说明的是模式设置位 OCxM,此部分由 3 位组成。总共可以配置成 7 种模式,我们使用的是 PWM 模式,所以这 3 位必须设置为 110/111。这两种PWM 模式的区别就是输出电平的极性相反。
该寄存器控制着各个输入输出通道的开关。
该寄存器比较简单,我们这里只用到了 CC2E 位,该位是输入/捕获 2 输出使能位,要想PWM 从 IO 口输出,这个位必须设置为 1,所以我们需要设置该位为 1。该寄存器更详细的介绍,请参考《STM32 参考手册》。
该寄存器总共有 4 个,对应 4 个输通道 CH1~4。因为这 4 个寄存器都差不多,我们仅以 TIMx_CCR1 为例介绍,
在输出模式下,该寄存器的值与 CNT 的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。 本章我们使用的是 TIM2 的通道 2,所以我们需要修改 TIM2_CCR2 以实现脉宽控制 LED 的亮度。
我们要利用 TIM2 的 CH2 输出 PWM 来控制 LED 的亮度,但是 TIM2_CH2 默认是接在 PA1上面的,而我们的 LED 接在 PC13 上面,只能用飞线把 PA1 飞到 PC13 上来实现了
TIM2 时钟使能。
初始化 TIM2,设置 TIM2 的 ARR 和 PSC。
设置 TIM2_CH2 的 PWM 模式,使能 TIM2 的 CH2 输出。
使能 TIM2。
修改 TIM2_CCR2 来控制占空比。
stm32f103c8t6自带一个led灯,使用PC13引脚就行了,
切记尽量避免使用PB3、PB4,具体看stm32f103c8t6使用PB3和PB4做普通GPIO使用时发现异常
#include "led.h" //绑定led.h
void LED_GPIO_Config(void) {
GPIO_InitTypeDef GPIO_InitStruct; //初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。
//开启RCC时钟
RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK, ENABLE);
//配置初始化,推挽输出方式和LED_G_GPIO_PIN管脚、赫兹
GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
//GPIO口初始化
GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
}
#ifndef __LED_H_
#define __LED_H_
#include "stm32f10x.h"
#include "sys.h"
#define LED_G_GPIO_PIN GPIO_Pin_13
#define LED_G_GPIO_PORT GPIOC
#define LED_G_GPIO_CLK RCC_APB2Periph_GPIOC
//使用位带操作来实现操作某个IO口的 1个位,由sys.h实现
#define LED PCout(13)
void LED_GPIO_Config(void); //函数定义
#endif
#include "timer.h"
//TIM2 PWM 部分初始化
//PWM 输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM2_PWM_Init(u16 arr, u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //①使能定时器 2 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIO 和 AFIO 复用功能时钟
//TIM2 CH2 的 PWM 脉冲波形 GPIOA.1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //①初始化 GPIO
//初始化 TIM2
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 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //③初始化 TIMx
//初始化 TIM2 Channel2 PWM 模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择 PWM 模式 2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性高
TIM_OC2Init(TIM2, &TIM_OCInitStructure); //④初始化外设 TIM2 OC2
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能预装载寄存器
TIM_Cmd(TIM2, ENABLE); //⑤使能 TIM2
}
#ifndef __TIMER_H_
#define __TIMER_H_
#include "sys.h"
#include "stm32f10x.h"
void TIM2_PWM_Init(u16 arr, u16 psc);
#endif
/******************************** END OF FILE *********************************/
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "stm32f10x.h"
#include "led.h"
#include "timer.h"
int main()
{
/********************************************************************************
* Delay_init(); //本实验使用的是SysTick时钟
* CPU_TS_TmrInit(); //已经使能宏,不需要初始化
* uart1_init(115200); //串口初始化为115200,需要在usart.h中使能
* uart3_init(115200); //串口初始化为115200
********************************************************************************/
/* 定义变量 */
u16 led0pwmval = 0;
u8 dir = 1;
/* 初始化 */
LED_GPIO_Config(); //初始化led使用的GPIO口
TIM2_PWM_Init(899,0);
while (1)
{
Delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval > 300)dir = 0;
if(led0pwmval == 0)dir = 1;
TIM_SetCompare2(TIM2, led0pwmval);
}
}
编译成功
本文选择的是ST_Link烧录工具
如果没有ID号看博客:ST-Link V2烧录问题(已解决)
链接:https://pan.baidu.com/s/1JC2vuPqwP6MWLmvwOVgPtQ 提取码:0000