硬件开发板:STM32G0B1RET6
软件平台:cubemax+keil+VScode
1 新建cubemax工程
1.1 配置系统时钟RCC

1.2 配置定时器
1.2.1 配置输入捕获
选择通用定时器TIM2-Channel 1为输入捕获引脚,对应IO口是PA0,时钟源选择内部时钟源Internal clock,工作模式选择直接输入捕获Input Capture direct mode,预分频系数选择63,定时器向上计数,重装载值选择最大值,减少溢出次数;输入捕获选择上升沿直接触发。
 
使能中断
 
1.2.2 配置PWM输出
选择通用定时器TIM3-Channel 1为PWM输出引脚,对应IO口是PA6,时钟源选择内部时钟源Internal clock,工作模式选择PWM输出PWM Generation CH1,预分频系数选择63,定时器向上计数,重装载值选择999,此时对应产生的PWM信号周期是 T = 64 ∗ 1000 64 M = 1 m s ; 频率为 1 K H z T=\frac{64*1000}{64M}=1ms;频率为1KHz T=64M64∗1000=1ms;频率为1KHz,占空比设置为100,即高电平所占总周期的10%
 
1.3 配置串口

2 代码
2.1 printf重定向
在usart.h中添加头文件和函数声明
# include "stdio.h"int fgetc(FILE *f);
int fputc(int ch,FILE *f);
在usart.c中重定向
//重定向scanf
int fgetc(FILE *f)
{uint8_t ch=0;HAL_UART_Receive(&huart2,&ch,1,0xffff);return ch;
}//重定向printf
int fputc(int ch,FILE *f)
{uint8_t temp[1]={ch};HAL_UART_Transmit(&huart2,temp,1,2);return ch;
}
由于该实验并未使用到scanf函数,可不必重定向scanf
2.2 定义变量
uint32_t capture_value[3];    /*定义数组变量,存放捕获到的值*/
uint32_t diff_value1;    /*计数差值*/
uint32_t diff_value2;    /*计数差值*/uint8_t capture_state=0;    /*捕获状态:0表示未开始捕获;1表示完成一次捕获;2表示完成两次捕获*/
uint8_t capture_flag=0;    /*捕获标志位:0表示未完成,1表示已完成*/
2.3 中断回调函数
/* USER CODE BEGIN 4 */
//回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if (htim==&htim2){switch (capture_state){case 0:{capture_value[0]=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);    /*读取捕获开始时间*/__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);    /*切换为下降沿捕获*/capture_state=1;    /*标志完成第一次捕获*/}break;case 1:{capture_value[1]=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);    /*读取第二次捕获时间*/__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);    /*切换为上升沿捕获*/capture_state=2;    /*标志完成第二次捕获*/}break;case 2:{capture_value[2]=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);    /*读取捕获结束时间*/HAL_TIM_IC_Stop_IT(htim,TIM_CHANNEL_1);    /*停止捕获*/capture_state=0;    /*标志完成第三次捕获,重新置0,准备下一轮捕获*/capture_flag=1;    /*标志捕获完成*/}break;default:printf("running error!\n");break;}}}
/* USER CODE END 4 */
2.4 main函数
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();MX_TIM3_Init();MX_USART2_UART_Init();/* USER CODE BEGIN 2 */HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);    /*开启PWM输出*/HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);    /*开启输入捕获*//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if (capture_flag==1)    /* 捕获完成 */{printf("\n******capture start******\n");if (capture_value[2] >= capture_value[0])    /* 计时没有溢出 */{diff_value1=capture_value[2]-capture_value[0];    /* 取差值 */}else    /* 计时有溢出 */{diff_value1=(0xffffffff+1)+capture_value[2]-capture_value[0];    /* 取差值 */}printf("周期:%.2fms\n",diff_value1/1000.0);    /*周期=差值*单次计数时间*/printf("频率:%.2fKHz\n",1000.0/diff_value1);if (capture_value[1] >= capture_value[0])    /* 计时没有溢出 */{diff_value2=capture_value[1]-capture_value[0];    /* 取差值 */}else    /* 计时有溢出 */{diff_value2=(0xffffffff+1)+capture_value[1]-capture_value[0];    /* 取差值 */}printf("高电平:%.2fms\n",diff_value2/1000.0);    /*高电平时间=差值*单次计数时间*/printf("占空比:%d%%\n",diff_value2*100/diff_value1);printf("******capture over******\n");capture_flag=0;    /*清除标志位,准备下一轮捕获*/HAL_Delay(1000);HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);    /*开启下一轮捕获*/}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
周期计算公式: T = 计数差值 ∗ 单次计数时间 = 计数差值 ∗ 1 计数频率 = 计数差值 ∗ 1 时钟频率 / 预分频系数 = 计数差值 ∗ 预分频系数 时钟频率 T=计数差值*单次计数时间=计数差值*\frac{1}{计数频率}=计数差值*\frac{1}{时钟频率/预分频系数}=计数差值*\frac{预分频系数}{时钟频率} T=计数差值∗单次计数时间=计数差值∗计数频率1=计数差值∗时钟频率/预分频系数1=计数差值∗时钟频率预分频系数
 比如该实验中,时钟频率为64MHz,预分频系数为63(64分频),得到的计数频率为1MHz,即单次计数时间为1us
3 实验现象
用杜邦线连接PA0和PA6引脚,打开串口,观察打印情况
 