STM32定时器知识点及标准库使用指南
目录
一、STM32定时器分类
二、定时器核心概念
1. 计数模式
2. 时钟源
3. 主要寄存器
三、定时器基本结构
四、定时器工作原理
1. 基本定时功能
2. 输入捕获功能
五、定时器配置步骤
1.基本定时配置步骤:
2.输入捕获配置步骤:
六、标准库中使用定时器
1. 基本定时器使用步骤
2. 通用定时器实现PWM输出
3. 输入捕获功能
七、超声波测距中的定时器应用
1. 基本定时中断方式
2. 输入捕获方式
3.使用通用定时器的计数值直接读取
STM32系列微控制器中的定时器是非常强大的外设,可用于多种功能,如定时计数、PWM生成、输入捕获、正交解码等。下面我将详细介绍STM32定时器的相关知识及标准库使用方法。
一、STM32定时器分类
STM32定时器根据功能和复杂度可分为以下几类:

二、定时器核心概念
1. 计数模式
向上计数 :从0计数到自动重载值(TIMx_ARR),然后重新从0开始
向下计数 :从自动重载值计数到0,然后重新从自动重载值开始
中央对齐模式 :先向上计数到ARR,再向下计数到0,重复此过程
2. 时钟源
内部时钟(CK_INT):来自APB总线
外部时钟模式1:通过TIx引脚输入
外部时钟模式2:通过ETR引脚输入
内部触发输入(ITRx):来自其他定时器
3. 主要寄存器
TIMx_CR1/CR2 :控制寄存器
TIMx_PSC :预分频器
TIMx_ARR :自动重载寄存器
TIMx_CNT :计数器
TIMx_CCR1-4 :捕获/比较寄存器
TIMx_DIER :中断使能寄存器
TIMx_SR :状态寄存器
三、定时器基本结构
定时器的核心是一个计数器,其工作原理基于时钟源的驱动:
1. 时钟源 :通常来自 APB1 或 APB2 总线时钟
2. 预分频器 :将时钟源分频,降低计数频率
3. 计数器 :递增或递减计数
4. 自动重装载寄存器 :存储计数器的最大值
5. 捕获/比较通道 :用于输入捕获或输出比较
四、定时器工作原理
1. 基本定时功能
基本定时功能是定时器最基础的应用,通过以下步骤实现:
1. 配置时钟源 :选择内部时钟或外部时钟
2. 设置预分频器 :确定计数频率
3. 设置自动重装载值 :确定定时周期
4. 使能更新中断 :定时时间到达时触发中断
计算公式 :
计数频率 = 时钟源频率 / (预分频器值 + 1)
定时周期 = (自动重装载值 + 1) / 计数频率
2. 输入捕获功能
输入捕获用于测量外部信号的脉冲宽度或频率,工作原理:
1. 配置通道 :选择捕获通道和触发方式
2. 设置触发极性 :上升沿、下降沿或双边沿
3. 使能捕获中断 :捕获到信号时触发中断
4. 记录时间戳 :在中断中读取捕获寄存器的值
五、定时器配置步骤
1.基本定时配置步骤:
1. 使能定时器时钟
2. 配置时基结构(预分频器、自动重装载值等)
3. 配置中断(NVIC)
4. 使能更新中断
5. 启动定时器
2.输入捕获配置步骤:
1. 使能定时器和 GPIO 时钟
2. 配置 GPIO 为输入模式
3. 配置时基结构
4. 配置捕获通道(极性、滤波等)
5. 配置中断(NVIC)
6. 使能捕获中断
7. 启动定时器
六、标准库中使用定时器
1. 基本定时器使用步骤
以TIM6为例,实现基本定时功能:
#include "stm32f10x.h"
void TIM6_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 1. 使能定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
// 2. 配置定时器基本参数
// 计算方法:定时时间 = (PSC+1) * (ARR+1) / 时钟频率
// 例如:72MHz时钟,PSC=7199,ARR=9999,定时时间=1s
TIM_TimeBaseStructure.TIM_Period = 9999; // 自动重载值
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
// 3. 配置中断
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); // 使能更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 4. 启动定时器
TIM_Cmd(TIM6, ENABLE);
}
// 5. 中断服务函数
void TIM6_IRQHandler(void)
{
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
// 在这里执行定时任务
TIM_ClearITPendingBit(TIM6, TIM_IT_Update); // 清除中断标志位
}
}
2. 通用定时器实现PWM输出
以TIM3为例,实现PWM输出:
void TIM3_PWM_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 2. 配置GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // TIM3_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 配置定时器
TIM_TimeBaseStructure.TIM_Period = 999; // PWM周期 = (999+1) * (71+1)/72MHz = 1ms
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// 4. 配置PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 500; // 占空比50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); // 使能预装载寄存器
TIM_ARRPreloadConfig(TIM3, ENABLE); // 使能自动重载寄存器
// 5. 启动定时器
TIM_Cmd(TIM3, ENABLE);
}
// 更改占空比
void SetPWM_DutyCycle(uint16_t duty)
{
TIM_SetCompare1(TIM3, duty); // 设置比较值,范围0-999
}
3. 输入捕获功能
以TIM2为例,实现输入捕获测量信号频率:
volatile uint32_t CaptureValue = 0;
volatile uint32_t Frequency = 0;
void TIM2_InputCapture_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 2. 配置GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // TIM2_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 配置定时器
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 1MHz计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 4. 配置输入捕获
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿触发
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
// 5. 配置中断
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 6. 启动定时器
TIM_Cmd(TIM2, ENABLE);
}
// 中断服务函数
void TIM2_IRQHandler(void)
{
static uint32_t LastCaptureValue = 0;
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
CaptureValue = TIM_GetCapture1(TIM2);
if (CaptureValue > LastCaptureValue)
{
Frequency = 1000000 / (CaptureValue - LastCaptureValue); // 计算频率
}
else
{
Frequency = 1000000 / (0xFFFF - LastCaptureValue + CaptureValue);
}
LastCaptureValue = CaptureValue;
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
}
}
七、超声波测距中的定时器应用
1. 基本定时中断方式
原理 :
使用 TIM3 定时器,每 10 微秒触发一次中断
在中断中递增计数器,累计 Echo 信号的高电平持续时间
根据累计时间计算距离
uint16_t TimeCount;
// Trig PB15
// Echo PC15
void HC_SR04Init()
{
HC_SR04GPIO_Init();
HC_SR04TIM_Init();
}
float Sonar()
{
float Distance,Distance_mm;
uint32_t Time_end;
GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_SET); //Trig发送触发信号 >10us
Delay_us(15);
GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_RESET);
while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_15) == 0);
TimeCount = 0;
while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_15) == 1);
Time_end = TimeCount*10;
if (Time_end < 24000)
{
Distance = Time_end * 0.000001f * 340 / 2;
Distance_mm = Distance * 1000;
}
return Distance_mm;
}
void HC_SR04GPIO_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);
//Trig GPIO设置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//HC-SR04 超声波模块的工作电压通常为 5V
//开漏输出可通过外部上拉电阻(如 1kΩ)连接到 5V,使输出高电平为 5V,符合模块要求
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//下拉输入模式避免了信号干扰,确保了回波信号的准确检测
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_WriteBit(GPIOC,GPIO_Pin_15,Bit_RESET);
}
void HC_SR04TIM_Init()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
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 = 10 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
// - 预分频器:71(72-1),72MHz / 72 = 1MHz,即 1 微秒计数一次
// - 自动重装载值:9(10-1),每计数 10 次触发一次中断,即 10 微秒中断一次
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3,ENABLE);
}
void TIM3_IRQHandler()
{
if (TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)//触发中断
{
TimeCount++;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
}
2. 输入捕获方式
原理 :
使用 TIM2 定时器的输入捕获功能
捕获 Echo 信号的上升沿和下降沿
计算两个时间戳的差值,得到 Echo 信号的持续时间
根据时间差计算距离
#include "stm32f10x.h"
#include "delay.h"
// 定义引脚
#define TRIG_PORT GPIOB
#define TRIG_PIN GPIO_Pin_15
#define ECHO_PORT GPIOC
#define ECHO_PIN GPIO_Pin_15
// 定义定时器
#define TIMx TIM2
#define RCC_APB1Periph_TIMx RCC_APB1Periph_TIM2
// 全局变量
volatile uint32_t capture_start = 0;
volatile uint32_t capture_end = 0;
volatile uint8_t capture_complete = 0;
/**
* @brief 初始化GPIO和定时器
*/
void HC_SR04_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIMx, ENABLE);
// 配置Trig引脚
GPIO_InitStructure.GPIO_Pin = TRIG_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(TRIG_PORT, &GPIO_InitStructure);
GPIO_ResetBits(TRIG_PORT, TRIG_PIN);
// 配置Echo引脚
GPIO_InitStructure.GPIO_Pin = ECHO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(ECHO_PORT, &GPIO_InitStructure);
// 配置定时器
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 1MHz计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);
// 配置输入捕获
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIMx, &TIM_ICInitStructure);
// 配置NVIC
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能捕获中断
TIM_ITConfig(TIMx, TIM_IT_CC1, ENABLE);
// 启动定时器
TIM_Cmd(TIMx, ENABLE);
}
/**
* @brief 发送触发信号
*/
void HC_SR04_Trigger(void)
{
GPIO_SetBits(TRIG_PORT, TRIG_PIN);
delay_us(15);
GPIO_ResetBits(TRIG_PORT, TRIG_PIN);
}
/**
* @brief 获取测量距离(毫米)
*/
float HC_SR04_GetDistance(void)
{
float distance_mm = 0;
uint32_t time_us = 0;
// 发送触发信号
HC_SR04_Trigger();
// 等待捕获完成
while(capture_complete == 0);
capture_complete = 0;
// 计算时间差(微秒)
if(capture_end > capture_start)
{
time_us = capture_end - capture_start;
}
else
{
// 处理定时器溢出
time_us = (0xFFFF - capture_start) + capture_end;
}
// 计算距离(毫米):距离 = 时间 * 声速 / 2
// 声速约为340m/s = 0.34mm/us
if(time_us < 24000) // 限制最大测量时间
{
distance_mm = time_us * 0.34f / 2.0f;
}
return distance_mm;
}
/**
* @brief TIM2中断处理函数
*/
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIMx, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIMx, TIM_IT_CC1);
// 检测Echo引脚状态
if (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN))
{
// 上升沿,记录开始时间
capture_start = TIM_GetCapture1(TIMx);
}
else
{
// 下降沿,记录结束时间
capture_end = TIM_GetCapture1(TIMx);
capture_complete = 1;
}
}
}
/**
* @brief 主函数
*/
int main(void)
{
float distance_mm;
uint16_t distance_cm, distance_cmf;
// 系统初始化
SystemInit();
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 初始化超声波模块
HC_SR04_Init();
// 初始化OLED
OLED_Init();
OLED_ShowString(1, 1, "Length:");
OLED_ShowChar(1, 11, '.');
OLED_ShowString(1, 14, "cm");
while(1)
{
// 获取距离
distance_mm = HC_SR04_GetDistance();
// 转换为厘米和小数部分
distance_cm = (uint16_t)(distance_mm / 10);
distance_cmf = (uint16_t)(distance_mm) % 10;
// 显示距离
OLED_ShowNum(1, 8, distance_cm, 3);
OLED_ShowNum(1, 12, distance_cmf, 1);
// 延时
delay_ms(100);
}
}
3.使用通用定时器的计数值直接读取
原理:
使用SysTick计数器,直接读取计数器值计算时间差
#include "stm32f10x.h"
#include "delay.h"
// 定义引脚
#define TRIG_PORT GPIOB
#define TRIG_PIN GPIO_Pin_15
#define ECHO_PORT GPIOC
#define ECHO_PIN GPIO_Pin_15
/**
* @brief 初始化GPIO
*/
void HC_SR04_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
// 配置Trig引脚
GPIO_InitStructure.GPIO_Pin = TRIG_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(TRIG_PORT, &GPIO_InitStructure);
GPIO_ResetBits(TRIG_PORT, TRIG_PIN);
// 配置Echo引脚
GPIO_InitStructure.GPIO_Pin = ECHO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(ECHO_PORT, &GPIO_InitStructure);
}
/**
* @brief 获取测量距离(毫米)
*/
float HC_SR04_GetDistance(void)
{
float distance_mm = 0;
uint32_t start_time, end_time, time_us;
// 发送触发信号
GPIO_SetBits(TRIG_PORT, TRIG_PIN);
delay_us(15);
GPIO_ResetBits(TRIG_PORT, TRIG_PIN);
// 等待Echo引脚变为高电平
while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == 0);
// 记录开始时间(使用SysTick计数器)
start_time = SysTick->VAL;
// 等待Echo引脚变为低电平
while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == 1);
// 记录结束时间
end_time = SysTick->VAL;
// 计算时间差(微秒)
// 假设SystemCoreClock为72MHz,SysTick每计数一次为1/72us
if(end_time < start_time)
{
time_us = (start_time - end_time) / 72;
}
else
{
// 处理SysTick溢出
time_us = (0xFFFFFF - end_time + start_time) / 72;
}
// 计算距离(毫米)
if(time_us < 24000) // 限制最大测量时间
{
distance_mm = time_us * 0.34f / 2.0f;
}
return distance_mm;
}
/**
* @brief 主函数
*/
int main(void)
{
float distance_mm;
uint16_t distance_cm, distance_cmf;
// 系统初始化
SystemInit();
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 初始化GPIO
HC_SR04_GPIO_Init();
// 初始化OLED
OLED_Init();
OLED_ShowString(1, 1, "Length:");
OLED_ShowChar(1, 11, '.');
OLED_ShowString(1, 14, "cm");
while(1)
{
// 获取距离
distance_mm = HC_SR04_GetDistance();
// 转换为厘米和小数部分
distance_cm = (uint16_t)(distance_mm / 10);
distance_cmf = (uint16_t)(distance_mm) % 10;
// 显示距离
OLED_ShowNum(1, 8, distance_cm, 3);
OLED_ShowNum(1, 12, distance_cmf, 1);
// 延时
delay_ms(100);
}
}
定时器中断计数:实现简单,逻辑清晰但占用定时器中断资源,计时精度依赖中断处理速度
输入捕获:精度高,不占用主循环时间但配置稍复杂,需要额外定时器通道
SysTick直接计数:无需额外定时器,实现简单但精度可能受系统其他中断影响,SysTick可能被其他功能占用
本文地址:https://www.yitenyun.com/7118.html









