32定时器&定时&输出比较&输入捕获&编码器接口

目录

目录

一.定时器简介

1.基本定时器

2.通用定时器

3.高级定时器

4.定时器基本结构

​编辑​编辑 5.计数器时序

 5.时钟树

二.定时器定时

代码实现

<1>显示屏自动计时

(1)跨文件使用变量

(2) 将中断函数放在主函数里面

<2>对射式红外计数

三.定时器输出比较

一.输出比较简介

二.PWM波形

三.输出模式控制器的工作原理

四.外部设备

五.PWM相关函数

六.代码实现

四.定时器输入捕获

一.简介

二.频率测量

三.电路结构

四.主从触发模式

五.对应相关函数​编辑

六.代码实现

五.定时器的编码器接口

代码实现



一.定时器简介

1.基本定时器

2.通用定时器

滤波器可以滤掉信号的抖动和干扰,其工作原理:在一个固定的时钟频率f下进行采样,如果连续n隔采样点都为相同的电平,那就代表输入的信号稳定了。如果采样值不全都相同,那就说明信号有抖动,这时就保证上一次的输出,或者直接输出低电平也行,这样就能保证输出信号在一定程度上的滤波,采样频率f和采样点数N都时滤波器的参数

频率越低,采样点数越多,滤波效果就越好,信号延迟就越大

采样频率f可以由内部时钟分频而来,由参数ClockDivision决定

3.高级定时器

4.定时器基本结构

上图对应函数

 5.计数器时序

 5.时钟树

二.定时器定时

代码实现

<1>显示屏自动计时

(1)跨文件使用变量

timer.c

#include "stm32f10x.h"                  // Device header
extern uint16_t Num;//告诉编译器,在其他地方已经定义了Num的值,自己去找
void Timer_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	/*选择时钟函数*/
	TIM_InternalClockConfig(TIM2);//也可以不写,因为定时器上电以后默认就是内部时钟
	/*配置时基单元*/
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=10000-1;//周期,就是ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0
    
    TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进入中断
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断,更新中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}
void TIM2_IRQHandler(void)
{
	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
	{
		Num++;	
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "Timer.h" 
uint16_t Num;
int main()
{
	OLED_Init();
	OLED_ShowString(1,1,"NUM:");
	Timer_Init();

	while(1)
	{
		OLED_ShowNum(1,5,Num,3);
        OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5);


		
	}	
}
(2) 将中断函数放在主函数里面

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "Timer.h" 
uint16_t Num;
int main()
{
	OLED_Init();
	OLED_ShowString(1,1,"NUM:");
	Timer_Init();

	while(1)
	{
		OLED_ShowNum(1,5,Num,3);
		OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5);

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

 Timer.c

#include "stm32f10x.h"                  // Device header
extern uint16_t Num;//告诉编译器,在其他地方已经定义了Num的值,自己去找
void Timer_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	/*选择时钟函数*/
	TIM_InternalClockConfig(TIM2);//也可以不写,因为定时器上电以后默认就是内部时钟
	/*配置时基单元*/
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=10000-1;//周期,就是ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进入中断
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断,更新中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}

//void TIM2_IRQHandler(void)
//{
//	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
//	{
//		
//		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
//	}
//}

<2>对射式红外计数

Timer.c

#include "stm32f10x.h"                  // Device header
extern uint16_t Num;//告诉编译器,在其他地方已经定义了Num的值,自己去找
void Timer_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*初始化GPIO*/
	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);
	/*选择时钟函数*/
	//第二个参数:外部触发预分频器;第三:外部触发极性(上升或下降触发);第四:外部触发滤波器(这里启动滤波防止CNT计数时发生跳变)
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0f);
	/*配置时基单元*/
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=10-1;//周期,就是ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚初始化完就进入中断
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断,更新中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}
uint16_t Count(void)//返回计数器的值
{
	return TIM_GetCounter(TIM2);
}

//void TIM2_IRQHandler(void)
//{
//	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
//	{
//		
//		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
//	}
//}

main.c 

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "Timer.h" 
uint16_t Num;
int main()
{
	OLED_Init();
	OLED_ShowString(1,1,"NUM:");
	OLED_ShowString(2,1,"CNT:");
	Timer_Init();

	while(1)
	{
		OLED_ShowNum(1,5,Num,3);
		OLED_ShowNum(2,5,Count(),5);

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

当外部输入信号功率很小,而IO内部的上拉电阻可能会影响到输入信号,可以使用浮空输入来防止影响外部输入的电平

三.定时器输出比较

一.输出比较简介

IC(input Capture)输入捕获

CC(Capture/Compare)输入捕获和输出比较单元,当使用输入捕获时就是捕获寄存器,当使用输出比较时就是比较寄存器

二.PWM波形

PWM是数字输出信号

惯性,举例LED在熄灭的时候,由于余晖和人眼视觉暂留现象,LED不会立马熄灭而会过一小段时间才会熄灭,电机同理

参数:

频率:1/Ts,Ts代表一个高低电平变换周期的时间,频率越快,等效模拟的信号就越平稳,性能开销就越大

占空比:一次高电平/一个高低电平变换周期的时间,决定了PWM等效出来的模拟电压的大小

分辨率:如1%,2%,3%......步距为1%,就是占空比变化的精细程度

三.输出模式控制器的工作原理

四.外部设备

五.PWM相关函数

六.代码实现

1.

该结构体的部分参数是在高级定时器才会用到,但最好用函数将其所有的参数全部初始化,便于后期使用高级定时器。

2.ARR,PSC,CCR共同决定PWM的周期和占空比

3.

4.

(1)LED呼吸灯

PWM.c

#include "stm32f10x.h"                  // Device header
void PWM_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	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_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=100-1;//周期,就是ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0
	
	TIM_OCStructInit(&TIM_OCInitStructure);//初始化结构体所有参数,防止修改报错
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性,High极性不翻转,Low极性翻转
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能
	TIM_OCInitStructure.TIM_Pulse=0;//CCR
	
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}
void PWM_CCR(uint16_t CCR_count)
{
	TIM_SetCompare1(TIM2,CCR_count);//单独更改通道1的CCR值
	
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "PWM.h" 
uint16_t i;
int main()
{
	OLED_Init();
	PWM_Init();
	while(1)
	{
		for(i=0;i<=100;i++)
		{
			PWM_CCR(i);
			Delay_ms(10);
		}
		for(;i>0;i--)
		{
			PWM_CCR(i);
			Delay_ms(10);
		}

		
	}	
}
	

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

将TIM2_CH1通道重映射到PA15IO

 PWM.c

#include "stm32f10x.h"                  // Device header
void PWM_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	/*选择时钟函数*/
	TIM_InternalClockConfig(TIM2);//也可以不写,因为定时器上电以后默认就是内部时钟
	/*配置时基单元*/
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=100-1;//周期,就是ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0
	
	TIM_OCStructInit(&TIM_OCInitStructure);//初始化结构体所有参数,防止修改报错
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性,High极性不翻转,Low极性翻转
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能
	TIM_OCInitStructure.TIM_Pulse=0;//CCR
	
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}
void PWM_CCR(uint16_t CCR_count)
{
	TIM_SetCompare1(TIM2,CCR_count);//单独更改通道1的CCR值
	
}

(2)舵机

PWM.c

#include "stm32f10x.h"                  // Device header
void PWM_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	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_InternalClockConfig(TIM2);//也可以不写,因为定时器上电以后默认就是内部时钟
	/*配置时基单元*/
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=20000-1;//周期,就是ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0
	
	TIM_OCStructInit(&TIM_OCInitStructure);//初始化结构体所有参数,防止修改报错
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性,High极性不翻转,Low极性翻转
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能
	TIM_OCInitStructure.TIM_Pulse=0;//CCR
	
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}
void PWM_CCR(uint16_t CCR_count)
{
	TIM_SetCompare2(TIM2,CCR_count);//单独更改通道2的CCR值
	
}

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"
float Angle;
void Servo_Init()
{
	PWM_Init();
}
void Servo_Angle(float Angle)
{
	PWM_CCR(Angle*2000/180+500);
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "Servo.h" 
#include "Key.h" 
uint8_t num;
float angle;
int main()
{
	OLED_Init();
	Servo_Init();
	Key_Init();
	OLED_ShowString(1,1,"Angle:");
	

	while(1)
	{
		num=Keynum();
		if(num==1)
		{
			angle+=30;
			if(angle>180)
			{
				angle=0;
				
			}
			Servo_Angle(angle);
			OLED_ShowNum(1,7,angle,3);
		}
	}	
}
	

主函数中的变量定义不要与模块中的变量定义一样

四.定时器输入捕获

一.简介

PWMI模式是专门为PWM频率和占空比设计的

二.频率测量

在一秒时间出现周期的个数就是频率

测频法适合测量高频信号,测量结果更新得慢一些(取决闸门时间),数值相对稳定,平滑,自带均值滤波,如果在闸门时间内波形频率有变化,得到的其实是闸门时间的平均频率

测周法适合测量低频信号,测量结果更新得快一些(取决与待测信号的频率),数据跳变也快,由于只测量一个周期,结果值受噪声的影响,波动较大

两种测量方法都存在正负1误差,N越大,正负1误差的影响就越小

频率>Fm:用测频法;频率<Fm:用测周法

三.电路结构

四.主从触发模式

可以用于定时器的级联

五.对应相关函数

PSC决定了测周法的标准频率,即72M/预分频=计数标准频率

六.代码实现

IC.c

#include "stm32f10x.h"                  // Device header
void IC_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	TIM_ICInitTypeDef TIM_ICInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	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_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,这里不进行分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=65536-1;//周期,就是ARR自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,高级定时器才有
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//为将初始化的值由缓冲寄存器写入,会立刻更新一个中断,所以下面的计数会从1开始而不是0

	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//选择通道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_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
	
	TIM_Cmd(TIM3,ENABLE);
}

uint32_t Get_Freq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3)+1);//这里由于频率在CCR计数到1000时信号跳变没有记上,100000/999=1001.01.
}

 这里由于频率在CCR计数到1000时信号跳变没有记上,100000/999=1001.01.

也可以理解成计数是从0-999计数到1000个数

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "PWM.h" 
#include "IC.h" 

int main()
{
	OLED_Init();
	PWM_Init();
	IC_Init();
	OLED_ShowString(1,1,"Freq:00000HZ");
//	PWM_SetPrescaler(720-1);
//	PWM_CCR(50);
	while(1)
	{
		OLED_ShowNum(1,6,Get_Freq(),5);
	
		
	}	
}
	

 

注:

头文件的防止重复定义的名称不能写错

 用户\main.c(11):警告:#223-D:函数“IC_Init”隐式声明

随着待测频率的增大,误差也会逐渐增大 

正负1误差频率=1/计数值

根据误差上限,可以得出对于计数频率1MHz ,误差为千分之一,那么测量低于误差的上限为1000000/1000=1000Hz,也就是说超出这个测量上限就会导致误差过大,所以,想要增大测量频率上限可以减少PSC,提高标准频率

以上是对于测周法,而对于高频,一般用测频法

在实际测量的时候,还会存在晶振误差

五.定时器的编码器接口

 定时器上的编码器接口,相当于一个带有方向的控制的外部时钟,同时控制CNT的计数时钟和计数方向,可以通过每隔一段时间取出CNT的值,来实现编码器的旋转方向和速度的测量

CH3和CH4不能接编码器

取其中的一路测量频率就可以获得电机转动的速度

相比于单独设置一个输出方向的信号,正交信号的精度更高,A,B相都可以进行计次,计次的频率更高,而且正交信号可以抗噪声

由上图可以看出,最终编码器的输入引脚就是定时器的CH1和CH2这两个引脚

CH3和CH4与编码器接口无关

计数器的自增和自减受编码器的控制

正转向上计数

反转向下计数

两个引脚都不进行反向(即两个接口对信号的上升沿和下降沿都有效)

 定时器编码器接口配置

上拉,下拉和浮空输入模式选择原理

根据外设的默认输出来进行选择,如果外部默认输出高电平,那么就选择上拉输入模式

如果外部默认输出低电平,那么就选择下拉输入模式

防止输出和输入电平引起冲突

如果外设输出功率低,则设置为浮空模式

代码实现

Encoder.c

#include "stm32f10x.h"                  // Device header
void Encoder_Init(void)
{
	TIM_ICInitTypeDef TIM_ICInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//上拉模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //不分频
	
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//选择通道1
	TIM_ICInitStructure.TIM_ICFilter=0xF;//选择滤波强度,滤波器计次并不会改变信号的原有频率
//	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Falling;//上升沿触发
	TIM_ICInit(TIM3,&TIM_ICInitStructure);

	TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//选择通道1
	TIM_ICInitStructure.TIM_ICFilter=0xF;//选择滤波强度,滤波器计次并不会改变信号的原有频率
//	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿触发
	TIM_ICInit(TIM3,&TIM_ICInitStructure);
	
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
																	//配置编码器模式以及两个输入通道是否反相
																	//注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
																	//此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置
	TIM_Cmd(TIM3,ENABLE);
}
int16_t Encoder_Speed()
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3,0);
	return Temp;
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "Timer.h" 
#include "Encoder.h" 
int16_t Speed;
int main()
{
	OLED_Init();
	Encoder_Init();
	OLED_ShowString(1,1,"Speed:");
	Timer_Init();

	while(1)
	{
		OLED_ShowSignedNum(1,7,Speed,3);

	}	
}
void TIM2_IRQHandler(void)
{
	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
	{
		Speed=Encoder_Speed();	
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值