http://www.z-linear.com
前言
大家好,我是ZLinear的硬件工程师。
在电子工程的世界里,有一个元件无处不在,却常常被人们忽视------定时器。从LED闪烁到电机调速,从ADC采样触发到PWM信号生成,从按键去抖到系统看门狗,几乎所有嵌入式系统都离不开定时器的参与。
如果说CPU是系统的大脑,那么定时器就是系统的心脏,它精确地控制着每一个时间节拍,让各个模块按部就班地协同工作。
今天,我们就从经典的555定时器芯片 开始,一路深入到STM32微控制器的定时器外设 ,并结合 ZLinear系列数据采集卡 (DABL_G511、DABL7606/7689)的实战设计,深度拆解定时器电路的基本原理、工作模式、硬件设计和应用实现。
一、定时器的本质:时间的主宰者
定时器的核心功能其实非常简单:对稳定的时钟脉冲进行计数。
- 当计数值达到预设的阈值时,触发一个事件(中断、输出翻转、启动ADC等)
- 通过预分频器调整计数时钟的速度,实现不同时间量程的定时
- 通过自动重载寄存器实现周期性的定时输出
从《电子工程师自学速成:设计篇》中的描述可以看出:
定时器/计数器就像单片机的内部时钟或计数器,可以根据需要将它设为定时器或计数器。如果要求CPU在一段时间(如5ms)后执行某段程序,可让定时器/计数器工作在定时状态,定时器/计数器开始计时,当计到5ms后马上产生一个请求信号送到中断控制器。
分类维度:
- 按实现方式:分立元件定时器(555)、模拟定时器、数字定时器(MCU内部定时器)、软件定时器(RTOS)
- 按功能:基本定时器(仅定时中断)、通用定时器(PWM/输入捕获)、高级定时器(死区补偿/互补输出)
- 按工作模式:单稳态、无稳态、双稳态
二、经典555定时器:历经50年的传奇
2.1 555芯片的内部结构
根据《手绘揭秘基本功能电路》和《不可不知的36种电子元器件(第2版)》的描述,555定时器的内部构成框图如下:
555定时器内部包含23个晶体管、2个二极管和16个电阻。三个5kΩ电阻(正是"555"名称的由来)组成分压网络,为两个电压比较器提供2/3Vcc和1/3Vcc两个基准电压。两个电压比较器的输出分别作为R-S触发器的置"0"信号和置"1"信号。
从《电子电路图识图技巧(升级版)》的表5-26中,我们可以得到NE555的功能表:
| 复位RST(4) | 阈值THR(6) | 触发TRI(2) | 放电DIS(7) | 输出OUT(3) |
|---|---|---|---|---|
| 0 | × | × | 导通 | 0 |
| 1 | <2/3Vcc | <1/3Vcc | 截止 | 1 |
| 1 | <2/3Vcc | >1/3Vcc | 保持 | 保持 |
| 1 | >2/3Vcc | <1/3Vcc | 导通 | 0 |
| 1 | >2/3Vcc | >1/3Vcc | 导通* | 0* |
*注:属于违背锁存器约束条件的情况。
2.2 三种经典工作模式
1)单稳态模式(Monostable)------定时器
根据《手绘揭秘基本功能电路》第1.4.1节和《电子电路图识图技巧(升级版)》图5-63:
单稳态触发器有一个稳定状态和一个暂稳态。当在2脚输入一个负触发脉冲时,输出跳变为高电平并进入暂稳态。暂稳态的持续时间由外接RC网络决定:tw = 1.1R×C,与Vcc无关。
Vcc (+5~+15v)
│
├─┐
│ R1
│ ├──┐
│ │ │8 4
│ │ │
│ C1 │ 555 3 ── 单稳态脉冲输出
│ │ │
│ └──┤2
└────┤6
│
C2 0.01μF
│
GND
应用场景:按键去抖、延时开关、脉冲展宽。
从《门老师教你学电子:电子电路识图》图2-143的"自动延时关灯电路"可以看到,555单稳态模式下,按一下SB,照明灯EL亮,延时约25s后自动关灯。
2)无稳态模式(Astable)------振荡器
根据《手绘揭秘基本功能电路》第1.4.2节:
2脚和6脚相连,每个时序周期电路都会对自己进行触发,可作为振荡器使用。C1通过R1和R2充电,通过R2放电。C1的电压变化范围为1/3Vcc~2/3Vcc。
关键公式:
- 充电时间:t₁ = 0.693×(R1+R2)×C1
- 放电时间:t₂ = 0.693×R2×C1
- 振荡频率:f = 1.44 / (R1+2R2)×C1
应用场景:LED闪烁、蜂鸣器驱动、时钟脉冲源。
从《手绘揭秘基本功能电路》第1.4.15节的"玩具风琴"电路可见,通过切换不同的C值(0.001μF~22μF)配合R1=100kΩ,可以产生从523Hz到56336Hz的不同音调。
3)双稳态模式(Bistable)------触发器
根据《电子电路图识图技巧(升级版)》图5-159和图5-160:
双稳态触发器有两个稳定状态。当在2脚输入负触发脉冲时,输出翻转为高电平并保持(置位);当在6脚输入正触发脉冲时,输出翻转为低电平并保持(复位)。C1和R1、C2和R2分别组成置"1"和置"0"的触发微分电路。
应用场景:按键控制开关、记忆电路。
2.3 555芯片的技术参数
根据《手绘揭秘基本功能电路》第1.3节的555芯片说明:
| 参数 | 最小值 | 典型值 | 最大值 | 单位 |
|---|---|---|---|---|
| 供电电压(Vcc) | 4.5 | - | 15 | V |
| 供电电流(Vcc=+5V) | - | 3~6 | - | mA |
| 供电电流(Vcc=+15V) | - | 10~15 | - | mA |
| 输出电流(最大值) | - | - | 200 | mA |
| 功耗 | - | - | 600 | mW |
| 工作温度 | 0 | - | 70 | °C |
注:显示的值适用于NE555芯片。
三、STM32定时器:从基本到高级的强大武器
当我们需要更精确、更复杂、更可编程的定时功能时,MCU内部的定时器外设就成了不二之选。以STM32F407为例,它拥有多达14个定时器:
3.1 STM32定时器分类
从《STM32F407 探索者开发指南V1.3》第21章和《STM32F4xx参考手册_V4》第14~17章中,可以得到定时器分类表:
| 类型 | 实例 | 计数器位数 | 计数模式 | 最大预分频 | 独立通道 | 特殊功能 |
|---|---|---|---|---|---|---|
| 基本定时器 | TIM6, TIM7 | 16 | 递增 | 1~65536 | 0 | 触发DAC |
| 通用定时器 | TIM2~TIM5 | 16/32 | 递增/递减/中心对齐 | 1~65536 | 4 | PWM, 输入捕获, 编码器 |
| 通用定时器 | TIM9~TIM14 | 16 | 递增/递减/中心对齐 | 1~65536 | 2 | PWM, 输入捕获 |
| 高级定时器 | TIM1, TIM8 | 16 | 递增/递减/中心对齐 | 1~65536 | 4+3 | 死区插入, 互补输出, 刹车输入 |
注:TIM2和TIM5是32位计数器(从STM32F3/F4系列开始),其他通用定时器为16位。
3.2 基本定时器:最简单的定时中断
根据《STM32F407 探索者开发指南V1.3》第20章和《STM32F4xx参考手册_V4》第17章:
基本定时器框图:
APB1时钟 → 倍频器(×1或×2) → PSC预分频器 → CNT计数器 → 更新事件
│
(当CNT=ARR时)
定时时间计算:
定时时间(秒) = (PSC+1) × (ARR+1) / 定时器时钟频率
// 例如:APB1时钟=42MHz, 实际定时器时钟=84MHz(×2倍频)
// PSC=8399, ARR=4999
// 则:8400 × 5000 / 84,000,000 = 0.5秒 = 500ms
配置代码(取自《STM32F407 探索者开发指南V1.3》):
TIM_HandleTypeDef tim6_handle;
tim6_handle.Instance = TIM6;
tim6_handle.Init.Prescaler = 8399; // 预分频系数
tim6_handle.Init.Period = 4999; // 自动重载值
tim6_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_Base_Init(&tim6_handle);
// 使能更新中断并启动定时器
HAL_TIM_Base_Start_IT(&tim6_handle);
// 中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == (&tim6_handle))
{
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); // LED1每500ms翻转
}
}
3.3 通用定时器:PWM输出
从《STM32F407 探索者开发指南V1.3》第21.3节:
PWM工作原理:
当CNT < CCRx时,IO输出低电平;当CNT >= CCRx时,IO输出高电平;当CNT=ARR时,定时器溢出,CNT归零重新递增。改变CCRx的值可以改变PWM占空比,改变ARR可以改变PWM频率。
在DABL_G511/DABL7689系列数据采集卡中,PWM输出是核心功能之一:
// TIM1_CH1 PWM输出配置(PA8)
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // 连接到TIM1
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// TIM1初始化
tim1_handle.Instance = TIM1;
tim1_handle.Init.Prescaler = 83; // 84MHz/(83+1)=1MHz
tim1_handle.Init.Period = 999; // 1kHz PWM
tim1_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
tim1_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&tim1_handle);
// 配置PWM通道
TIM_OC_InitTypeDef sConfigOC;
sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
sConfigOC.Pulse = 500; // 初始占空比50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&tim1_handle, &sConfigOC, TIM_CHANNEL_1);
// 启动PWM输出
HAL_TIM_PWM_Start(&tim1_handle, TIM_CHANNEL_1);
3.4 通用定时器:输入捕获
参考《STM32F407 探索者开发指南V1.3》第21.4节和《STM32Cube高效开发教程》第10章:
输入捕获原理:
定时器检测通道引脚上的边沿跳变。当检测到有效沿时,计数器CNT的当前值被锁存到捕获/比较寄存器CCRx中,并产生捕获中断。通过两次捕获的差值,可以计算出脉冲的周期或脉宽。
在ZLinear采集卡中,编码器位置测量正是利用输入捕获原理实现的:
编码器A相 → PA6(TIM3_CH1)
编码器B相 → PA7(TIM3_CH2)
// 定时器编码器模式配置
TIM_Encoder_InitTypeDef sEncoderConfig;
sEncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12; // T1和T2双沿
sEncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sEncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sEncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sEncoderConfig.IC1Filter = 0;
// ... IC2同理
HAL_TIM_Encoder_Init(&tim3_handle, &sEncoderConfig);
// 启动编码器接口
HAL_TIM_Encoder_Start(&tim3_handle, TIM_CHANNEL_ALL);
// 读取位置
int16_t position = __HAL_TIM_GET_COUNTER(&tim3_handle);
3.5 高级定时器:死区插入与互补输出
从《STM32F4xx参考手册_V4(中文版)》第14章:
高级控制定时器(TIM1和TIM8)具有带死区插入的互补输出功能。死区时间是指在两个互补输出之间插入的一个短暂的延迟,防止桥式驱动电路中的上下桥臂同时导通(直通)而烧毁功率管。
在DABM-D223等电机控制采集卡中,这一功能被用于驱动H桥电路:
TIM_BreakDeadTimeConfigTypeDef sBreakConfig;
sBreakConfig.OffStateRunMode = TIM_OSSR_ENABLE;
sBreakConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
sBreakConfig.LockLevel = TIM_LOCKLEVEL_1;
sBreakConfig.DeadTime = 100; // 死区时间(取决于TIMx_CR1的CKD位)
sBreakConfig.BreakState = TIM_BREAK_ENABLE;
sBreakConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
HAL_TIMEx_ConfigBreakDeadTime(&tim8_handle, &sBreakConfig);
四、产品实战:ZLinear系列采集卡的定时器电路设计
4.1 系统级定时器需求分析
以DABL_G511/DABL7689数据采集卡为例,其定时器需求可以概括如下:
| 功能模块 | 所需定时器资源 | 工作模式 | 典型参数 |
|---|---|---|---|
| ADC采样触发 | TIM2 | 输出比较/触发 | 20μs~1s(50kHz~1Hz) |
| PWM输出 | TIM1 | PWM生成 | 1Hz~100kHz,占空比0.1%~100% |
| 编码器测速 | TIM3 | 编码器接口 | 最高1MHz输入频率 |
| DI脉冲计数 | TIM4 | 外部时钟模式 | 最高1MHz计数频率 |
| 系统时基 | TIM6 | 基本定时器 | 1ms定时中断 |
| DAC更新触发 | TIM7 | 触发DAC转换 | 与ADC采样同步 |
| RTOS系统滴答 | TIM5或SysTick | 周期性定时 | 1kHz(RT-Thread默认) |
4.2 ADC采样触发定时器设计
在数据采集卡中,ADC采样的精确时序控制至关重要。根据《DABL7689核心代码解析》:
// TIM2配置:ADC采样触发
TIM_HandleTypeDef htim2;
htim2.Instance = TIM2;
htim2.Init.Prescaler = 84 - 1; // 84MHz/84 = 1MHz
htim2.Init.Period = 20 - 1; // 1MHz/20 = 50kHz采样率
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_Base_Init(&htim2);
// 配置TIM2触发ADC
TIM_MasterConfigTypeDef sMasterConfig;
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; // 更新事件触发
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
这种设计使得ADC转换与定时器事件完全同步,无需CPU干预,实现了"硬件触发采样"------每个定时器更新事件自动启动一次ADC转换,DMA自动将结果搬运到缓存。
4.3 脉冲计数器设计(DI输入)
根据《DABL-G511.docx》和用户手册,DABL_G511支持8路数字量输入,其中部分通道可配置为高速脉冲计数:
外部信号 → 限流/防浪涌 → 高速光耦隔离 → MCU定时器输入
│
外部时钟模式1(TI1/TI2)
硬件连接:
DI_1(PD0) → (光耦隔离后) → TIM4_CH1(PD12,通过AF2)
DI_2(PD1) → (光耦隔离后) → TIM4_CH2(PD13,通过AF2)
配置代码:
// TIM4外部时钟模式1配置
TIM_SlaveConfigTypeDef sSlaveConfig;
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; // 外部时钟模式1
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1; // TI1FP1作为输入
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
sSlaveConfig.TriggerFilter = 0;
HAL_TIM_SlaveConfigSynchronization(&htim4, &sSlaveConfig);
4.4 FreeRTOS/RT-Thread系统时基
根据《FreeRTOS开发指南_V1.12.pdf》和DABL_G511的实际代码分析:
// FreeRTOS运行时间统计时基
uint32_t FreeRTOSRunTimeTicks;
void ConfigureTimeForRunTimeStats(void)
{
FreeRTOSRunTimeTicks = 0; // 节拍计数器初始化为0
btim_tim3_int_init(10-1, 720-1); // 初始化TIM3
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == (&g_tim3_handle))
{
FreeRTOSRunTimeTicks++;
}
}
4.5 UCOSIII软件定时器
根据《STM32F767 UCOS开发手册_V1.0》第9章:
定时器是一个递减计数器,当计数器递减到0时触发回调函数。定时器分辨率由OS_CFG_TMR_TASK_RATE_HZ决定。
OS_TMR tmr1; // 声明定时器
// 创建定时器:周期模式,每100ms执行一次回调
OSTmrCreate(&tmr1, "tmr1", 0, 100, OS_OPT_TMR_PERIODIC, tmr1_callback, &err);
// 按键触发启动
OSTmrStart(&tmr1, &err);
// 回调函数
void tmr1_callback(void *p_tmr, void *p_arg)
{
static u8 tmr1_num=0;
LCD_ShowxNum(62,111,tmr1_num,3,16,0x80); // 显示执行次数
tmr1_num++;
}
五、555定时器在电源电路中的典型应用
根据《常用电源电路设计及应用》第7章、第8章和《实用电子元器件与电路基础》第11章:
5.1 直流倍压电源
将NE555电路产生的振荡脉冲,通过二极管整流电路整流后向电容充电,使电容充电至电源电压,将这样的整流充电电路逐级连接,就可以得到二倍、四倍甚至多倍于电源电压的升压电路。
核心结构(来自《常用电源电路设计及应用》第7章):
+12V → NE555多谐振荡器(2kHz) → 倍压整流电路 → +24V输出
5.2 负电压产生电源
同样出自《常用电源电路设计及应用》第8章:
利用NE555定时器将+12V的直流电压进行振荡,得到连续变化的振荡脉冲波形,再通过整流电路进行整流稳压,并对电压进行极性转换,从而输出-10V的直流稳压电源。
5.3 NE555在电源电路中的典型应用汇总
根据该书的"思考与练习"部分:
(1)NE555定时器在电源电路中的典型应用有哪些?
答:单电源变双电源、直流倍压电源、负电压产生电源、逆变电源等。
六、定时器电路设计的"黄金法则"
6.1 无稳态/有稳态布局
从《手绘揭秘基本功能电路》第1.2节:
在面包板上建立测试电路,然后再做不可变动的印制板的测试。在单稳态电路中,控制端误触发可能会导致故障发生,故需要将引脚5用0.1μF电容器接地。如果电源引线过长,可在8脚和1脚之间接入一个0.1μF或1μF的电容。
6.2 定时器的复位与抑制
根据《爱上电子学:创客的趣味电子实验(第2版)》实验16中的"基础知识:脉冲抑制":
当设置为单稳态模式的定时器第一次通电时,定时器很容易在静止之前自发发出一个脉冲。阻止脉冲产生的方法是在重置引脚和接地负极之间放置一个1μF的电容器。第一次接通电源时,电容器吸收重置引脚的电流,并在几分之一秒内保持该引脚处于低电位,阻止定时器发出"唤醒"脉冲。
6.3 定时器链锁设计
从《电子电路图识图技巧(升级版)》和《常用电源电路设计及应用》中可以总结出两种链锁方式:
- 级联定时器(《手绘揭秘基本功能电路》第1.4.6节):两个定时器都以单拍模式连接,输入触发脉冲后按先Timer1后Timer2的顺序进行。
- 多谐+单稳态组合 (DABL_G511):
- 定时器1作为非稳态振荡器(控制采样频率)
- 定时器2作为单稳态模式(控制采样窗口宽度)
6.4 PCB布局要点
基于DABL_G511/DABL7689的实际设计经验:
- 去耦电容:每个定时器芯片(如NE555)的VCC引脚旁必须放置100nF MLCC去耦电容,紧贴引脚,走线短而宽。
- 定时RC网络:决定定时周期的电阻R和电容C应尽量靠近芯片引脚,避免长走线引入寄生电容。
- 信号隔离:高速定时器信号(如PWM输出、编码器输入)应远离模拟信号和电源电路。
- 地平面完整性:定时器芯片下方保持完整的地平面,为充放电回路提供低阻抗路径。
七、常见问题与排查指南
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 555定时器不工作 | 复位脚4未接高电平 | 检查4脚是否接Vcc |
| 555输出频率与计算值偏差大 | 电阻/电容容差过大,漏电 | 使用1%精度电阻,测量实际阻值和容值 |
| STM32定时溢出中断不触发 | 时钟未使能,NVIC未配置 | 检查__HAL_RCC_TIMx_CLK_ENABLE()和HAL_NVIC_EnableIRQ() |
| PWM无输出 | 高级定时器未使能主输出 | 检查TIMx_BDTR的MOE位是否置1,或调用HAL_TIMEx_PWMN_Start() |
| 编码器计数不准确 | 编码器模式配置错误 | 检查EncoderMode、极性、滤波器设置 |
| RTOS任务统计时基不工作 | ConfigureTimeForRunTimeStats未调用 | 确认宏configGENERATE_RUN_TIME_STATS已定义 |
| ADC采样率不稳定 | 定时器触发频率波动 | 检查定时器预分频器是否稳定,时钟源是否干净 |
八、总结
定时器,这个看似简单的"计数器",在实际工程中扮演着无比重要的角色。从经典555芯片到STM32的复杂定时器架构,定时器电路始终是嵌入式工程师必须掌握的核心技能之一。
通过拆解 ZLinear系列数据采集卡 的定时器电路设计,我们可以看到:
- 选型匹配需求:555用于低成本、简单定时的场合(如门铃、玩具);STM32内部定时器用于高精度、多通道、可编程的工业级应用(如数据采集、电机控制)。
- 硬件设计扎实:去耦电容紧贴芯片、复位引脚正确处理、RC网络远离干扰源、信号走线注意阻抗匹配------每个细节都决定了定时器的稳定性和精度。
- 代码配合紧密:从HAL库的初始化配置,到中断回调函数,再到RTOS的定时器管理,软件与硬件紧密配合,实现了精确的时间控制。
- 系统化设计思维:在ZLinear的产品中,不同定时器各司其职(TIM2触发ADC、TIM1产生PWM、TIM3编码器接口、TIM6系统时基),形成了完整的时序控制体系。
最后,借用《达人迷:我的第一本电子电路DIY手册》中的一句话作为结尾:
在1960年代,一个定时器电路可能需要十几个分立元件;而在今天,一个指甲盖大小的芯片集成了数十万晶体管,实现了从微秒到数小时、从单一脉冲到复杂波形的一切定时功能。
这就是定时器技术的发展历程,也是电子工程进化的缩影。
我是 ZLinear 开源电子,一个专注于工业数据采集卡研发、生产与销售的专业团队。我们致力于从芯片级到系统级拆解硬核技术,分享一线工程经验。如果这篇内容对你有帮助,欢迎点赞、收藏、关注三连支持!我们下期继续拆解工业数据采集的硬核干货~