STM32定时器

news2024/11/15 23:51:37

目录

基本定时器结构框图

通用定时器结构框图

高级定时器结构框图

​编辑TIMx时基单元 

定时工作原理

影子寄存器

​编辑

定时器中断基本结构

定时器计时中断

定时器外部中断

输出比较  OC

输出比较模式

PWM基本结构

输出比较常用函数

使用PWM来驱动舵机

输入捕获  IC 

测量频率

输入捕获通道

主从触发模式

​编辑输入捕获基本结构

PWMI基本结构

PWM输入模式时序

编码器接口

正交编码器

编码器接口基本结构

​编辑

工作模式


  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72Mhz计数时钟下可以实现最大65535*65535/72M = 59.65s的定时
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器通用定时器基本定时器三种类型 
定时器类型
类型总线功能
高级定时器APB2拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能
通用定时器APB1拥有基本定时器全部功能、并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能
基本定时器APB1拥有定时器中断、主模式触发DAC的功能

 

 

 

 

 

  • 基本定时器:TIM6、TIM7
  • 通用定时器:TIM2~TIM5
  • 高级定时器:TIM1、TIM8

STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4

基本定时器结构框图

通用定时器结构框图

高级定时器结构框图
TIMx时基单元 
  • 计数器寄存器(TIMx_CNT)
  • 预分频器寄存器(TIMx_PSC)
  • 自动装载寄存器 (TIMx_ARR)
定时工作原理

        首先,定时器时钟信号送入16位可编程预分频器寄存器(TIMx_PSC),该预分频器系数为0~65535之间的任意数值,TIMx_PSC溢出后,会向16位的计数器寄存器(TIMx_CNT)发出一个脉冲信号(CK_CNT),每来一个CK_CNT脉冲,TIMx_CNT计数器值+1,当TIMx_CNT的值与自动装载寄存器 (TIMx_ARR)的设定值相等后就自动生成更新事件(也可产生DMA请求,产生中断信号或触发ADC同步电路),并且TIMx_CNT计数器值自动清零,然后重新开始计数。 

影子寄存器

比如预分频器(或者自动装载寄存器 ),这个控制寄存器带有缓冲器(影子寄存器) ,能够在工作时被改变,新的预分频器的参数在下一次更新事件到来时被采用。

(引入这类寄存器的目的实际上是为了同步,让值的变化和更新事件同步发生,防止在运行途中更改造成错误,比如自动装载寄存器一开始的值为F5,后面更新为36,此时计数器寄存器已经到F1了,如果没有影子寄存器,F5--->36立即生效,此时F1已经超过36了,F1就只能增加,但他的目标却是36,那就只能一直加到FFFF再回到0,再加到36,才能产生更新)

预分频器时序

计数器计数频率:CK_CNT = CK_PSC/ (TIMx_PSC + 1)

计数器时序

计数器溢出频率:CK_CNT_OV = CK_PSC/(TIMx_PSC + 1)/(TIMx_ARR) 

计数器无预装时序

计数器有预装时序

定时器中断基本结构

计数器时钟选择

  • 内部时钟(CK_INT)
  • 外部时钟模式1:外部输入脚(TIx)
  • 外部时钟模式2:外部触发输入(ETR)
  •  内部触发输入:使用一个定时器作为另一个定时器的预分频器

时基单元的时钟选择函数

一些基本函数 (stm32f10x_tim.h)

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
// 时基单元初始化函数
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
// 使能计数器(运行控制)
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
// 使能中断输出信号
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                   uint16_t ExtTRGFilter);
// 单独用来配置ETR引脚的预分频器,极性,滤波器这些参数
......
定时器计时中断
void Timer_Init(void) {
	
	// 1.RCC开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	
	// 2.选择时基单元的时钟源
	TIM_InternalClockConfig(TIM4);
	
	// 3.配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;   // 自动重装寄存器 溢出就会产生中断
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; // 预分频器  1ms
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
	
	// 因为TIM_TimeBaseInit()函数最后 有TIMx->EGR = TIM_PSCReloadMode_Immediate;
	// 所以要先清除事件
	TIM_ClearFlag(TIM4, TIM_FLAG_Update);
	// 4.配置中断输出控制,允许更新终端输出到NVIC
	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
	
	// 5.配置NVIC,并分配优先级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);

	// 6.运行控制,使能计数器
	TIM_Cmd(TIM4, ENABLE);
}

中断处理函数

在启动文件中找中断处理函数

void TIM4_IRQHandler(void) {

	if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) {
	
        // 中断要执行的代码
		Count++;
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
	}
}
定时器外部中断
void Timer_Init(void) {
	
	// 1.RCC开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置GPIO,选择模式和引脚
	GPIO_InitTypeDef GPIO_InitStruture;
	GPIO_InitStruture.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruture.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruture);
	
	// 2.选择时基单元的时钟源
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0f);
	
	// 3.配置时基单元
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;   // 自动重装寄存器 溢出就会产生中断
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;  // 预分频器
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	// 因为TIM_TimeBaseInit()函数最后 有TIMx->EGR = TIM_PSCReloadMode_Immediate;
	// 所以要先清除事件
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	// 4.配置中断输出控制,允许更新终端输出到NVIC
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	// 5.配置NVIC,并分配优先级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStructure);
	
	// 6.运行控制,使能计数器
	TIM_Cmd(TIM2, ENABLE);
}

void TIM2_IRQHandler(void) {

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


uint16_t Timer_GetCounter(void) {

	return TIM_GetCounter(TIM2);
}

(来一个外部事件比如遮挡一下对射式传感器,计数器值++,直到它的值等于自动重装寄存器的值时会产生溢出,计数器值清零,重新计数) 

输出比较  OC
  • 通过比较CNT与CCR寄存器值的关系,对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
  • 每个高级定时器和通用定时器都拥有4个输出比较通道
  • 高级定时器的前3个通道额外拥有死区生成和互补输出的功能

输出比较通道(通用)

输出比较模式
输出比较模式
模式                                                        描述
冻结

CNT=CCR时,REF保持为原状态

匹配时置有效电平

CNT=CCR时,REF置有效电平

匹配时置无效电平

CNT=CCR时,REF置无效电平

匹配时电平翻转

CNT=CCR时,REF电平翻转(输出方波)

强制为无效电平

CNT与CCR无效,REF强制为无效电平

强制为有效电平

CNT与CCR无效,REF强制为有效电平

PWM模式1

向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平

向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平

PWM模式2

向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平

向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平

PWM基本结构

 

PWM频率:Freq = CK_PSC/(TIMx_PSC+1)/(TIMx_ARR+1)

PWM占空比:Duty = CCR / (TIMx_ARR+1)

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

输出比较常用函数
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
// 输出比较控制
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
// 给输出比较结构体赋一个默认值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
// 单独更改CCR寄存器的值
使用PWM来驱动舵机

舵机是一种根据输入PWM信号占空比来控制输出角度的装置,输入PWM信号要求:周期为20ms,高电平宽度为0.5-2.5ms

 

(这里的PWM波形其实是当作一个通信协议来使用的,把PWM当作一个通信协议是一个比较常见的应用) 

代码:

void PWM_Init(void) {

    // 开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	// 选择内部时钟
	TIM_InternalClockConfig(TIM2);

	// 配置时基单元
	TIM_TimeBaseInitTypeDef TimeBase_Initstructure;
	TimeBase_Initstructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TimeBase_Initstructure.TIM_CounterMode = TIM_CounterMode_Up;
	TimeBase_Initstructure.TIM_Period = 20000 - 1;
	TimeBase_Initstructure.TIM_Prescaler = 72 - 1;
	TimeBase_Initstructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TimeBase_Initstructure);
	
    // 配置输出比较单元
	TIM_OCInitTypeDef TIM_OCInitstructure;
	TIM_OCStructInit(&TIM_OCInitstructure);
	TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitstructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitstructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitstructure.TIM_Pulse = 0;
	TIM_OC2Init(TIM2,&TIM_OCInitstructure);
	
    // 配置GPIO,把PWM对应的GPIO口初始化为复用推挽输出
	GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Initstructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	
    // 运行控制
	TIM_Cmd(TIM2,ENABLE);
	
}

// 设置占空比
void Set_Compare2(uint16_t compare) {
	TIM_SetCompare2(TIM2,compare);
}

// 设置角度
void Set_Angle(float angle) {
	Set_Compare2(angle/180*2000+500);
}
输入捕获  IC 
  • 当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
  • 每个高级定时器和通用定时器都同时拥有4个输入捕获通道
  • 可配置为PWMI(PWM的输入模式)模式,同时测量频率和占空比
  • 可配合主从触发模式,实现硬件全自动测量
测量频率

  • 测频法(高频信号):在闸门时间T内,对上升沿/下降沿计次,得到N,则频率f_{x} = N / T
  • 测周法(低频信号):两个上升沿/下降沿内,以标准频率f_{c}计次,得到N,则频率 f_{x} = f_{c} / N
  • 中界频率: 测频法与测周法误差相等的频率点 f_{_{m}} =  \sqrt{f_{c} / T}
输入捕获通道

主从触发模式

(实现这三块,对应库函数中三个函数,调用函数,给个参数就行了) 

手册中主模式的解释(控制寄存器2)

从模式触发源的可选信号(从模式控制寄存器)

从模式选择(从模式控制寄存器)

输入捕获基本结构

这里使用了一个通道,只能测量频率 

(注:CNT的值是有上限的,ARR一般设置最大65535,CNT最大也只能计65535个数,如果信号频率太低,CNT计数值可能会溢出;从模式的触发源选择,只有TI1FP1和TI2FP2,没有TI3和TI4的信号,所以如果想使用从模式自动清零CNT,就只能用通道1和通道2,对于通道3和通道4,就只能开启捕获中断,在中断里手动清零)

PWMI基本结构

使用了两个通道,可同时测量周期和占空比 ,CCR1是一整个周期的计数值,CCR2是高电平期间的计数值,CCR2/CCR1就是占空比了

PWM输入模式时序

这里使用PA0引脚产生PWM(输出),再用PA6引脚进行输入捕获,所以用线连到PA0(TIM2)(输出,产生波形)和PA6(TIM3)(输入,测量波形频率或占空比) 

产生波形代码:

void PWM_Init(void) {

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	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);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // 1kHZ
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;  // 占空比
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

void SetTIM2_Compare1(uint16_t Compare) {  // 设置占空比

	TIM_SetCompare1(TIM2, Compare);
}

void SetTIM2_Prescaler(uint16_t Prescaler) {  // 改变频率

	TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Update);
}

输入捕获代码:

/* 输入捕获,捕获PA0的TIM2的通道1的频率和占空比*/ 

void IC_Init(void) {

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM3);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;  // 尽量设置大一些,防止计数溢出
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;  
	// 测频率的范围,给的标准频率是1Mhz,计数器最大只能计到65535
	// 所以所测量的最低频率是1M/65535   15HZ,如果频率再低,计数器就要溢出了
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
//	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
	
	
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	
	TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_GetFreq(void) {

	return 72000000 / (TIM_GetPrescaler(TIM3) + 1) / (TIM_GetCapture1(TIM3) + 1);
}

uint32_t IC_FetDuty(void) {

	return (TIM_GetCapture2(TIM3) + 1)*100 / (TIM_GetCapture1(TIM3) + 1);
}
编码器接口

对应手册14.3.12 编码器接口模式 

  • 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生正交信号脉冲,自动控制CNT自增自减,从而指示编码器的位置、旋转方向和旋转速度
  • 每个高级定时器和通用定时器都拥有1个编码器接口
  • 两个输入引脚借用了输入捕获的通道1和通道2

        使用编码器接口的好处就是节约软件资源,如果使用外部中断来计次,当电机高速旋转时,编码器每秒产生成千上万个脉冲,程序就得频繁进中断,进中断之后完成的任务只是简单的加1减1,软件资源就被这种简单又低级的工作给占用了,所以对于这种任务可以设计一个硬件电路模块来自动完成

正交编码器

当编码器的旋转轴转起来时,A相和B相就会输出这样的方波信号,转的越快这个方波的频率就越高,所以方波的频率就代表了速度,取出任意一相的信号来测量频率,就能知道旋转速度了,但是只有一相的信号。就无法测量旋转方向,因为无论是正转还是反转,都是这样的方波,所以要测量方向,还必须要有另一根线的辅助。

编码器的设计逻辑:首先把A相和B相的所有边沿作为计数器的计数时钟,出现边沿信号时,就计数自增或者自减,是增是减,由另一相的状态来确定,当出现某个边沿时,判断另一相的高低电平。(比如初始化后,CNT的初始值为0,编码器右转,CNT++,右转产生一个脉冲,CNT的值就加一次,比如右转后产生10个脉冲后停下来,那么这个过程CNT就由0自增到10停下来;编码器左转,CNT自减,左转产生一个脉冲,CNT的值就减一次,比如编码器再左转产生5个脉冲,那CNT就在原来10的基础上自减5停下来,所以编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟,他同时控制着CNT的计数时钟和计数方向,这样,CNT的值就代表了编码器的位置,如果每隔一段时间取一次CNT的值,再把CNT清零,那每次去取出来的值就表示了编码器的速度,(测频法测量正交脉冲的频率))

编码器接口在定时器的位置

编码器接口基本结构
工作模式

 

代码:

// TIM3 CH1 CH2
void Encoder_Init(void) {

	// 开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	// 配置引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置时基单元,预分频器不分频,只需要CNT执行计数即可
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65535;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 0;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	// 配置输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xf;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xf;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	// 配置编码器接口模式
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	
	// 启动定时器
	TIM_Cmd(TIM3, ENABLE);
	
}

uint16_t Encoder_Get(void) {

	int16_t temp = 0;
	temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return temp;
}

初始化完成后,CNT就会随着编码器旋转而自增自减,如果需要测量编码器的位置,直接读出CNT的值就行,如果需要测量编码器的速度和方向,则需每隔一端固定的闸门时间取出CNT的值,再把CNT的值清零。

void TIM2_IRQHandler(void) {

	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {
	
        // 1s取一次CNT的值
		Speed = Encoder_Get();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

(引脚上拉下拉的选择:看接在这个引脚的外部模块输出的默认电平,外部模块空闲默认输出高电平,选择上拉,默认输出高电平;外部模块空闲默认输出低电平,选择下拉,默认输出低电平;和外部模块保持默认状态一致,防止默认电平打架,一般来说,默认高电平,这是一个习惯的状态,上拉输入用的比较多) 

(说明:学习记录)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1047966.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NAS文件的名称或路径过长导致文件同步被挂起

将文件复制到群晖设备时遇到文件名长度限制问题&#xff0c;NTFS文件系统&#xff08;通过Samba等方式在群晖上使用&#xff09;: 在Windows系统上广泛使用的NTFS文件系统也支持较长的文件名&#xff0c;最大长度为255个字符。然而&#xff0c;要注意的是&#xff0c;使用Samba…

如何找回回收站删除的文件?文件恢复,3个方法!

“求助求助&#xff01;回收站里面删除的文件还能恢复吗&#xff1f;在清理电脑内存的时候一不小心把回收站清空了&#xff0c;现在不知道如何是好&#xff0c;请大家帮帮我&#xff01;” 电脑回收站里的文件清空了就是被永久删除了吗&#xff1f;如果误删了回收站里的文件还有…

成都优优聚是做美团餐饮代运营的吗?

成都优优聚公司是一家专注于美团代运营的企业&#xff0c;致力于为餐饮业主提供全方位的服务和解决方案。在如今的互联网时代&#xff0c;美团已经成为了许多餐饮业主不可或缺的平台之一&#xff0c;但是对于一些传统的餐饮业主来说&#xff0c;运营美团平台可能并不容易&#…

直播软件开发趋势揭秘:抓住行业热点实现爆发增长

直播软件开发者们正迎来一个前所未有的繁荣时期。随着社交媒体的普及和5G网络的迅猛发展&#xff0c;直播行业吸引了越来越多的用户&#xff0c;创造了巨大的商机。本文将揭示最新的直播软件开发趋势&#xff0c;帮助你抓住这个行业的热点&#xff0c;实现爆发性的增长。 关键…

【广州华锐互动】屠宰场生猪检疫VR模拟演练系统

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术在各个领域的应用越来越广泛。在教育领域&#xff0c;VR技术也为学生提供了更加真实和沉浸式的学习体验。屠宰场生猪检疫VR模拟演练系统由VR公司广州华锐互动所开发&#xff0c;作为一种新型的教学方式&a…

黑马VUE3视频笔记

目录 一、使用create-vue创建项目 二、setup选项 三、reactive和ref函数 1.reactive() 2.ref() 三、computed 四、watch ​五、生命周期函数 六、父传子、子传父 父传子defineProps 子传父defineEmits 七、模板引用 ref defineExpose 八、跨层传递普通数据 prov…

正交对角化,奇异值分解

与普通矩阵对角化不同的是&#xff0c;正交对角化是使用正交矩阵对角化&#xff0c;正交矩阵是每列向量都是单位向量&#xff0c;正交矩阵*它的转置就是单位矩阵 与普通矩阵对角化一样&#xff0c;正交对角化的结果也是由特征值组成的对角矩阵 本质还是特征向量对原矩阵的拉伸…

Go 里的超时控制

前言 日常开发中我们大概率会遇到超时控制的场景&#xff0c;比如一个批量耗时任务、网络请求等&#xff1b;一个良好的超时控制可以有效的避免一些问题&#xff08;比如 goroutine 泄露、资源不释放等&#xff09;。 Timer 在 go 中实现超时控制的方法非常简单&#xff0c;…

【3】贪心算法-最优装载问题-加勒比海盗

算法背景 在北美洲东南部&#xff0c;有一片神秘的海域&#xff0c;那里碧海蓝天、阳光 明媚&#xff0c;这正是传说中海盗最活跃的加勒比海&#xff08;Caribbean Sea&#xff09;。 有一天&#xff0c;海盗们截获了一艘装满各种各样古董的货船&#xff0c;每一 件古董都价值连…

python time和datetime的常用转换处理

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备好了&#xff0c;直接在文末名片自取就可 一、time 1、…

解决前端二进制流下载的文件(例如:excel)打不开的问题

1. 现在后端请求数据后&#xff0c;返回了一个二进制的数据&#xff0c;我们要把它下载下来。 这是响应的数据&#xff1a; 2. 这是调用接口的地方&#xff1a; uploadOk(){if(this.files.length 0){return this.$Message.warning("请选择上传文件&#xff01;&#xff…

2023-09-28 monetdb-databae的概念和作用-分析

摘要: 每个数据库对于db,schema以及user,role都有一套自己的设计, 不同数据库间对于相同名字的东西例如database和schema可以说南辕北辙, 例如mysql中schema其实是database的同义词. 本文分析monetdb的database的概念和作用 备份: https://stoneatom.yuque.com/staff-ft8n1u…

Android AMS——APP启动流程(三)

Android 应用启动方式主要有两种 , 冷启动和热启动。 冷启动:后台没有应用进程 , 需要先创建进程 , 然后启动 Activity ;热启动:后台有应用进程 , 不创建进程 , 直接启动 Activity ; 其实,还有一种温起动的方式,就是用户按了返回键退出应用,随后又从新启动,可是活…

JS三大运行时全面对比:Node.js vs Bun vs Deno

全文约 5100 字&#xff0c;预计阅读需要 15 分钟。 JavaScript 运行时是指执行 JavaScript 代码的环境。目前&#xff0c;JavaScript 生态中有三大运行时&#xff1a;Node.js、Bun、Deno。老牌运行时 Node.js 的霸主地位正受到 Deno 和 Bun 的挑战&#xff0c;下面就来看看这…

分析几道关于死锁的真题

以下四点是408中死锁这一节的内容&#xff0c;考频基本上为每年一道题&#xff0c;虽然一半以上的题目是关于银行家算法的不安全序列的送分题&#xff0c;但其中有几道题综合了这以下几个概念&#xff0c;如果现在不提前分析这几个概念之间的关系的话。可能考场上就是随便蒙一个…

华为云云耀云服务器L实例评测 | 实例使用教学之简单使用:通过命令行管理华为云云耀云服务器

华为云云耀云服务器L实例评测 &#xff5c; 实例使用教学之简单使用&#xff1a;通过命令行管理华为云云耀云服务器 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器是什么华为云云耀云服务…

postgresql|数据库|数据库测试工具pgbench之使用

前言&#xff1a; 数据库是项目中的重要组件&#xff0c;也是一个基础的重要组件&#xff0c;其地位说是第一我想应该是没有什么太多问题的。 那么&#xff0c;数据库的设计这些方面是不用多说的&#xff0c;关键的第一步&#xff0c;主要是涉及数据库的部署方式&#xff0c;…

系统集成|第十章(笔记)

目录 第十章 质量管理10.1 项目质量管理概论10.2 主要过程10.2.1 规划质量管理10.2.2 实施质量保证10.2.3 质量控制 10.3 常见问题 上篇&#xff1a;第九章、成本管理 下篇&#xff1a;第十一章、人力资源管理 第十章 质量管理 10.1 项目质量管理概论 质量管理&#xff1a;指确…

探索古彝文AI识别技术:助力中国传统文化的传承与发扬

目录 ⭐️ 写在前面 ⭐️ 一、什么是古彝文 1.1 古彝文介绍 1.2 古彝文与其他古文字示例 1.3 古彝文的重要性 ⭐️二、AI识别技术的挑战与前景 2.1 挑战 2.2 前景 ⭐️三、合合信息AI识别技术 3.1 智能文字识别技术&#x1f44d;&#x1f44d; 3.2 古文识别应用 ⭐…

基于微信小程序的高校暑期社会实践小程序设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…