通过NE555方波发生电路测量pf级别电容大小(HAL库学习笔记)
NE555工作原理
根据手册上的555内部结构原理图可知:
左边3个电阻的阻值都是5kΩ 这也是NE555名字的由来
C1比较器的负输入端为三分之二VCC
C2比较器的正输入端为三分之一VCC
两个比较器的输出端接入到了SR锁存器
下面是SR锁存器的真值表
Q’是Q的互补信号 可以把3脚的输出看作为Q’ Q的输出直接接到三极管基级控制三极管开关
如果想让C1比较器输出端为1 那么比较器正输入端也就是6引脚电压大于三分之二
VCC
如果想让C1比较器输出端为0 那么比较器正输入端也就是6引脚电压小于三分之二
VCC
如果想让C2比较器输出端为1 那么比较器正输入端也就是2引脚电压小于三分之一
VCC
如果想让C2比较器输出端为0 那么比较器正输入端也就是2引脚电压大于三分之一
VCC
如果想让NE555产生方波就需要搭建手册中的典型电路 使NE555构成多谐振荡器
当电源上电时,电源通过RA和RB给电容C进行充电
所以NE5552脚和6脚的电压在升高
当电容上的电压小于三分之一VCC的时候 输出为高电平
当电容上的电压大于三分之一VCC小于三分之二VCC的时候 输出为保持原来状态 仍然为高电平
当电容上的电压大于三分之二VCC的时候 输出为低电平 这时内部的三极管就会导通,电容就会通过RB电阻接到7脚的三极管进行放电
(由NE555内部结构电路可知)只有当SR锁存器S输出1的 R输出0时候,也就是大于电容上电压三分之二VCC时
上图为通过示波器测量555引脚3的方波和充电电容的波形
相关公式
方波周期:T = (R1+2R2) C ∗ 0.693
方波频率:f = 1.44 / (R1+2R2)C
占空比:D = R1+R2 / R1+2R2
方波的参数只与 R1 R2 C有关
我们可以通过单片机的输入捕获功能,上升沿有效,这样就能采集到两个上升沿之间的定时器计数值,从而根据时钟频率计一个数多长时间转化为对应的周期时间
R1 R2 C的参数
对于NE555产生的方波:
低频范围:30-150Hz为低频段;
中频范围:150-500Hz为中低频段,500-5KHz为中高频段;
高频范围:5K-16KHz高频段
设计目标是通过调整电阻 R1+2R2的值,使得在不同电容范围下,输出频率保持在300 Hz ~ 3 kHz 在中频范围内可以抑制噪声与寄生效应效果
若频率过高(如>100 kHz),内部晶体管开关延迟会显著影响波形,导致占空比失真
高频下频繁充放电会增加平均电流,导致芯片发热
根据NE555在无稳态模式下的频率公式:我们选型R1=10K R2=230K
则R1+2R2=470K
在100pf时 方波频率为3kHZ
在1000pf时 方波频率为300HZ
当然如果想改变测量电容的范围 只需要改变阻值的倍数
例如R1+2R2=47 kΩ,测 10.0 nF ~ 100.0 nF
R1+2R2=4.7 kΩ,测 100 nF ~ 1000 nF
MX配置和代码编写
定时器计一个数的时间只和PSC和主频有关,极限就是不分频,假设你的时钟周期为170M赫兹,那你定时器极限就是计一个数5.66ns 与ARR值无关
单片机定时器的定时周期公式为:
T = (ARR + 1) × (PSC + 1) / F_CLK
其中:
ARR:自动重装载寄存器值(Auto-Reload Register
PSC:预分频器值(Prescaler)
F_CLK:定时器的输入时钟频率
这个公式代表的是单片机定时周期 可以用在多少时间进一次中断
例如主频72M的单片机 如果想一秒钟进一次中断
可以配置PSC = 7199,ARR = 9999
T = (9999 + 1) × (7199 + 1) / 72,000,000 = 1 秒
我们选择TIM2定时器也是因为32位定时器的ARR值很大,不担心溢出的风险
这里我们选择TIM2 32位定时器 不分频 因为我们采用上升沿检测 所以捕获的引脚我们采用下拉模式 这样更容易采集到上升沿信号
配置时钟的时候我们要注意
高级定时器:TIM1、TIM8(挂在总线APB2)
通用定时器:TIM2、TIM3、TIM4、TIM5(挂在总线APB1)
所以我们这里配置的TIM2的时钟总线频率为84M
#define HTIM htim2
#define TIM_CHANNEL TIM_CHANNEL_2
#define TIM_ARR UINT32_MAX
static uint32_t calculate_cnt_diff(uint32_t cnt1, uint32_t cnt2) {
uint32_t diff1, diff2;
if (cnt1 >= cnt2) {
diff1 = cnt1 - cnt2;
diff2 = TIM_ARR - cnt1 + cnt2;
} else {
diff1 = cnt2 - cnt1;
diff2 = TIM_ARR - cnt2 + cnt1;
}
if (diff1 <= diff2)
return diff1;
else
return diff2;
}
static float get_f_Hz() {
g_last_cnt = 0;
g_f_Hz_sum = 0;
g_measure_cnt = 0;
HAL_TIM_IC_Start_IT(&HTIM, TIM_CHANNEL); // 启动输入捕获中断
while (g_measure_cnt < AVG_N); // 等待测量完成AVG_N次
HAL_TIM_IC_Stop_IT(&HTIM, TIM_CHANNEL); // 停止捕获
return g_f_Hz_sum / g_measure_cnt; // 返回平均频率
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == HTIM.Instance) {
uint32_t cnt = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL);
if (g_last_cnt == 0) { // 首次捕获,仅记录计数值
g_last_cnt = cnt;
return;
}
// 计算两次捕获的计数值差
uint32_t cnt_diff = calculate_cnt_diff(g_last_cnt, cnt);
// 计算频率:系统时钟 / 分频因子 / 计数值差
float f_Hz = (float) SystemCoreClock / 2 / (float) cnt_diff;
g_f_Hz_sum += f_Hz; // 累加频率值
g_measure_cnt += 1; // 增加测量次数
g_last_cnt = cnt; // 更新上一次计数值
}
}
static float f_Hz_to_c_pF(float f_Hz) {
float c_pF = 1.44f / (R1K + 2 * R2K) / f_Hz * 1e9f
if (c_pF < 0)
c_pF = 0;
return c_pF;
}
calculate_cnt_diff(uint32_t cnt1, uint32_t cnt2) 函数计算两次捕获的计数器值 cnt1 和 cnt2 之间的最小差值,考虑定时器溢出(环形计数)的情况。
环形计数处理:
定时器从0计数到TIM_ARR后溢出,重新从0开始。例如:
若 cnt1 = 0xFFFFFFFF,cnt2 = 0x00000001,实际差值为2,而非 0x00000001 - 0xFFFFFFFF 的错误负数。
返回值:
返回两个可能的差值(正向或反向溢出)中的较小值,确保正确的时间间隔。
在每次输入捕获事件(上升沿)时触发中断,计算信号频率
读取当前计数值 cnt。
若是首次捕获(g_last_cnt == 0),仅记录计数值,不计算频率。
后续捕获时,计算与上一次的计数值差 cnt_diff。
根据公式计算瞬时频率并累加
误差分析
当我们真正焊接电路进行测试方波的频率时会发现 方波的实际频率与我们理论计算有至少百分之10-20的误差
NE555产生方波的本质就是RC震荡 所以误差影响最主要的就是参数
误差来源一:装置内寄生电容:
实际焊接时两个引脚之间的距离很近,很容易产生寄生电容
下图蓝色的接线端子为更换被测电容的装置,我将被测电容C空载时,555定时器3脚能产生300KHZ的方波
我这里电阻参数为R1=10K R2=200K 当然电阻至少有百分之一的数值误差,我们现在先假设电阻为理想电阻,这里通过计算器可算出,装置内的寄生电容大概为11.32pf
误差来源二:R1 R2阻值误差:
在实际焊接的时候各个焊点之间的走线难免会产生电阻 并且R1和R2的阻值不可能达到我们理想的要求
这里我的解决办法为,多次测量100pf到1000pf之间的电容 并且记录测量值 直接列举出修正测量值y=kx-b的形式
这里的b为装置寄生电容 x为实际测量值(就是我们通过输入捕获测出频率代入计算算出的电容值) k为电阻误差的补偿比例
我初步的拟定方案:y≈0.9757x−11.32
但由于嘉立创51休息我打的板子没有发货 所以先不给大家展示实际的测量结果了
后续会补全的
如果输出方波不够方 可以采用555输出经过两个非门增加驱动能力并且整形 并且在电源处加100nf电容进行滤波 保证输入电源稳定没有纹波