STM32学习笔记五——TIM定时器

TIM定时中断

TIM简介

在这里插入图片描述

定时器的类型

在这里插入图片描述

基本定时器

在这里插入图片描述

通用定时器

在这里插入图片描述

高级定时器

在这里插入图片描述

定时中断的基本结构

在这里插入图片描述

通用计时器的时序

可以参考STM32参考文档的14通用定时器(TIMx) 部分。

预分频器时序

在这里插入图片描述

计数器时序

在这里插入图片描述

计数器无预装时序(无缓冲寄存器)

在这里插入图片描述

计数器有预装时序(有缓存寄存器)

在这里插入图片描述

RCC时钟树

STM32中用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统。
三种不同的时钟源可被用来驱动系统时钟(SYSCLK):
● HSI振荡器时钟
● HSE振荡器时钟
● PLL时钟
这些设备有以下2种二级时钟源:
● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/
待机模式下自动唤醒系统。
● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。
当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。
在这里插入图片描述
1.当HSI被用于作为PLL时钟的输入时,系统时钟能得到的最大频率是64MHz。
2.对于内部和外部时钟源的特性,请参考相应产品数据手册中“电气特性”章节。
用户可通过多个预分频器配置AHB、高速APB(APB2)和低速APB(APB1)域的频率。AHB和
APB2域的最大频率是72MHz。APB1域的最大允许频率是36MHz。SDIO接口的时钟频率固定
为HCLK/2。
RCC通过AHB时钟(HCLK)8分频后作为Cortex系统定时器(SysTick)的外部时钟。通过对SysTick
控制与状态寄存器的设置,可选择上述时钟或Cortex(HCLK)时钟作为SysTick时钟。ADC时钟
由高速APB2时钟经2、4、6或8分频后获得。
定时器时钟频率分配由硬件按以下2种情况自动设置:

  1. 如果相应的APB预分频系数是1,定时器的时钟频率与所在APB总线频率一致。
  2. 否则,定时器的时钟频率被设为与其相连的APB总线频率的2倍。

具体可参考STM32参考手册6.3 RCC寄存器描述部分

定时器定时中断

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:OLED显示屏上显示“Num:”,每秒自动加一。
main.c文件

#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:");
	
	while(1)
	{
		OLED_ShowNum (1,5,Num,5);
//		OLED_ShowNum (2,5,TIM_GetCounter (TIM2),5);
		//获取TIMx计数器的值:TIM_GetCounter
	}
}

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

Timer.c文件

#include "stm32f10x.h"                  // Device header

//extern uint16_t Num;

void Timer_Init(void )
{
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM2 ,ENABLE );
	//TIM2是APB1总线的外设
	
	//配置TIMx内部时钟
	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 = 10000 - 1;//指定下一次更新事件中将被载入到激活的自动重载寄存器的周期值。
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//指定用于分频TIM时钟的预分频器值。
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//指定重复计数器值
	
	//根据TIM_TimeBaseInitStruct中指定的参数,初始化TIMx时间基准单元外设。
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	//清除TIMx的挂起标志位。
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	
	//使能或失能指定的TIM中断
	TIM_ITConfig(TIM2 ,TIM_IT_Update ,ENABLE);
	
	//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 = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	//使能或失能指定的TIM外设
	TIM_Cmd(TIM2, ENABLE);
}

//中断函数
/*
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Num ++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

Timer.h文件

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

定时器外部时钟

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:对射式红外传感器遮挡后移开,CNT加一,CNT加到9后,再加一,CNT清零,Num的值为一。
main.c文件

#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);
//		OLED_ShowNum (2,5,TIM_GetCounter (TIM2),5);
		//获取TIMx计数器的值:TIM_GetCounter
	}
}

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

Timer.c文件

#include "stm32f10x.h"                  // Device header

//extern uint16_t Num;

void Timer_Init(void )
{
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM2 ,ENABLE );
	//TIM2是APB1总线的外设
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	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);
	
	//配置外部时钟模式2。
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0F);
	//指定要配置的定时器实例,这里是TIM2
	//TIM_ExtTRGPSC_OFF:表示禁用定时器的外部时钟源
	//TIM_ExtTRGPolarity_NonInverted:表示定时器的输出极性为非反相。
	//0x00:表示定时器的分频值,这里设置为0。
	
	//配置时基单元
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	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时钟的预分频器值。
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//指定重复计数器值
	
	//根据TIM_TimeBaseInitStruct中指定的参数,初始化TIMx时间基准单元外设。
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	//清除TIMx的挂起标志位。
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	
	//使能或失能指定的TIM中断
	TIM_ITConfig(TIM2 ,TIM_IT_Update ,ENABLE);
	
	//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 = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	//使能或失能指定的TIM外设
	TIM_Cmd(TIM2, ENABLE);
}

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

//中断函数
/*
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Num ++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

Timer.h文件

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);
uint16_t Timer_GetCounter(void);

#endif

TIM输出比较

输出比较简介

在这里插入图片描述

PWM简介

在这里插入图片描述

输出比较通道(通用)

在这里插入图片描述

输出比较通道(高级)

仅做了解
在这里插入图片描述

输出比较模式

在这里插入图片描述

PWM基本结构

在这里插入图片描述

PWM参数计算

在这里插入图片描述

舵机

舵机简介

在这里插入图片描述

硬件电路

在这里插入图片描述

直流电机

直流电机及驱动简介

在这里插入图片描述

硬件电路

在这里插入图片描述

PWM驱动LED呼吸灯

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:PA0端口上的LED呈现呼吸灯的效果。
main.c文件

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

uint8_t i;

int main (void)
{
	OLED_Init ();
	PWM_Init ();
	
	while(1)
	{
		for (i=0;i<=100;i++)
		{
			PWM_SetCompare1 (i);
			Delay_ms(10);
		}
		for (i=0;i<=100;i++)
		{
			PWM_SetCompare1 (100-i);
			Delay_ms(10);
		}
	}
}

PWM.c文件

#include "stm32f10x.h"                  // Device header

void PWM_Init(void )
{
    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_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;     //GPIO_Pinn_15
	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;  //ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;    //PSC
	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;    //CCR
	
	TIM_OC1Init(TIM2 ,&TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2 ,Compare );
}

PWM.h文件

#ifndef __PWM_H
#define __PWM_H

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

#endif

PWM驱动舵机

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:按下按键,舵机输出轴的角度变化,OLED显示当前的角度。
main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"

uint8_t KeyNum;
float Angle;

int main (void)
{
	OLED_Init ();
	Servo_Init ();
	Key_Init();
	
	OLED_ShowString (1,1,"Angle:");
	
	while(1)
	{
		KeyNum =Key_GetNum ();
		if (KeyNum == 1)
		{
			Angle +=30;
			if (Angle >180)
			{
				Angle =0;
			}
		}
		Servo_SetAngle(Angle );
		OLED_ShowNum (1,7,Angle ,3);
	}
}

Servo.c文件

#include "stm32f10x.h"                  // Device header
#include "PWM.h"

void Servo_Init(void )
{
	PWM_Init ();
}

void Servo_SetAngle(float Angle)
{
	PWM_SetCompare2 (Angle /180*2000 + 500);
}

Servo.h文件

#ifndef __SERVO_H
#define __SERVO_H

void Servo_Init(void );
void Servo_SetAngle(float Angle);

#endif

PWM驱动直流电机

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:按下按键,电机转动,再按一下按键,速度增加,增加到最大,再按下按键,点击反向全速选择,之后速度减少;OLED显示当前的速度值。
main.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"

uint8_t KeyNum;
int8_t Speed;

int main (void)
{
	OLED_Init ();
	Motor_Init();
	Key_Init();
	
	OLED_ShowString (1,1,"Speed:");
	
	while(1)
	{
		KeyNum = Key_GetNum();
		if (KeyNum == 1)
		{
			Speed +=20;
			if (Speed >100)
			{
				Speed=-100;
			}
		}	
		Motor_SetSpeed(Speed);
		OLED_ShowSignedNum (1,7,Speed ,3);
	}
}

Motor.c文件

#include "stm32f10x.h"                  // Device header
#include "PWM.h"

void Motor_Init(void )
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
	GPIO_Init(GPIOA ,&GPIO_InitStructure );
	
	PWM_Init ();
}

void Motor_SetSpeed(int8_t Speed)
{
	if (Speed >=0)
	{
		GPIO_SetBits(GPIOA ,GPIO_Pin_4);
		GPIO_ResetBits(GPIOA ,GPIO_Pin_5);
		PWM_SetCompare3(Speed ); 
	}
	else 
	{
		GPIO_ResetBits(GPIOA ,GPIO_Pin_4);
		GPIO_SetBits(GPIOA ,GPIO_Pin_5);
		PWM_SetCompare3(-Speed ); 
	}
}

Motor.h文件

#ifndef __MOTOR_H
#define __MOTOR_H

void Motor_Init(void);
void Motor_SetSpeed(int8_t Speed);

#endif

TIM输入捕获

输入捕获简介

在这里插入图片描述

频率测量

在这里插入图片描述

输入捕获通道

在这里插入图片描述

主从触发模式

在这里插入图片描述

输入捕获基本结构

在这里插入图片描述

PWMI结构

在这里插入图片描述

输入捕获模式测频率

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:OLED屏幕上显示“Freq:01000Hz”。
main.c文件

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

int main (void)
{
	OLED_Init();
	PWM_Init();
	IC_Init();
	
	OLED_ShowString(1, 1, "Freq:00000Hz");
	
	PWM_SetPrescaler(720 - 1);			//Freq = 72M / (PSC + 1) / 100
	PWM_SetCompare1(50);				//Duty = CCR / 100
	
	while (1)
	{
		OLED_ShowNum(1, 6, IC_GetFreq(), 5);
	}
}


PWM.c文件

#include "stm32f10x.h"                  // Device header

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;  //ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;    //PSC
	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;    //CCR
	
	TIM_OC1Init(TIM2 ,&TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2 ,Compare );
}

void PWM_SetPrescaler(uint16_t Prescaler)
{
	//配置 TIMx 预分频器
	TIM_PrescalerConfig(TIM2 ,Prescaler ,TIM_PSCReloadMode_Immediate);
}

PWM.h文件

#ifndef __PWM_H
#define __PWM_H

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

#endif

IC.c文件

#include "stm32f10x.h"                  // Device header

void IC_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_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;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//设置TIM IC通道为TIM_Channel_1,即选择TIM3定时器的通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;//设置TIM IC的输入捕获过滤器为0xF,这意味着当输入信号的上升沿或下降沿被检测到时,TIM IC将产生中断
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//设置TIM IC的中断极性为上升沿触发,这意味着当输入信号的上升沿被检测到时,TIM IC将产生中断
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//设置TIM IC的输入捕获预分频器为1,这意味着输入信号的上升沿或下降沿每过1个TIM时钟周期,TIM IC就会产生一次中断
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//设置TIM IC的输入捕获选择为直接TI模式,这意味着TIM IC将在每个输入通道上独立地产生中断
	//初始化TIM3定时器的TIM IC
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	//选择TIM3定时器的通道1作为输入触发源,并设置触发源的预分频值为1
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	//将TIM3定时器设置为从模式,并使能定时器
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	
	//使能TIM3定时器的时钟
	TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_GetFreq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}

IC.h文件

#ifndef __IC_H
#define __IC_H

void IC_Init(void);
uint32_t IC_GetFreq(void);

#endif

PWMI模式(PWM输入模式)测频率和占空比

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:OLED屏幕第一行显示“Freq:01000Hz”,第二行显示“Duty:50%”。
main.c文件

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

int main (void)
{
	OLED_Init();
	PWM_Init();
	IC_Init();
	
	OLED_ShowString(1, 1, "Freq:00000Hz");
	OLED_ShowString(2, 1, "Duty:00%");
	
	PWM_SetPrescaler(720 - 1);			//Freq = 72M / (PSC + 1) / 100
	PWM_SetCompare1(50);				//Duty = CCR / 100
	
	while (1)
	{
		OLED_ShowNum(1, 6, IC_GetFreq(), 5);
		OLED_ShowNum(2, 6, IC_GetDuty(), 2);
	}
}


IC.c文件

#include "stm32f10x.h"                  // Device header

void IC_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_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;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//设置TIM IC通道为TIM_Channel_1,即选择TIM3定时器的通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;//设置TIM IC的输入捕获过滤器为0xF,这意味着当输入信号的上升沿或下降沿被检测到时,TIM IC将产生中断
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//设置TIM IC的中断极性为上升沿触发,这意味着当输入信号的上升沿被检测到时,TIM IC将产生中断
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//设置TIM IC的输入捕获预分频器为1,这意味着输入信号的上升沿或下降沿每过1个TIM时钟周期,TIM IC就会产生一次中断
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//设置TIM IC的输入捕获选择为直接TI模式,这意味着TIM IC将在每个输入通道上独立地产生中断
	//初始化TIM3定时器的TIM IC
	/*
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;//设置TIM IC通道为TIM_Channel_2,即选择TIM3定时器的通道2
	TIM_ICInitStructure.TIM_ICFilter = 0xF;//设置TIM IC的输入捕获过滤器为0xF,这意味着当输入信号的上升沿或下降沿被检测到时,TIM IC将产生中断
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;//设置TIM IC的中断极性为下降沿触发,这意味着当输入信号的下降沿被检测到时,TIM IC将产生中断
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//设置TIM IC的输入捕获预分频器为1,这意味着输入信号的上升沿或下降沿每过1个TIM时钟周期,TIM IC就会产生一次中断
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;//设置TIM IC的输入捕获选择为交叉TI模式
	//初始化TIM3定时器的TIM IC
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	*/
	TIM_PWMIConfig(TIM3 ,&TIM_ICInitStructure );

	
	//选择TIM3定时器的通道1作为输入触发源,并设置触发源的预分频值为1
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	//将TIM3定时器设置为从模式,并使能定时器
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	
	//使能TIM3定时器的时钟
	TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_GetFreq(void)
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}

uint32_t IC_GetDuty(void)
{
	return (TIM_GetCapture2(TIM3)+1)*100 / (TIM_GetCapture1(TIM3)+1);
}

IC.h文件

#ifndef __IC_H
#define __IC_H

void IC_Init(void);
uint32_t IC_GetFreq(void);
uint32_t IC_GetDuty(void);

#endif

TIM编码器接口

编码器接口简介

在这里插入图片描述

正交编码器

在这里插入图片描述

编码器接口基本结构

在这里插入图片描述

工作模式

在这里插入图片描述

实例(均不反相)

在这里插入图片描述

实例(TI1反相)

在这里插入图片描述

编码器接口测速

第一步:新建工程

第二步:连接线路

第三步:编写程序

实验现象:自动对编码器进行计次,从而得到旋转编码器的速度。向右慢速旋转旋转编码器,OLED显示屏上显示的数值为正,计次比较小;向右快速旋转,计次就会增大;向左旋转,计次数值为负。
main.c文件

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

int16_t Speed;

int main (void)
{
	OLED_Init ();
	Timer_Init ();
	Encoder_Init ();

	OLED_ShowString (1,1,"Speed:");
	
	while(1)
	{
	    OLED_ShowSignedNum (1,7,Speed ,5);
	}
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Speed = Encoder_Get ();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

Encoder.c文件

#include "stm32f10x.h"                  // Device header

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);
		
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	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 = 1 - 1;		//PSC
	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_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_ICStructInit (&TIM_ICInitStructure );
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);

	//配置 TIMx 编码器接口。
	TIM_EncoderInterfaceConfig(TIM3 ,TIM_EncoderMode_TI12 ,TIM_ICPolarity_Rising ,TIM_ICPolarity_Rising );
	/*
	用来配置TIM3定时器的编码器接口的。
	TIM_EncoderMode_TI12:这是编码器的模式,表示使用TI12模式。在这种模式下,编码器接口会在每个输入捕获事件发生时更新一个计数器,
	       这个计数器的值会被用来对定时器的溢出时间进行“取模”运算,从而产生一个PWM占空比的值。
	TIM_ICPolarity_Rising:这是输入捕获极性,表示当输入信号的上升沿或下降沿被检测到时,TIM IC将产生中断。
	TIM_ICPolarity_Rising:这是输入捕获极性,表示当输入信号的上升沿或下降沿被检测到时,TIM IC将产生中断。
	*/
	
	TIM_Cmd (TIM3 ,ENABLE );
}

int16_t Encoder_Get(void )
{
	int16_t Temp;
	Temp = TIM_GetCounter (TIM3 );
	TIM_SetCounter (TIM3 ,0);
	return Temp ;
}

Encoder.h文件

#ifndef __ENCODER_H
#define __ENCODER_H

void Encoder_Init(void );
int16_t Encoder_Get(void );

#endif

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值