刘刘 stm32学习日记 (六)定时器

一、介绍

也就是定一个时间,每隔一段时间触发一次中断,然后去处理事情

基本定时器:

 下边三个构成了时基单元(基本计数计时单元){时钟72M(将72M(时间就是计72个就是1us)计72000也就是1ms}

  • 内部时钟首先到PSC预分频器,然后到CNT进行计数,当定时器计数值等与自动重装载的值相等时就会产生一个UI或U,然后NVIC进行通道设置后,CPU就可以相应更新中断了

PSC:预分频器的时钟分割操作,PSC写1就是2分频就是36M,写3就是4分频就是18M;{PSC是16位的,因此最大可以65535就是65536分频}))

CNT计数器:每来一个脉冲,计数值加一,16位所以最大到65535,再加重新从0开始,

自动重装载寄存器:也就是设定的目标时间,当CNT记到这个时间之后就会产生一个中断,然后会清除计数器,开始下一次计数,        

UI(更新中断):指定时器计数值等与自动重装载的事件产生的中断,指向NVIC,配置好NVIC通道后,就能得到CPU的响应了。

U(更新事件)

主从DAC(通过U触发扳机(TRGO)进行   DAC采样,避免重复使用中断)

通用计时器还支持  1向下计数和中央对齐计数,2 外部时钟

二、时序电路

预分频时序

计数器时序

时钟树

三、实战 1

1、目标:

每隔一秒计数1,在oled上显示

2、硬件:仅需要一个oled,

3、软件:

(1)在系统文件夹编写库文件.c .h文件

.h:

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

(2)根据下边结构图,完.c文件

第一步,RCC开启时钟(这里选择TIM2通用定时器在APB1总线上)

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
第二步,选择时基单元的时钟源(这里选择内部时钟)不写也行,默认为内部时钟

	TIM_InternalClockConfig(TIM2);
第三步,配置时基单元(包括预分频器、自动重装器、计数模式)

对TIM2定时器的初始化和配置,用于生成定时中断。通过设置计数器的周期值和预分频器的值,可以确定定时器的计时周期和频率。通过使能更新中断,可以在计数器溢出时触发中断事件。

TIM_InternalClockConfig(TIM2);  // 配置TIM2为内部时钟模式,使用内部时钟源

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;  // 定义TIM_TimeBaseInitStructure结构体,用于配置TIM的基本参数

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // 设置时钟分频系数为1,不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 设置计数器为向上计数模式
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;  // 设置计数器的周期值为10000,即计数器从0到9999
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;  // 设置预分频器的值为7200-1,将输入时钟频率分频为1MHz
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;  // 设置重复计数器的值为0,不使用重复计数功能
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);  // 根据TIM_TimeBaseInitStructure的配置初始化TIM2的时间基准参数

TIM_ClearFlag(TIM2, TIM_FLAG_Update);  // 清除TIM2的更新标志位
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  // 使能TIM2的更新中断,当计数器溢出时会触发更新中断
第四步,配置输出中断控制,允许更新中断输出到NVIC

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 配置中断优先级分组为2,即4位抢占优先级和0位响应优先级
第五步,配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级

对中断控制器(NVIC)的初始化和配置,用于使能TIM2定时器的中断。通过设置中断通道、抢占优先级和响应优先级,可以确定中断的优先级顺序。通过使能中断通道,可以在满足触发条件时触发相应的中断事件。最后,通过使能TIM2定时器,开始计数。


NVIC_InitTypeDef NVIC_InitStructure;  // 定义NVIC_InitStructure结构体,用于配置NVIC的参数

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  // 设置中断通道为TIM2_IRQn,即TIM2的中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  // 使能TIM2的中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  // 设置抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  // 设置响应优先级为1
NVIC_Init(&NVIC_InitStructure);  // 根据NVIC_InitStructure的配置初始化NVIC

TIM_Cmd(TIM2, ENABLE);  // 使能TIM2定时器,开始计数

 以上5步初始化结束

------------------------------------------------------------------------------------------------------------------------------

第六步,中断函数(找到定时器2的中断函数)

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		// 检查是否发生了TIM2的更新中断
		// 如果更新中断已经发生
		// 进入下面的代码块

		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		// 清除TIM2的更新中断标志位
		// 这样可以重置中断状态,以允许下一次中断发生
	}
}

 中断处理函数,它用于处理TIM2定时器的更新中断。首先,它检查TIM2的更新中断标志位是否被设置(即中断是否发生)。如果更新中断已经发生,它会执行清除中断标志位的操作,以允许下一次中断触发。这是一个典型的中断处理程序,用于确保及时响应和处理特定的中断事件。

第七步、主函数
#include "stm32f10x.h"                  // 引入STM32标准库的头文件
#include "Delay.h"                      // 引入延迟函数的头文件
#include "OLED.h"                       // 引入OLED显示库的头文件
#include "Timer.h"                      // 引入定时器库的头文件

uint16_t Num;                             // 声明一个无符号16位整数变量Num

int main(void)
{
	OLED_Init();                          // 初始化OLED显示屏
	Timer_Init();                         // 初始化定时器
	
	OLED_ShowString(1, 1, "Num:");        // 在OLED上显示字符串 "Num:"
	
	while (1)
	{
		OLED_ShowNum(1, 5, Num, 5);      // 在OLED上显示变量Num的值
	}
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Num++;                            // 如果TIM2的更新中断发生,增加Num的值
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除TIM2的更新中断标志位,以准备下一次中断
	}
}

四、实战2  定时器外部时钟

目标:将外部时钟信号来触发事件,在oled上显示事件变化(这里采用对射式红外传感器作为时钟产生装置,当触发时,产生一个时钟被捕获)

硬件:

DO接PA0

软件思路;

就是将实战1里边的.c文件中将选择为内部时钟改为选择外部时钟   


	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);

GPIO引脚初始化


GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

更改自动重装值,因为手动触发开关,所以不需要分频来一次算一次就行,自动重装就设置9,从0-9之后就重置 ,其他的和内部时钟的一样


	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;

观察显示CNT函数 (记得外部声明)



uint16_t Timer_GetCounter(void)
{
	return TIM_GetCounter(TIM2);
}

主函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num;

int main(void)
{
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1, 1, "Num:");
	OLED_ShowString(2, 1, "CNT:");
	
	while (1)
	{
		OLED_ShowNum(1, 5, Num, 5);
		OLED_ShowNum(2, 5, Timer_GetCounter(), 5);
	}
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Num ++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

 现象:每次触发对射管,CNT数值加一,到9后清零,申请中断num++

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值