当前位置:   article > 正文

stm32f103呼吸灯(PWM脉冲宽度调制)_stm32f103pwm输出分辨率

stm32f103pwm输出分辨率

stm32呼吸灯(PWM脉冲宽度调制)



任务简介
使用TIM3TIM4,分别输出一个PWM波形PWM的占空比随时间变化,去驱动你外接的一个LED以及最小开发板上已焊接的LED(固定接在 PC13 GPIO端口),实现两个 LED呼吸灯的效果。

实验工具:
(1)软件

(2)硬件

  • STM32F103C8T6的最小核心板
  • LED小灯

一.输出比较简介

  • OC(Output Compare)输出比较
  • 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
  • 每个高级定时器和通用定时器(TIM)都拥有4个输出比较通道(CH1,CH2,CH3,CH4)
  • *高级定时器的前3个通道额外拥有死区生成和互补输出的功能
  • 我们需要记住的是如果要用TIM定时器产生PWM信号,则输出比较必不可少。

二.PWM简介

1.名称概念

  • PWM(Pulse Width Modulation)脉冲宽度调制,是一个数字输出信号

2.原理

  • 具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域。
  • 按理说,数字输出信号只能让LED灯完全亮和完全灭两种状态,但为什么PWM能让LED灯看起来有呼吸效果呢?

  • 由于LED在熄灭的时候由于余晖和人眼视觉暂留现象,LED不会立马熄灭,而是会有一定的惯性,过一会儿才会熄灭,所以我们让LED不断地点亮熄灭,当点亮熄灭的频率足够大(也就是每次点亮熄灭的时间间隔很短的时候),在我们人眼看来LED就不会闪烁,而是会呈现一个与LED常亮时候不同的中等亮度

  • 当我们调控点亮和熄灭的时间比例的时候就能让LED呈现出不同的亮度级别。
    在这里插入图片描述

3.PWM参数

在这里插入图片描述

①频率1/Ts:PWM频率等于TIM经过预分频后,计数器CNT随时间自增加到与自动重装器ARR值相等的频率。PWM频率越快,等效的模拟信号就越平稳但是性能开销就越大。
②占空比T(on)/T(s)高电平时间相当于整个周期时间的比例占空比越大,等效模拟电压越趋近于高电平,占空比越小,等效模拟电压越趋近于低电平。
③分辨率:占空比变化步距,也就是变化的细腻程度(也就是占空比变化的最小数值,例如占空比最小只能从1%跳到2%,那么分辨率就是1%)。

三.输出比较通道

  • 由于实验功能简单,这里用不到高级定时器,所以我们只说明通用定时器的输出比较通道

在这里插入图片描述

这里先放图,下面解释工作流程

  • 1.比较CNT计数器与CCR(自己设置的输出比较的一个参数值,后面会讲)。
  • 2.根据比较的结果和输出模式来决定oc1ref参考信号的值,这里给出PWM需要用到的输出控制的模式介绍。
    在这里插入图片描述
  • 3.接下来进入一个极性选择,当给这个极性选择的寄存器写0,信号不翻转,进来什么样出去就是什么样,当给这个寄存器写1,信号非门取反。电平翻转。()
  • 注意
    相当于可以由第二步的PWM输出模式和第三步的极性选择来灵活地控制,例如使用PWM1的正极性与PWM2的反极性最终的输出都是一样的
  • 4.输出使能到OC1引脚,也就是CH1通道的引脚(可以在引脚的定义表里查看对应的是哪个gpio口)

四.PWM基本结构

在这里插入图片描述

CCR是我们自己设置的用来调整占空比的捕获/比较器
占空比受CCR调控**,CCR设置得大一些,占空比就变大,CCR设置得低一些,占空比就变小**
这样输出的REF就是频率可调,占空比也可调的PWM波形,在经过极性选择和输出使能输出到GPIO口

五.参数计算

  • PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
    在这里插入图片描述

  • PWM占空比: Duty = CCR / (ARR + 1)
    在这里插入图片描述

  • PWM分辨率: Reso = 1 / (ARR + 1)

六.具体实现

在这里插入图片描述

1.实现步骤

  • 第一步:RCC开启时钟,把要用的TIM外设和GPIO外设的时钟打开
  • 第二步:配置时基单元
  • 第三步:配置输出比较单元
  • 第四步:配置GPIO,把PWM需要的GPIO口初始化为复用推挽的输出配置
  • 第五步:运行控制

2.几个要点

①.计算参数

我们准备输出一个1KHz,占空比可任意调节,分辨率为1%的PWM波形

PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
这里CK_PSC是系统主频72MHz
72M/(PSC+1)/(ARR+1)=1000
PWM占空比: Duty = CCR / (ARR + 1)
CCR/(ARR+1)=50%
PWM分辨率: Reso = 1 / (ARR + 1)
1/(ARR+1)=1%
CCR=50
PSC=719
ARR=99
我们可以调控CCR的值来控制占空比

②.输出模式

为什么选择复用推挽输出
如果选择普通开漏推挽输出,引脚的控制权来自于输出寄存器,如果想让定时器控制引脚,则选择复用推挽输出,这时候与输出寄存器断开,控制权移交给片上外设。这里就是CH1通道。

3.代码部分

  • PWM.c
#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	//第一步开启TIM时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	
	 
	//选择时基单元时钟,选择内部时钟   如果不调用也是默认调用
	TIM_InternalClockConfig(TIM3);
	TIM_InternalClockConfig(TIM4);

	//第二步配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct1;
	TIM_TimeBaseInitStruct1.TIM_ClockDivision = TIM_CKD_DIV1;//这里的值关系不大
	TIM_TimeBaseInitStruct1.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct1.TIM_Period = 100-1;//自动重装计时器的值 ARR
	TIM_TimeBaseInitStruct1.TIM_Prescaler = 7200-1;  //预分频器的值 PSC
	TIM_TimeBaseInitStruct1.TIM_RepetitionCounter = 0; //重复计数器的值,高级定时器才有,这里直接给0
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct1);
	//-----------------------------------------------------------------------
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct2;
	TIM_TimeBaseInitStruct2.TIM_ClockDivision = TIM_CKD_DIV1;//这里的值关系不大
	TIM_TimeBaseInitStruct2.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct2.TIM_Period = 100-1;//自动重装计时器的值 ARR
	TIM_TimeBaseInitStruct2.TIM_Prescaler = 7200-1;  //预分频器的值 PSC
	TIM_TimeBaseInitStruct2.TIM_RepetitionCounter = 0; //重复计数器的值,高级定时器才有,这里直接给0
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct2);
	


	//第三步设置输出比较单元
	TIM_OCInitTypeDef TIM_OCInitStruct1;
	TIM_OCStructInit(&TIM_OCInitStruct1);//先给这个结构体赋初值,如果不赋初值后面我们也不给所有成员变量赋值的话,会出现问题
	TIM_OCInitStruct1.TIM_OCMode =  TIM_OCMode_PWM1 ; //设置输出比较模式
	TIM_OCInitStruct1.TIM_OCPolarity = TIM_OCPolarity_High;  //设置输出比较的极性,High值高极性,极性不翻转,REF直接输出
	TIM_OCInitStruct1.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能
	TIM_OCInitStruct1.TIM_Pulse =10;   //设置CCR的寄存器值
	TIM_OC1Init(TIM3,&TIM_OCInitStruct1);
	//--------------------------------------------------
	TIM_OCInitTypeDef TIM_OCInitStruct2;
	TIM_OCStructInit(&TIM_OCInitStruct2);//献给这个结构体赋初值,如果不赋初值后面我们也不给所有成员变量赋值的话,会出现问题
	TIM_OCInitStruct2.TIM_OCMode =  TIM_OCMode_PWM1 ; //设置输出比较模式
	TIM_OCInitStruct2.TIM_OCPolarity = TIM_OCPolarity_High;  //设置输出比较的极性,High值高极性,极性不翻转,REF直接输出
	TIM_OCInitStruct2.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能
	TIM_OCInitStruct2.TIM_Pulse =10;   //设置CCR的寄存器值
	TIM_OC1Init(TIM4,&TIM_OCInitStruct2);
	
	
	//第四步配置GPIO,把PWM需要的GPIO口初始化为复用推挽的输出配置
	GPIO_InitTypeDef GPIO_InitStructure1;
	GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure1.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure1);
	//---------------------------------------------------
	GPIO_InitTypeDef GPIO_InitStructure2;
	GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure2.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure2);

	
	//启动定时器
	TIM_Cmd(TIM3,ENABLE);
	TIM_Cmd(TIM4,ENABLE);
}
 

//TIM3设置CH1通道的CCR的值
void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare1(TIM3,Compare);
}
//TIM4设置CH1通道的CCR的值
void PWM_SetCompare4(uint16_t Compare)
{
	TIM_SetCompare1(TIM4,Compare);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • PWM.h
#ifndef  _PWM_H
#define _PWM_H
void PWM_Init(void);
void PWM_SetCompare3(uint16_t Compare);
void PWM_SetCompare4(uint16_t Compare);
#endif


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "PWM.h"

uint8_t i;

int main(void)
{
	PWM_Init();
	
	while(1)
	{
	//循环调用修改CCR的值,可以通过调整延时函数的值来控制呼吸快慢
		for(i = 0; i<=100;i++)
		{
			PWM_SetCompare3(i);
			PWM_SetCompare4(i);
			Delay_ms(5);
		}
		
		for(i = 0; i<=100;i++)
		{
			PWM_SetCompare3(100-i);
			PWM_SetCompare4(100-i);
			Delay_ms(5);
		}
		
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

七.电路连接即实验结果

请添加图片描述

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号