4-定时器-TIMER

248 阅读8分钟

理论

预分频寄存器(TIMx_PSC):由于时钟源为:72MHz,T = 1/f = 1/72MHz,由于不好计算周期时间,则需要分频,若分72则T = 1/1MHz = 1us(1MHz = 一百万秒)

计数方式:向上(递增到某个数触发中断)、向下(递减到某一个数触发中断)、中心计数(递增到某一个数触发中断,再递减到某一个数触发中断)

比较值(参考:链接):

    PWM1模式:若计数值小于有效值则高电平,计数值大于有效值则低电平,可以控制比较值来调节占空比

    PWM2模式:与PWM1模式相反,计数值小于有效值则低电平,大于有效值则高电平

复用:Pin脚本身除了支持普通GPIO功能之外,还支持别的功能(使用别的功能就叫复用)

重映射:Pin脚本身不支持这些功能,配置重映射寄存器,使其具备别的功能

定时器分类

型号:STM32F103ZET6

基本定时器:TIM6、TIM7

基本定时器功能

通用定时器:TIM2~TIM5

通用定时器功能

高级定时器:TIM1、TIM8

高级定时器功能

代码编写

定时器中断实验:LED灯一秒闪烁一次、LED灯两秒闪烁一次、计算单片机运行时间、串口5秒返回单片机运行时间

PWM信号输出:呼吸灯、电机(由慢到快)、舵机

输入捕获:检测信号脉冲宽度(舵机脉冲宽度)

LED灯、UART、定时器、PWM配置

LED灯配置请看:链接

串口配置请看:链接

配置定时器:

72/7200 = 0.01,T = 1/f = 1/0.01MHz = 100us,计数10000,触发中断,100us * 10000 = 1s,1s = 1000000us,但单片机都是以0开始,所以分频值以及计数值都 -1

定时器配置

配置定时器向上计数溢出中断NVIC(嵌套向量中断控制器)

配置定时器NVIC

定时器(PWM)控制LED灯配置

LED(PB5)引脚说明:

PWMLED灯配置

所以配置定时器3,通道二,但配置完发现图中不符,需手动修改

定时器配置LED灯

定时器(PWM)控制电机配置

配置PB4引脚PWM控制电机速度

配置PWM控制电机速度

定时器(PWM)控制舵机配置

舵机脉冲周期:20ms

PWM控制舵机配置

输入捕获定时器配置

输入捕获定时器配置 输入捕获定时器配置

配置定时器全局中断NVIC

开启中断

DHT11(温湿度传感器)配置

DHT11(温湿度传感器)配置

LED灯闪烁、串口输出运行时间

LED1每隔一秒电平翻转一次,LED2每隔两秒电平翻转一次,串口输出单片机运行时间

Cube IDE代码

main.c

/* USER CODE BEGIN Includes */
#include <stdio.h>	//27行
#include <string.h>	//28行
/* USER CODE END Includes */

/* USER CODE BEGIN 0 */
uint32_t G_Timer_Count = 0;	//59行
uint8_t UART_Count[200];	
uint8_t UART_Flag = 0;
/* USER CODE END 0 */

/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim1);	//开启定时器,97行
/* USER CODE END 2 */

if(UART_Flag)	//104行
{
	sprintf(UART_Count,"MCU run time is %lus",G_Timer_Count);
	HAL_UART_Transmit(&huart1, UART_Count, strlen(UART_Count), 1000);
	UART_Flag = 0;	//打印一次后标志=0,等中断五次(5s)后
}

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)	//定时器触发函数,157行
{
	if(htim == &htim1)
	{
		HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		G_Timer_Count++;
		if((G_Timer_Count % 5) == 0)
			UART_Flag = 1;	//每隔五秒,让标志=1
		if((G_Timer_Count % 2) == 0)	//LED2每隔两秒翻转电平
			HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
	}

}
/* USER CODE END 4 */

PWM信号LED呼吸灯、电机、舵机

理论参考:链接

PWM信号控制LED,产生一个呼吸灯效果,以及对电机控制,控制速度由慢到快

Cube IDE代码

main.c

/* USER CODE BEGIN PV */
uint8_t PWM_Value = 0,LED_PWM_Value = 0,SG_PWM = 5;	//47行
/* USER CODE END PV */

/* USER CODE BEGIN 2 */
//参数1:定时器句柄(指向配置好的定时器结构体的指针),参数2:定时器通道,93行
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);	//开启定时器3,通道2 PWM
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);	//开启定时器3,通道1 PWM
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);	//开启定时器4,通道1 PWM
/* USER CODE END 2 */

//103行
PWM_Value++;
PWM_Value = PWM_Value % 200;
if(PWM_Value > 99)
	LED_PWM_Value = 200 - PWM_Value;	//大于99时,从大到小(100,99...)
else
	LED_PWM_Value = PWM_Value;
HAL_Delay(25);
//参数1:定时器句柄,参数2:定时器通道,参数3:比较值
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, LED_PWM_Value);	//设置LED比较值
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, LED_PWM_Value);	//设置电机比较值

if(PWM_Value % 30 == 0)
{
	//每0.1ms计数值+1则0.5ms,比较值模式1,则占空比(高电平)0.5ms
	SG_PWM += 5;
	if(SG_PWM > 25)
		SG_PWM = 5;
	__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, SG_PWM);	//设置舵机比较值
}

输入捕获(IC)

捕获高电平持续时间

Cube IDE代码

捕获PWM高电平的时间

main.c

/* USER CODE BEGIN PTD */
uint32_t ic_state=0,period_count=0,ic_count=0,us_count;	//32行
/* USER CODE END PTD */

/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);	//开启普通定时器中断
  HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);	//开启捕获定时器中断
  printf("Please connect MCU51 P2.0,and let SG90 run to detect signal!\n");	//串口输出捕获的时间(记得配置串口重定向)
/* USER CODE END 2 */

if(ic_state== 2 )	//103行(while里)
{
	/* 始终设置的是1us触发计数值加1
	* 一个周期大概65ms,若大于65只有捕获中断函数不好使
	* 若period_count为1,则代表过了一个中断周期,时间(1*65535)us
	* 若没有到整个中断周期时间则剩下的为:ic_count
	* 所以两个相加等于整个高电平时间*/
	us_count = ic_count + period_count * 0xFFFF;
	printf("High level duration:  %ldus \n",us_count);	//(float)(us_count)/1000.000
	ic_state = 0;	//再将中间键恢复0,方便下次上升沿触发中断计时
}

/* USER CODE BEGIN 4 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)	//输入捕获触发函数,161行
{
	if(TIM2 == htim->Instance)
	{
		if ( ic_state == 0 )
		{
			__HAL_TIM_SET_COUNTER(htim,0);	//将定时器从零开始计时
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);		//设置成下降沿触发
			ic_state = 1;	//下次触发中断时(下降沿)则运行else
			period_count = 0;
			ic_count = 0;
		}
		else
		{
			ic_count = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2);	//读取定时器计数值
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2,   TIM_INPUTCHANNELPOLARITY_RISING);	//设置成上降沿触发
			ic_state = 2;	//进入while里面的判断
		}
	}
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)	//普通定时器中断触发函数
{
    if(TIM2 == htim->Instance)
    {
		if(ic_state==1)
		{
			if(period_count==0XFFFF)	//一次周期大约65ms,若进入这个需要(65*65535)ms
			{
				ic_state=2;
				ic_count=0XFFFF;	//返回一个超大数显示错误
			}
			else
				period_count++;
		}
    }
}
/* USER CODE END 4 */

DHT11

main.c

/* USER CODE BEGIN Includes */
#include "dht11.h"	//27行
/* USER CODE END Includes */

if(DHT_Read())	//while里,101行
	printf(" H:%u  T:%u \r\n",Data[0],Data[2]);
HAL_Delay(1000);

dht11.c

#include "stm32f1xx.h"

#include "dht11.h"

uint8_t Data[5]={0x00,0x00,0x00,0x00,0x00};
		
void Delay_us(uint16_t us)	//微秒延迟
{
	uint16_t differ = 0xffff-us;
	__HAL_TIM_SET_COUNTER(&htim1,differ);
	HAL_TIM_Base_Start(&htim1);
	
	while(differ < 0xffff){
		differ = __HAL_TIM_GET_COUNTER(&htim1);
	}
	HAL_TIM_Base_Stop(&htim1);
}


void DHT_GPIO_SET_OUTPUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin=GPIO_PIN_5;
	GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;	//PA5设置输出
//	GPIO_InitStructure.Pull=;
	GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void DHT_GPIO_SET_INPUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin=GPIO_PIN_5;
	GPIO_InitStructure.Mode=GPIO_MODE_INPUT;	//PA5设置输入
	GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}

uint8_t DHT_Read_Byte(void)
{
	 uint8_t ReadData=0;
	 uint8_t temp;
	 uint8_t retry=0;
	 uint8_t i;    
	 for(i=0; i<8; i++)
	 {
			while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0 && retry<100)  

			{
					Delay_us(1);
				  retry++;
			}
			retry=0;
			Delay_us(40);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1)   temp=1;
			 else   temp=0;

			 while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1 && retry<100)
			 {
				 Delay_us(1);
				 retry++;
			 }
			 retry=0;
			 
			 ReadData<<=1;
			 ReadData |= temp;
	 }

		return ReadData;
}

uint8_t DHT_Read(void)
{
	 uint8_t retry=0;
	 uint8_t i;
		
	 DHT_GPIO_SET_OUTPUT();
	 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
	 HAL_Delay(18);
	 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
	 Delay_us(20);
	

	DHT_GPIO_SET_INPUT();
	Delay_us(20);
	if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0)
	{

		while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==0 && retry<100)  
		{
		   Delay_us(1);
			 retry++;
		}
		retry=0;
		while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)==1 && retry<100) 
		{
		   Delay_us(1);
			 retry++;
		}
		retry=0;
		

		for(i=0; i<5; i++)
		{
			 Data[i] = DHT_Read_Byte();
		}
		Delay_us(50);

	}
	
	 uint32_t sum=Data[0]+Data[1]+Data[2]+Data[3];
	 if((sum)==Data[4])    return 1;  
	   else   return 0;
	
}

dht11.h

#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f1xx_hal.h"
#include "stm32f1xx.h"

extern uint8_t Data[5];

extern TIM_HandleTypeDef htim1;
void Delay_us(uint16_t us);
void DHT_GPIO_SET_OUTPUT(void);
void DHT_GPIO_SET_INPUT(void);
uint8_t DHT_Read_Byte(void);
uint8_t DHT_Read(void);

#endif