【嵌入式基础】定时器&PWM练习

本次实验是在前面实验的基础上加入定时器和PWM脉冲宽度调制,之前的延时功能都是通过delay函数实现的。而本次作业通过定时器Timer方式实现时间的精准控制,更有利于CPU的运行,再通过PWM脉冲宽度调制,输出波形,分析PWM的占空比随时间变化。

目录

一、定时器Timer简介

1、定时器Timer介绍

2、定时器Timer分类

 3、定时器功能单元

4、定时器特色

5、定时器事件

6、定时器时钟源

 7、工作原理

二、定时器实现LED闪烁

1、题目要求

2、建立工程并设置工程环境

3、代码编写

4、编译烧录

 5、效果展示

三、基于PWM的呼吸灯

1、题目要求

2、PWM脉冲宽度调制

3、STM32上的PWM

3、建立工程和配置环境

 4、代码编写

5、编译烧录

四、实验总结

五、参考文献


一、定时器Timer简介

1、定时器Timer介绍

在大容量的 STM32F103xx增强型系列产品包含最多2个高级控制定时器、4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器,本次的目标芯片(STM32F103C8T6)也是大容量系列,所以具备以上所述的定时器种类。

  • 能够对内部时钟信号或外部输入信号进行计数,数值达到设定要求时,向CPU发起中断请求,完成外部程序的运行
  • 本质就是进行计数,选择内部时钟脉冲,作为计数器时,技术信号的来源选择非周期脉冲信号

2、定时器Timer分类

首先学习一下分类也可以大致了解一下各个定时器的特点,此处按功能分类,可分为如下三类:

基本定时器:几乎没有任何对外输入/输出,常用作时基,实现基本的计数、定时功能。例如Systick,TIM6,TIM7(其中Systick又为核内定时器,TIM6,TIM7为外设定时器),框图如下

 通用定时器:除了基本定时器的时基功能外,还可对外做输入捕捉、输出比较以及连接其它传感器接口【编码器和霍尔传感器】 。(例如TIM2-TIM5)框图如下

 高级定时器: 此类定时器的功能最为强大,除了具备通用定时器的功能外,还包含一些与电机控制和数字电源应用相关的功能,比方带死区控制的互补信号输出、紧急刹车关断输入控制。(例如TIM1,TIM8)框图如下

 3、定时器功能单元

可把定时器大致分为六个功能单元

从模式控制单元:负责时钟源、触发信号源的选择;控制计数器的启停、复位、门控等;
时基单元:定时器核心单元。负责时钟源的分频、计数、溢出重装等。
输入单元:为部分的时钟信号、 捕捉信号、 触发信号提供信号源。
比较输出单元:通过对比较寄存器与计数器的数值匹配比较,实现不同输出波形。
触发输出单元:输出触发信号给到其它定时器或外设。
捕捉比较单元: 是输入捕捉或比较输出的公共执行单元。

4、定时器特色

定时器中的PSC/ARR/RCR/CCRx寄存器具有预装载功能,即每类寄存器具有双寄存器机制,分别由各自的影子寄存器和预装载寄存器组成。
TIMx_PSC 分频寄存器,设置分频器对时钟源的分频比或分频系数
TIMx_CNT 核心计数器,对从分频器过来的时钟进行计数
TIMx_ARR 自动重装寄存器,为计数器设置计数边界或初始值,决定计数脉冲的多少或计时周期长短。比如计数器向上计数时,记到多少发生溢出;向下计数时从多少开始往下计数。带预装载使能控制位ARPE@TIMx_CR1
TIMx_RCR 重复计数器,重复计数器是个向下计数器,当计数器发生 TIMx_RCR+1次溢出动作后会触发更新操作。
TIMx_CCR 捕捉/比较寄存器,带预装载使能控制位OCxPE@TIMx_CCMR
当关闭预装载使能位时,用户修改预装寄存器的数据后会立即被拷贝进影子寄存器【实际寄存器】 ,否则,修改过的预装寄存器的数据只能等到下次更新事件来完成从预装寄存器数据到影子寄存器的拷贝更新。
影子寄存器是真正起作用的寄存器,预装载寄存器为影子寄存器提供缓冲,提前做数据或指令准备; 因为定时器工作往往具有一定周期性,如果每次我们的参数修改都直接作用于实际寄存器,往往不可避免会影响到当前周期的正常计数以及相关的输出动作。
用户操作的永远只是预装载寄存器!包括DMA的访问。
ARR/CCR影子寄存器的预装功能可软件开启或关闭。PSC/RCR影子寄存器的预装功能不可通过软件关闭,始终开启。在开启预装载功能时,影子寄存器的内容必须借助更新事件完成更新!

5、定时器事件

以下几类事件都可触发中断或DMA请求;

更新事件: 比如影子寄存器更新往往需借助该事件;
触发事件:定时器收到各类触发输入信号时往往激发该事件;
捕获、比较事件: 发生输入捕捉或比较输出时会产生该事件;
由第三章的定时器特色学习我们知道影子寄存器的更新依赖于更新事件,我们这变介绍一下更新事件。首先我们必须学习一下更新操作。
注意:更新操作与更新操作之间的牵连
更新操作【事件源】可分为以下三类:

1.核心计数器的溢出【上溢或下溢】
2.软件复位操作【对TIMX_EGR@UG】 (软件产生更新操作,软件置1,硬件自动清零)
3.工作在复位模式下的定时器收到触发信号【即复位触发信号】
 

6、定时器时钟源

四个来源;内部时钟源、 ETR脚、触发信号,编码器模式

  • 1、内部时钟源, 来自芯片时钟系统给到定时器的时钟
  • 2、来自于芯片ETR脚的外来时钟
  • 3、来自于各类触发输入信号作为时钟
  • 4、编码器模式

 框图如下

 7、工作原理

在选定的时钟源(可以是内部的也可以是外部的)和预分频器TIMX_PSC的驱动下,根据设置的计数模式(向上、向下、中央对齐)自动。

装载计数器TIMX_CNT开始计数;如果使能了相应的事件(更新事件、触发事件、输入捕获、输出比较)则会产生相应的中断。

如果没有开启输入和输出,只使能了计数器计数溢出后自动装载,可以做为一个简单定时器使用,计数器自己开始周期计数
如果开启了通道输入捕获,当检测到ICx信号上相应的边沿后,计数器(CNT)的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中,通过中断的方式可以读取出来假设为n1,然后更改输入捕获的信号级性(上升沿或下降沿),当再次检测到ICx信号上相应的边沿后,计数器(CNT)的当前值再次被锁存到捕获/比较寄存器(TIMx_CCRx)中假设为n2;n2 -n1节可算出电平的持续时间
如果开启了输出控制,可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的PWM信号。
如果选择外部的同步时钟信号(TI1F_ED、TI1FP1、TI2FP2)作为计数器的时钟源,可以用来统计脉冲,实现脉冲频率采集功能。

二、定时器实现LED闪烁

1、题目要求

前面的实验中,延时功能都是通过delay函数实现的。这种方式,相当于让CPU一直在做无用功,还不能做别的事情。这一节通过定时器的方式实现时间的精准控制,相当于给CPU上了一个闹钟,CPU平时处理其它任务,当定时时间到了以后,处理定时相关的任务。请设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁。

2、建立工程并设置工程环境

新建工程,进行基本配置。通过点击“ACCESS TO MCU SELECTOR”来创建一个新的工程:

 芯片选择“STM32F103C8”,开启工程。

 打开外部时钟,点击“System Core”,选择RCC,在右侧弹出的菜单栏中选择“Crystal/Ceramic Resonator”。

 选择调试接口,点击“System Core”,选择SYS。,在右侧弹出的菜单栏中选择“Serial Wire”。

 配置IO。配置PC15,并命名为D1。这里我们只使用一个LED。

配置定时器2与定时器3。我们使用定时器来实现定时的功能。如图所示,点击“Timer”,选择“TIM2”和“TIM3”,配置定时器的时钟源为内部时钟;设置分频系数为71,向上计数模式,计数周期为5000,使能自动重载模式。

 分频系数那里虽然写的是71,但系统处理的时候会自动加上1,所以实际进行的是72分频。由于时钟我们一般会配置为72MHZ,所以72分频后得到1MHZ的时钟。1MHZ的时钟,计数5000次,得到时间5000/1000000=0.005秒。也就是每隔0.005秒定时器2会产生一次定时中断。

配置中断,开启定时器2和3的中断。

并且生成定时器2中断优先级配置代码

选择Connectivity,点开USART1,Mode选择异步通信Asynchronous:

时钟配置。这里,我们需要把它倍频到72MHZ。先点击“Clock Configuration”页面,按照下面红色框中的值,从左到右进行配置即可。

 生成工程。在工程管理页面“Project Manager”,先点击“Project ”,选择如下配置:

  再点击“Code Generator”,进行如下配置:

 最后,点击右上角那个不像按钮的按钮“GENERATE CODE”,即可生成相应工程。工程生成之后,会弹出对话框,提示你是否需要打开。选择打开。

3、代码编写

修改工程。生成工程后,打开,添加中断响应之后所需的一些代码。在main.c文件中添加如下内容:

	HAL_TIM_Base_Start_IT(&htim2);
	HAL_TIM_Base_Start_IT(&htim3);

该函数表示启动相应的定时器,“h”表示HAL库,“tim2”表示定时器2,“tim3”表示定时器3,所以这行代码的意思就是启动定时器2和定时器3。

 串口输出代码:

	uint8_t hello[20]="hello windows!\r\n";

 接下来添加的函数为定时器的中断回调函数,当产生定时中断的时候,会自动调用这个函数。在函数内部定义了一个静态变量:time_cnt。当它大于等于100的时候,才会执行if里面的代码。也就是说需要发生100次中断,才会让LED的状态翻转。前面已经算过了,一次定时中断的时间是0.005秒,所以400次中断的时间是0.005*400=2.0秒。也就是说每隔2.0秒,LED的状态翻转一次。

代码如下:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint32_t time_cnt =0;
	static uint32_t time_cnt3 =0;
	if(htim->Instance == TIM2)
	{
		if(++time_cnt >= 400)
		{
			time_cnt =0;
			HAL_GPIO_TogglePin(D1_GPIO_Port,D1_Pin);
		}
	}
	if(htim->Instance == TIM3)
	{
		if(++time_cnt3 >= 1000)
		{
			time_cnt3 =0;
    HAL_UART_Transmit(&huart1,hello,20,100000);
		}
			
	}
}

4、编译烧录

 编译上面修改完之后的代码

结果显示,编译无误,开始烧录。

借助flymcu软件进行烧录

 5、效果展示

串口通信结果

通过串口接收时间来看,是每隔5s发送一个“hello world”,符合实验要求。

LED闪烁 

也符合实验预期。 

三、基于PWM的呼吸灯

1、题目要求

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

2、PWM脉冲宽度调制

使用脉冲占空比拟合不同波形的方式称为 PWM(脉冲宽度调制)控制技术——通过 对一系列脉冲的宽度进行调制,来等效地获得所需要波形(含形状和幅值)。PWM 控制 的基本原理为:冲量相等而开头不同的窄脉冲加在具有惯性的环节上时,其效果基本 相同。其中冲量指窄脉冲的面积;效果相同指环节输出响应波形基本相同。 例如:可以用一系列等幅不用一系列等幅不等宽的脉冲来代替一个正弦半波,见图

要改变等效输出正弦波幅值,按同一比例改变各脉冲宽度即可。 若把拟合的波形改成呼吸特性曲线,即可得到控制呼吸灯使用的 PWM 波形,要生成 拟合的 PWM波形,通常使用计算法和调制法,本文中使用计算法:根据拟合波形的频率、幅值和半周期脉冲数,准确计算 PWM 波各脉冲宽度和间隔,据此控制开关器件的通断,就可得到所需 PWM 波形。在下边编程实现中会详细说明。

要改变PWM输出波形的宽度,就要改变比较寄存器 CCRx 的值,想要输出不通宽度来拟合正弦波,则需要CCRx的值呈现如下图的变化趋势,即要生成一张CCRx的数值表,按周期变化将表中元素的值赋给CCRx。

3、STM32上的PWM

PWM产生
STM32的定时器除了TIM6和7,其他的定时器都可以用来产生PWM输出。其中高级定时器TIM1和TIM8可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出。
脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。

PWM相关寄存器
包含三个寄存器:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。在TIMx_CCMRx寄存器中的OCxM位写入110(PWM模式1)或111(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。
捕获/比较模式寄存器(TIMx_CCMRx)
下图为TIMx_CCMR1寄存器的各位描述:

3、建立工程和配置环境

 新建工程,进行基本配置。通过点击“ACCESS TO MCU SELECTOR”来创建一个新的工程:

 芯片选择“STM32F103C8”,开启工程。

 打开外部时钟,点击“System Core”,选择RCC,在右侧弹出的菜单栏中选择“Crystal/Ceramic Resonator”。

 选择调试接口,点击“System Core”,选择SYS。,在右侧弹出的菜单栏中选择“Serial Wire”。

配置定时器3和定时器4。如图,选中定时器3和定时器4;选择时钟源为“Internal Clock”,通道2选择“PWM Generation CH2”,设置分频系数为71,计数周期为500,其它默认。设置占空比初始值为10,其实这里不写也没影响。

 

 时钟配置。这里,我们需要把它倍频到72MHZ。先点击“Clock Configuration”页面,按照下面红色框中的值,从左到右进行配置即可。

生成工程。在工程管理页面“Project Manager”,先点击“Project ”,选择如下配置:

再点击“Code Generator”,进行如下配置:

 最后,点击右上角那个不像按钮的按钮“GENERATE CODE”,即可生成相应工程。工程生成之后,会弹出对话框,提示你是否需要打开。选择打开。

 

 4、代码编写

修改工程。打开工程,主要修改main.c文件,定义一个变量,用来存储占空比:

初值设为0.

uint16_t duty_num = 0;

 开始TIM3和TIM4的通道2,输出PWM。代码:

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_2);

 while函数中调用函数,代码如下:

while (duty_num< 500)
	  {
		  duty_num++;
		  __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, duty_num);  
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_1, duty_num);  			
		  HAL_Delay(1);
	  }
	  while (duty_num)
	  {
		  duty_num--;
		  __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, duty_num);    
       __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_2, duty_num);  
			
		  HAL_Delay(1);
	  }
	  HAL_Delay(200);

5、编译烧录

编译函数:

编译无误,可以进行烧录,借用flymcu软件烧录 :

效果展示

 

四、实验总结

通过这次实例演训,初步认识了STM32定时器的相关理论知识,以及在STM32F103C8T6核心开发板下,通过使用定时器Timer方式,来实现串口定时输出及LED灯周期闪烁的操作步骤。还学习到了PWM的相关理论知识,以及在STM32F103C8T6核心开发板下,通过TIM3和TIM4输出PWM波形实现2个 LED呼吸灯效果的操作步骤;

虽然中间过程有点曲折,但最终实验结果还是基本能符合预期。

五、参考文献

http://www.mcublog.cn/stm32/2021_01/stm32cubemx-dingshiqi-led/
http://www.mcublog.cn/stm32/2021_01/stm32cubemx-pwm-huxideng/
https://blog.csdn.net/qq_39257301/article/details/100057561
https://blog.csdn.net/zmhDD/article/details/111942507
https://blog.csdn.net/qq_45237293/article/details/111997424

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值