蓝桥杯嵌入式—定时器频率&占空比

一、定时器的寄存器

1.ARR(自动重装载值):相当于水杯的容量

2.CCRx(捕获/比较寄存器值):相当于水杯的刻度

3.CNT(计数器):相当于水滴

二、重要公式

Duty(占空比)=高电平时间(CCRx)/重装载值(ARR+1)

Frq(频率)=HCLK(设置的时钟频率)/预分频系数(PSC+)/重装载值(ARR+1)

PS:当CNT值小于CCRx时,通道输出1;相反,当CNT值大于CCRx时,通道输出0

三、引脚配置

将PB4和PA15配置为定时器2,3通道1

定时器2,3的通道1,2配置为输入捕获直接/间接模式

分配系数配置为79,通道1配置为上升沿,通道2配置为下降沿,NVIC勾上(定时器3同理)

PS:测频率只需要配置通道一为上升沿,测占空比则需要配置通道二为下降沿

将PA6 7配置为定时器16 17通道1

选择PWM Generration CH1模式

定时器16分频系数为8000-1,ARR为100-1。

定时器17分配系数为4000-1,ARR为100-1

这样子PA6的频率为100HZ,PA7为200HZ;ARR配置为100是因为好计算占空比。

PS:PWM没有用到中断所以可以不用开启

四、代码如下:


/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "stdio.h"
#include "string.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void LED_Proc(void);
void KEY_Proc(void);
void LCD_Proc(void);
/* USER CODE END PTD */


/* USER CODE BEGIN PM */
//LED
uint8_t Uled=0x00;

//LCD
char lcd_buff[32];
uint8_t lcd_shift=1;


//KEY
uint8_t key_val,key_up,key_down,key_old;


//TIME16 17 PWM生成
uint16_t PA6_Frq,PA7_Frq; 				//定时器16 17的频率
uint8_t PA6_Duty=10,PA7_Duty=10;	//定时器16 17的占空比	

//TIM2 3 输入捕获
uint32_t cap1,cap2,cap1_1,cap2_2; //定时器2 3的捕获值(1和2是上升沿   1_1和2_2是下降沿)
uint32_t R40_frq,R39_frq,R39_duty,R40_duty; //定时器2 3的频率 占空比


void SystemClock_Config(void);

int main(void)
{
  
  HAL_Init();



  
  SystemClock_Config();



 
  MX_GPIO_Init();
  MX_TIM16_Init();
  MX_TIM17_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	
	//输入捕获的中断开启 PA15(定时器2)和PB4(定时器3) 1通道捕获上升沿 2通道捕获下降沿
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
	
	//开启定时器16 17的PWM模式
	HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
	
	//计算定时器16 17的频率 公式(时钟频率/PSC/ARR)设置PA6为100HZ PA7为200HZ
	PA6_Frq = 80000000/8000/(TIM16->ARR+1);
	PA7_Frq = 80000000/4000/(TIM17->ARR+1);
	
	//将占空比的值装入CCRx(CCRx决定占空比值) 占空比公式(CCRx/ARR)
	TIM16->CCR1 = PA6_Duty;
	TIM17->CCR1 = PA7_Duty;
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	
    /* USER CODE BEGIN 3 */
		 LED_Proc();
		 KEY_Proc();
		 LCD_Proc();
  }
  /* USER CODE END 3 */
}


void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void LED_Proc(void)
{
	LED_Desplay(Uled);
}
void KEY_Proc(void)
{
	key_val = KEY_Scanf();
	key_down = key_val&(key_val^key_old);
	key_up = ~key_val&(key_val^key_old);
	key_old = key_val;
	
	if(key_down == 1)
	{
		Uled = 0x11;
	}
	
	if(key_down == 2)
	{
		PA6_Duty+=10;
		if(PA6_Duty==100)
		{
			PA6_Duty=10;
		}
		TIM16->CCR1 = PA6_Duty;
	}
	
	if(key_down == 3)
	{
		PA7_Duty+=10;
		if(PA7_Duty==100)
		{
			PA7_Duty=10;
		}
		TIM17->CCR1 = PA7_Duty;
	}
	
	if(key_down == 4)
	{
		TIM16 ->ARR =999;
		TIM17 ->ARR =999;
	}
}
void LCD_Proc(void)
{
	if(lcd_shift == 1)
	{
		sprintf(lcd_buff,"  TIM Frq And Duty  ");
		LCD_DisplayStringLine(Line1,(uint8_t *)lcd_buff);
		
		sprintf(lcd_buff,"  PA6_frq=%dHz      ",PA6_Frq);
		LCD_DisplayStringLine(Line2,(uint8_t *)lcd_buff);
		sprintf(lcd_buff,"  PA7_frq=%dHz  ",PA7_Frq);
		LCD_DisplayStringLine(Line3,(uint8_t *)lcd_buff);
		
		sprintf(lcd_buff,"  R39_frq=%dHz      ",R39_frq);
		LCD_DisplayStringLine(Line4,(uint8_t *)lcd_buff);
		sprintf(lcd_buff,"  R40_frq=%dHz      ",R40_frq);
		LCD_DisplayStringLine(Line5,(uint8_t *)lcd_buff);
		
		sprintf(lcd_buff,"  PA6_duty=%d%%     ",PA6_Duty);
		LCD_DisplayStringLine(Line6,(uint8_t *)lcd_buff);
		sprintf(lcd_buff,"  PA7_duty=%d%%     ",PA7_Duty);
		LCD_DisplayStringLine(Line7,(uint8_t *)lcd_buff);

		sprintf(lcd_buff,"  R39_duty=%d%%      ",R39_duty);
		LCD_DisplayStringLine(Line8,(uint8_t *)lcd_buff);
		sprintf(lcd_buff,"  R40_duty=%d%%      ",R40_duty);
		LCD_DisplayStringLine(Line9,(uint8_t *)lcd_buff);
		
	}
}

/*
程序逻辑:通过开启定时器2 3的输入捕获,通道1捕获上升沿,通道2捕获下降沿,然后要把计数值清零
					定时器2的频率为时钟频率/预分频*获取到的上升沿数(CCR的值)
					定时器2的占空比为获取到下降沿的值/上升沿的值(一个周期的高电平时间/一个周期的总时间)
					然后要重新开启一下定时器2 3的输入捕获中断

					PA15(定时器2)和PB4(定时器3)采取的是555信号发生器的频率,本程序可以接到PA6和PA7的
					引脚上来采样定时器16 17的占空比和频率
*/

//输入捕获的中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	//定时器2产生中断
	if(htim->Instance == TIM2)
	{
		//定时器2的通道一产生中断
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
		{
			//获取上升沿的值
			cap1 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
			//获取下降沿的值
			cap1_1 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2);
			//清空计数器
			TIM2->CNT = 0;
			
			//PA15 定时器2
			//计算频率
			R40_frq = 80000000/(80*cap1);
			//计算占空比
			R40_duty = (1.0*cap1_1)/(1.0*cap1)*100;
			//重新开启输入捕获中断
			HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
			HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
		}
	}
	
	if(htim->Instance == TIM3)
	{
		if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			cap2 = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);
			cap2_2 = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_2);
			TIM3->CNT = 0;
			R39_frq = 80000000/(80*cap2);
			R39_duty = (1.0*cap2_2)/(1.0*cap2)*100;
			HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
			HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
		}
	}
}
/* USER CODE END 4 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值