一、定时器的寄存器
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 */