第8~9周作业--定时器&PWM应用编程

一、STM32定时功能介绍
STM32的定时器功能是一种强大的工具,可用于在嵌入式系统中实现定时操作和控制。STM32微控制器通常具有多个定时器,每个定时器具有多种不同的配置和功能。下面是对STM32定时器功能的一些基本介绍:

  1. 定时器类型:STM32微控制器通常具有几种不同类型的定时器,包括高级定时器(TIM2-TIM5)、基本定时器(TIM6-TIM7)和看门狗定时器(TIM1-TIM3和TIM15-TIM17)。每种类型的定时器都有其特定的用途和特性。
  2. 定时器模式:每个定时器都可以配置为多种模式之一,例如向上计数模式、向下计数模式、中央对齐模式等。根据所需的定时行为,可以选择适当的模式。
  3. 计数范围:定时器的计数范围可以根据需要进行配置。计数周期的范围可以从0到2^32-1,这使得定时器能够用于各种不同的应用场景。
  4. 触发输入:一些定时器类型还具有触发输入,这使得它们能够从外部信号触发计时。这对于需要与外部事件同步的应用非常有用。
  5. 捕获比较功能:定时器可以配置为在达到特定计数值时触发中断或更新输出。这使得定时器可以用于生成毫秒级别的定时或用于PWM控制等任务。
  6. 同步:STM32的定时器之间可以相互同步,这使得它们可以协同工作以实现更复杂的功能。例如,可以使用一个定时器的输出信号来触发另一个定时器的开始或停止。
  7. 定时器链:STM32还支持定时器链,这使得多个定时器可以连接在一起并同步工作。这对于需要精确时间同步的应用非常有用。
  8. 倒计时功能:STM32的定时器还支持倒计时功能,可以在一定的时间间隔后触发一个事件。这对于需要在一段时间后触发特定操作的场景非常有用。
  9. 中断控制:STM32的定时器支持中断控制,这意味着可以在定时器达到特定值时触发中断,然后在中断处理程序中执行特定的任务。
  10. 校准:STM32的定时器还具有校准功能,可以调整计时器的频率以实现更精确的计时。这对于需要高精度计时的应用非常有用。
    总的来说,STM32的定时器功能非常强大,可以根据不同的应用需求进行灵活配置。通过使用这些功能,可以轻松地实现各种定时操作和控制任务。
    二、PWM功能介绍
    PWM(Pulse Width Modulation)即脉冲宽度调制,简称脉宽调制。PWM是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或 MOS 管栅极的偏置,来实现晶体管或 MOS 管导通时间的改变,从而实现开关稳压电源输出的改变。PWM 是一种对模拟信号电平进行数字编码的方法。 通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。 PWM 信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有( ON ),要么完全无( OFF )。 只要带宽足够,任何模拟值都可以使用 PWM 进行编码。在STM32中,PWM功能常用于控制电机速度、调节LED亮度、产生音频信号等应用。通过调整PWM的占空比(高电平时间占总周期的比例),可以控制输出信号的平均电压或功率。
    三、创建工程
    在原有基础工程上,我们在左边文件栏“Hardware"添加一个c文件,和一个头文件。
    在这里插入图片描述
    在“PWM.h”中添加基本的函数语句
#ifndef __PWM_H
#define __PWM_H
#include "stm32f10x.h"                  // Device header




#endif

四、配置函数解析
4.1 在STM32中,控制TIM2使能的是APB1,且需要控制TIM2为内部时钟模式,配置的相关函数为:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//APB1使能。
TIM_InternalClockConfig(TIM2);//TIM2认定内部时钟模式

4.2 配置时基单元需要定义一个结构体变量,再将其结构体成员引出来分别进行配置。声明结构体的语句为

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//配置结构体

根据公式,时钟频率为72MHZ/(PSC+1)/(ARR+1),经过计算,当PSC设置为719,ARR设置为99,时钟频率为1000HZ,也就是0.001s,也就是说,每个电平存在时间为0.001s

//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//配置结构体
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,选择不分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//选择计数模式,向上计数
	TIM_TimeBaseInitStruct.TIM_Period=100-1;//周期,ARR自动重装的值
	TIM_TimeBaseInitStruct.TIM_Prescaler= 720-1;//PSC预分频器的值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才会使用
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);

4.3 需要配置使能中断,设置为输出比较模式,这样才能将已激活的时钟信号进行输出比较从而得到PWM波形。输出比较结构体定义为

TIM_OCInitTypeDef TIM_OCInitStruct;//输出比较结构体定义

能中断的代码如下:

//使能更新中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断到NVIC
  
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);//结构体赋初始值,避免没有出现的成员未编译而报错
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式,选择PWM1模式
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//输出极性,高电平有效
	TIM_OCInitStruct.TIM_OutputState= TIM_OutputState_Enable;//设置输出使能
	TIM_OCInitStruct.TIM_Pulse=0 ;//设置CCR 
    TIM_OC1Init(TIM2,&TIM_OCInitStruct);	

4.4 需要使用LED灯,所以还需要加上GPIO的配置函数。此外,TIM对应GPIO引脚需要查找定义表,TIM2_CH1_ETR引脚复用在PA0上,故我们配置PA0。

//配置GPIO
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//改为复用推挽输出,定时器控制引脚输出电平
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOA, GPIO_Pin_0);
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);

4.5 PWM的占空比的公式为CCR/ARR+1。前面我们设定为ARR为99,故我们可以设定CCR在0-100波动,这样算出的占空比就是0-100%了,具体结果会在主函数里展示。我们现在只是定义了一个输出比较函数,在STM32标准库里,系统给出了设置CCR函数为

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)

我们可以通过这个函数来设定一个不断变化的CCR值。
在这里我们写入以下代码

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2,Compare);//设置CCR寄存器的值,可以随时改变CCR的值
	
	
	
}

4.6 头文件以及C文件最终函数
头文件:

#ifndef __PWM_H
#define __PWM_H
#include "stm32f10x.h"                  // Device header

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);


#endif

C文件

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//APB1使能。
	TIM_InternalClockConfig(TIM2);//TIM2认定内部时钟模式
	
	
	//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//配置结构体
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,选择不分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//选择计数模式,向上计数
	TIM_TimeBaseInitStruct.TIM_Period=100-1;//周期,ARR自动重装的值
	TIM_TimeBaseInitStruct.TIM_Prescaler= 720-1;//PSC预分频器的值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才会使用
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	//使能更新中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断到NVIC
  
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);//结构体赋初始值,避免没有出现的成员未编译而报错
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式,选择PWM1模式
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//输出极性,高电平有效
	TIM_OCInitStruct.TIM_OutputState= TIM_OutputState_Enable;//设置输出使能
	TIM_OCInitStruct.TIM_Pulse=0 ;//设置CCR 
  TIM_OC1Init(TIM2,&TIM_OCInitStruct);	
	
	//TIM对应GPIO引脚需要查找定义表,TIM2_CH1_ETR引脚复用在PA0上
	//配置GPIO
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//改为复用推挽输出,定时器控制引脚输出电平
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOA, GPIO_Pin_0);
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2,Compare);//设置CCR寄存器的值,可以随时改变CCR的值
	
	
	
}


五、主函数编写解析
5.1 主函数代码
在for循环中,不断调用设置CCR的函数,不断改变CCR从而实现呼吸灯,最终代码如下:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
//#include "OLED.h"
#include "PWM.h"
#include "LED.h"
#include "Delay.h"
uint16_t Num;
int main(void)
{
//	OLED_Init();
    PWM_Init();//配置函数
//  OLED_ShowString(1,1,"a:");
//  OLED_ShowString(2,1,"b:");
	while (1)
	{//在for循环中,不断调用设置CCR的函数实现呼吸灯
		for(Num=0;Num<=100;Num++)//幅值不断增大
		{
			
			PWM_SetCompare1(Num);
			Delay_ms(10);//通过延时函数可改变闪动的周期。
//			OLED_ShowNum(1,6,Num,3);
		}
		for(Num=0;Num<=100;Num++)//幅值不断减小
		{
			
			PWM_SetCompare1(100-Num);
			Delay_ms(10);	
//			OLED_ShowNum(2,6,100-Num,3);
		}
		
	}
}


六、烧录结果以及波形观察
在PA0端口插上一个LED灯,其他跟之前的实验一样。
在这里插入图片描述
打开魔术棒,设置如下:
在这里插入图片描述
在这里插入图片描述
打开keil的调试界面,点击逻辑分析仪:
在这里插入图片描述
在界面点击”SET UP“
在这里插入图片描述
在弹出界面中设置以下(上面栏里填入”PORTA.0)。
在这里插入图片描述
得到结果如下:
在这里插入图片描述
七、总结
通过本次实验使我明白了不同基本定时中断模式的运作原理,也探索了通用定时器的输出比较功能。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值