新闻详情

新闻详情

首页 / 资讯中心 / 详情

【CW32无线抄表项目】模拟电压(VC)比较器

发布时间:2026/6/19 1:41:08
【CW32无线抄表项目】模拟电压(VC)比较器
一、VC介绍特性ADC (模数转换)VC (电压比较器)反应速度慢需要采样、转换、计算极快纳秒级响应几乎瞬间功耗高ADC 模块很费电极低微安级适合电池供电省心程度需要 CPU 不停地去“问”结果自动触发电压一变立马发中断CPU 可以睡觉用纯硬件电路电压比较器 VC来代替软件算法ADC 采样从而解放 CPU。框图详情整体结构VC1和VC2是两套几乎对称的比较器通道每路都有正输入 INP、负输入 INN、比较器核心、极性控制、窗口模式、数字滤波和中断逻辑。比较结果最终既可以作为内部状态/标志使用也可以形成VC1_OUT/VC2_OUT输出信号并触发VC1中断/VC2中断。输入部分怎么理解INP、INN前面都有一个多路选择器说明比较器输入源不是固定的而是可以选不同通道。外部通道可以选VCx_CH0 ~ VCx_CH7之类的模拟输入。内部参考源也能接进来图里明确给了温度传感器1.2V基准电压ADC参考电压中间还有一个电阻分压器输入可来自VDDA或ADC参考电压输出为VCx_DIV.DIV这说明芯片内部还能先做一次分压再送去比较器当阈值参考。比较器核心中间三角形带/-的就是模拟比较器本体。VCx_CR0.EN使能比较器。VCx_CR0.HYS迟滞控制。这个很重要输入电压靠近阈值时容易抖动开迟滞可以减少误翻转。输出整形VCx_CR0.POL输出极性翻转。也就是你可以选择“正向输出”还是“反向输出”。后面还有VCx_CR0.WINDOW这表示VC1和VC2不一定完全独立也可以组合成一个“窗口比较器”。窗口模式的意义正常模式下VC1、VC2各比各的。窗口模式下通常一个比较器作为“下限阈值”另一个作为“上限阈值”低于下限落在窗口内高于上限这样就很适合做“区间检测”比如电池电压是否在正常范围内而不只是“高于某个点”。图中两个比较器中间交叉和逻辑门的部分就是在做这个窗口逻辑组合。数字滤波和状态输出数字滤波模块说明比较结果不是直接裸输出而是可以经过稳定化处理。VCx_CR1.FLTCLK滤波时钟。VCx_CR1.FLTTIME滤波时间/滤波长度。这类设计通常用于抑制噪声、毛刺、慢速抖动。滤波后的结果会反映到VCx_SR.FLTV滤波后的状态标志VCx_OUT最终输出信号中断部分触发条件选择由VCx_CR1[7:5]控制通常就是配置上升沿触发下降沿触发双沿触发或某种电平/状态触发VCx_CR0.IE中断使能。条件满足并且中断使能后输出VCx中断。这张图对应的典型用途电压阈值检测比如某路电压是否超过设定值欠压/过压检测配合内部参考和分压器窗口检测判断电压是否落在某个安全区间零点检测/波形边沿检测传感器阈值比较温度、模拟量越界判断读图时最关键的信号链输入选择INP/INN选谁比较器配置EN、HYS输出逻辑POL是否启用窗口WINDOW是否做数字滤波FLTCLK、FLTTIME是否开中断IE和触发条件选择配置流程第一步确定使用VC1还是VC2以及是“单路比较”还是“窗口比较”第二步配置比较器输入源谁接INP谁接INN第三步如果要用内部参考/分压阈值先配置分压器第四步配置比较器本体参数使能前先设HYS、POL、WINDOW第五步配置数字滤波FLTCLK、FLTTIME第六步配置中断触发条件和中断使能第七步最后打开比较器EN再读取输出标志或等待中断按寄存器拆开看VCx_CR0.INP选择比较器正端输入VCx_INP可选外部通道如VCx_CH0 ~ VCx_CH7VCx_CR0.INN温度传感器1.2V基准电压ADC参考电压分压器输出选择比较器负端输入VCx_INN除外部通道外从图上看还能选内部源VCx_DIV.VIN选择分压器输入源图里给出的候选是VDDA或ADC参考电压VCx_DIV.DIV设置分压比作用是把内部电压先缩放再作为比较阈值送入比较器VCx_CR0.HYS设置迟滞输入靠近阈值有噪声时建议打开能减少抖动误翻转VCx_CR0.POL设置输出极性正常输出还是反向输出由这个位控制VCx_CR0.WINDOW设置是否进入窗口比较模式单独使用某一路时通常关闭VC1 VC2组成上下限窗口检测时打开相关配置VCx_CR1.FLTCLK选择数字滤波时钟VCx_CR1.FLTTIME选择数字滤波时间/长度值越大一般抗毛刺越强但响应更慢VCx_CR1[7:5]选择中断触发条件从框图看是“触发条件选择”通常会是上升沿/下降沿/双沿一类VCx_CR0.IE使能该路比较器中断输出VCx_CR0.EN最后一步使能比较器VCx_SR.FLTV读取滤波后的比较结果状态VCx_OUT比较器最终输出信号推荐的实际配置顺序1)先关闭VCx_CR0.EN2)配置VCx_CR0.INP选择正端输入3)配置VCx_CR0.INN选择负端输入4)如果负端或正端要用内部阈值先配VCx_DIV.VIN和VCx_DIV.DIV5)配置VCx_CR0.HYS6)配置VCx_CR0.POL7)如果要做窗口比较再配置VCx_CR0.WINDOW8)配置VCx_CR1.FLTCLK和VCx_CR1.FLTTIME9)如果要中断配置VCx_CR1[7:5]和VCx_CR0.IE10)清状态标志如果手册定义有清标志位11)打开VCx_CR0.EN12)通过VCx_SR.FLTV轮询或者等待VCx中断翻成“使用场景”会更好理解普通比较模式目标判断某个输入电压是否高于阈值配法INP接被测信号INN接1.2V基准或分压后的内部参考配HYS可选POLWINDOW0需要稳定输出就开滤波需要事件响应就开中断窗口比较模式目标判断输入值是否位于某个区间内配法一路比较下限一路比较上限两路共享同一被测量或按手册要求分别接入打开窗口逻辑WINDOW输出就不再只是单纯“大于/小于”而是参与区间判断典型思路VC1输入与“下限阈值”比较VC2输入与“上限阈值”比较两路通过窗口逻辑组合后判断低于下限落在区间内高于上限一个更实用的寄存器思维导图输入从哪来INP / INN阈值怎么来内部基准 / 分压器 / 外部脚输出要不要翻转POL抖动要不要抑制HYS FLTCLK FLTTIME是不是要做区间检测WINDOW要不要中断CR1[7:5] IE最后开机EN几个配置经验阈值附近信号有噪声时优先开HYS再决定是否加数字滤波想快速响应边沿用较弱滤波想避免误触发用较强滤波如果只做软件轮询重点看VCx_SR.FLTV如果做中断检测边沿重点配VCx_CR1[7:5]和VCx_CR0.IE如果输入源切换频繁建议先关EN再改输入选择二、霍尔模块介绍AH812D特性高带带宽 (120kHz)反应极快不管是水表慢转还是电机快转都能抓到。静态 2.5V 输出这是最重要的信息。意思是当周围没有磁场时它默认吐出 2.5V 电压。耐热抗压能在 -40°C 到 150°C 工作工业级水准。应用场景除了咱们做的水表计圈它还能测电流、控电机。1脚 (VCC)电源正极。2脚 (GND)电源负极地。3脚 (VOUT)信号输出。它会把磁场的大小变成“变化的电压”从这里传给单片机的 PB00也就是咱们连 VC 的地方。$$C_{BYPASS$$(0.1uF)这是“电源滤镜”必须靠近传感器的电源脚防止电源杂波干扰测量。$$C_$$(0.5nF)这是“输出滤镜”能让输出的电压信号更平滑配合咱们之前代码里的数字滤波效果翻倍。工作电压 (4.5V - 5.5V)典型值是5V。静态输出 (2.5V)再次强调没磁场时就是 2.5V。伏笔这就是为什么你之前测到 2.5V 的原因也是为什么咱们要把 VC 阈值设在 2.67V 的物理依据。中心点横轴输出电压在 2.5V 时纵轴磁场强度是 0。线性关系磁铁的南极 (S)靠近电压往4.5V爬。磁铁的北极 (N)靠近电压往0.5V掉。型号区别A、B、C、D 四条线斜率不同代表灵敏度不同。斜率越陡如 AH812-A磁铁稍微动一点电压跳得越厉害。手册虽然推荐 0.5nF但在低速计数的场景下如水表、转速计我们可以换成470nF (104电容)。这样做相当于给信号加了一个‘减震器’能有效防止因为磁铁手抖导致的误触发计数。好处一强力硬件“去噪”霍尔传感器的输出信号比较微弱容易受到电机或电源的杂波干扰。0.5nF只能滤掉极高频的电磁波。470nF形成了一个更强的低通滤波器。它能把绝大部分的高频毛刺直接掐死在硬件阶段让传给单片机 PB00 的电压信号像丝绸一样顺滑。好处二自带硬件“防抖”之前晃动磁铁时数值猛跳很大一部分原因是电压在阈值附近抖动。当用了470nF后这个电容像一个“储能水槽”它会让电压的变化变得缓慢而圆滑。即使磁铁在边缘轻微抖动电压也不会立刻跟着剧烈跳变。这种硬件级的延迟配合咱们代码里的数字滤波能极大地解决“晃一下跳 145 圈”的问题。唯一的代价牺牲了响应速度用大电容会让传感器的反应变慢。如果用来检测每秒转几万转的电机470nF 会让波形失真但水表叶轮每秒钟可能才转几圈这种微秒级的延迟完全可以忽略不计。实物钕磁铁钕磁铁Neodymium magnet全称钕铁硼磁铁NdFeB在电子爱好者圈子里有个响亮的称号——“磁王”。它是目前人类能制造出的磁性最强的永久磁铁。别看它通常只有一颗纽扣甚至一颗米粒那么大它能吸起自身重量 600 倍以上的物体。同等体积下它的磁力最强同等磁力下它的体积最小。在智能水表计圈这个具体的场景下选用钕磁铁主要有三个“非它不可”的理由穿透力强体积小 水表的叶轮封装在充满水的密封腔内而我们的传感器 PB00 是装在干燥的电路板上的。磁力必须穿过加厚的塑料外壳才能被感应到。普通磁铁如果想穿透这么厚的壳体积会变得巨大根本塞不进叶轮而钕磁铁只需要一小块就能释放出足够的磁通量。极高的稳定性寿命长 水表一装就是几年甚至十年。普通磁铁容易随着时间流逝或温度变化而退磁磁力变弱导致计圈越来越不准。钕磁铁具有极高的矫顽力只要不遇到极高温通常高于 80℃它的磁性能保持很多年不衰减。线性响应更清晰 配合选用的AH812 线性霍尔传感器钕磁铁能提供非常稳定的磁场梯度。这意味着当它靠近时产生的电压变化非常干脆、线性度好不会给单片机的 VC 模块带来模糊的“灰色地带”。建立“磁力桥梁”当叶轮旋转时嵌在上面的钕磁铁会随之转动。磁铁周围存在着看不见的磁感线。当磁铁靠近 AH812 时这些磁感线会垂直穿过传感器的芯片表面。激发“霍尔效应”AH812 内部有一个半导体薄片。平时电流平稳流过输出 2.5V。当钕磁铁的磁场扫过时磁力会把薄片里的电子推向一边。根据磁场强弱电子偏转的程度不同输出端的电压就会随之起伏比如从 2.5V 爬升到 3.2V。触发“逻辑闸门”这就是咱们之前代码干的事了钕磁铁远在天边传感器输出 2.5V — VC 比较器发现 2.5V 2.67V 没动静。钕磁铁近在眼前传感器输出 3.2V —VC 比较器发现 3.2V 2.67V 触发中断计数器WaterPulseCount加 1。三、程序详情第一步确定使用模式 关使能流程图节点单路比较模式 - 选 VC2 - 关闭比较器使能对应代码我们选择了VC2因为你的霍尔传感器物理引脚 PB00 就是焊在 VC2 的通道 3 上。第二步是否使用内部分压阈值 (造一把尺子)流程图节点是 - 配置 VCx_DIV.VIN (选源) - 配置 VCx_DIV.DIV (设分压比)对应代码VC_DivStruct.VC_DivVref VC_DivVref_VDDA; // 原料选 3.3V 供电 VC_DivStruct.VC_DivValue 51; // 比例切成 63 份取 51 份第三步配置输入源 (牵线搭桥)流程图节点配置 VCx_CR0.INP (正端) / INN (负端)对应代码VC_InitStruct.VC_InputP VC_InputP_Ch3; // 正端接外面的水表 PB00 VC_InitStruct.VC_InputN VC_InputN_DivOut; // 负端接内部的 2.67V 标尺第四步配置比较器本体 (定规矩)流程图节点配置 HYS (迟滞) / POL (极性) / WINDOW (窗口)对应代码VC_InitStruct.VC_Hys VC_Hys_20mV; // 迟滞20mV 缓冲带 VC_InitStruct.VC_Polarity VC_Polarity_Low; // 极性正常输出 VC_InitStruct.VC_Window VC_Window_Disable; // 窗口不搞花里胡哨的双重比较第五步是否启用数字滤波 (戴上降噪耳机)流程图节点是 - 配置 FLTCLK (时钟) - 配置 FLTTIME (时间)对应代码VC_InitStruct.VC_FilterEn VC_Filter_Enable; VC_InitStruct.VC_FilterTime VC_FltTime_63Clk; // 听大约 0.4 毫秒第六步是否启用中断 清标志流程图节点是 - 选触发条件 - 使能中断 - 清除标志位对应代码VC2_ITConfig(VC_IT_FALL | VC_IT_RISE, ENABLE); // 靠近和离开都喊我 VC2_EnableIrq(VC_INT_PRIORITY); // 打开法官办公室的门 VC2_ClearIrq(); // 把以前的旧案子档案全撕了第七步使能比较器 等待流程图节点VCx_CR0.EN 1 - 等待中断对应代码VC2_EnableChannel(); // 法官醒醒开工了 VC_EnableNvic(ADC_IRQn, VC_INT_PRIORITY); // 打开老板办公室的对讲机接收端vc.h#ifndef __VC_H #define __VC_H #include cw32f030.h #include cw32f030_vc.h #include cw32f030_gpio.h #include cw32f030_rcc.h // 1. 使用 extern 声明全局变量告诉 main.c 这些变量的存在 // 注意这里绝对不能写 0只声明不赋值 extern volatile boolean_t gFlagIrq; extern volatile uint32_t WaterPulseCount; // 2. 声明初始化函数 void WaterMeter_VC_Init(void); #endif /* __VC_H */vc.c#include vc.h // 1. 在这里真正地定义并初始化变量它们的主人是 vc.c volatile boolean_t gFlagIrq FALSE; volatile uint32_t WaterPulseCount 0; /** * brief 水表计圈 VC 模块完整初始化 * 包含 GPIO、分压器、比较器、滤波器以及中断的配置 */ void WaterMeter_VC_Init(void) { VC_InitTypeDef VC_InitStruct; VC_DivTypeDef VC_DivStruct; VC_BlankTypeDef VC_BlankStruct; VC_OutTypeDef VC_OutStruct; // 1. 开启时钟 __RCC_GPIOB_CLK_ENABLE(); __RCC_VC_CLK_ENABLE(); // 2. 将 PB00 设置为模拟输入模式 (VC2_CH3) PB00_ANALOG_ENABLE(); // 3. 配置内部分压器产生 2.67V 阈值 (3.3V * 51 / 63) VC_DivStruct.VC_DivVref VC_DivVref_VDDA; VC_DivStruct.VC_DivEn VC_Div_Enable; VC_DivStruct.VC_DivValue 51; VC1VC2_DIVInit(VC_DivStruct); // 4. 配置比较器通道 VC_InitStruct.VC_InputP VC_InputP_Ch3; VC_InitStruct.VC_InputN VC_InputN_DivOut; VC_InitStruct.VC_Hys VC_Hys_20mV; VC_InitStruct.VC_Resp VC_Resp_High; // 开启硬件滤波 (63个时钟周期) VC_InitStruct.VC_FilterEn VC_Filter_Enable; VC_InitStruct.VC_FilterClk VC_FltClk_RC150K; VC_InitStruct.VC_FilterTime VC_FltTime_63Clk; VC_InitStruct.VC_Window VC_Window_Disable; VC_InitStruct.VC_Polarity VC_Polarity_Low; VC2_ChannelInit(VC_InitStruct); // 5. 初始化空白窗口和输出连接 VC1VC2_BlankInit(VC_BlankStruct); VC2_BlankCfg(VC_BlankStruct); VC1VC2_OutInit(VC_OutStruct); VC2_OutputCfg(VC_OutStruct); // 6. 开启中断 VC2_ITConfig(VC_IT_FALL | VC_IT_RISE, ENABLE); VC2_EnableIrq(VC_INT_PRIORITY); VC2_ClearIrq(); VC2_EnableChannel(); // 7. 开启 NVIC 中断通道 VC_EnableNvic(ADC_IRQn, VC_INT_PRIORITY); }main.c#include main.h #include cw32f030_gpio.h #include cw32f030_rcc.h #include init.h #include buffer.h #include fun.h #include radio.h #include delay.h #include flashhoufun.h #include cw32_eval_spi_flash.h #include dma.h #include vc.h // 全局中断标志 (fun.c 也要用) volatile uint8_t g_bIrqTriggered 0; void System_Init_Config(void); //int32_t main(void) //{ // // 1. 硬件初始化 // System_Init_Config(); // // // 2. 射频初始化 // if (rf_init() ! OK) // { // while(1); // 失败报警 // } // rf_set_default_para(); // // 3. 初始状态设置 (编译时决定) // #ifdef SLAVE_MODE // // [从机] 上电必须开启接收否则听不到第一句 // rf_enter_single_timeout_rx(15000); // #endif // // // [主机] 不需要预先接收它会主动发送 // while (1) // { // // 1. 优先处理中断 (公共逻辑) // if (g_bIrqTriggered) // { // g_bIrqTriggered 0; // rf_irq_process(); // SPI 读取状态 // } // // 2. 业务逻辑 (编译时二选一) // #ifdef MASTER_MODE // OnMaster(); // #endif // #ifdef SLAVE_MODE // OnSlave(); // #endif // } // //} //int32_t main(void) //{ // System_Init_Config(); // // SPI_FLASH_Init(); // // flash_fun(); // while (1) // { // } //} //int32_t main(void) //{ // System_Init_Config(); // 初始化时钟和串口 // SPI_FLASH_Init(); // 初始化 SPI 硬件 // SPI2_DMA_Init(); // 初始化 DMA 配置 // printf(开始 DMA 验证...\r\n); // // 第一步写入 kunkun // W25Q_DMA_Write_Kunkun(0x0000); // // // // // 第二步读取回来 // W25Q_DMA_Read_Back(0x0000); // // 第三步验证 // if (strcmp((char*)CW_DMA_RxBuf1, kunkun) 0) { // printf(验证通过收到了%s\r\n, CW_DMA_RxBuf1); // } else { // printf(验证失败收到了垃圾数据。\r\n); // } // while(1); //} int main(void) { // 1. 初始化基础外设 //LED_Init(); // 2. 调用封装好的 VC 模块初始化 WaterMeter_VC_Init(); // 3. 开启内核全局中断总闸 (所有配置就绪后最后开总闸) __enable_irq(); // 4. 主循环 while (1) { // 直接使用 vc.h 里 extern 声明过来的标志位 if(gFlagIrq) { PB09_TOG(); gFlagIrq FALSE; // 这里可以加一句串口打印用来观察 WaterPulseCount // printf(当前水表圈数: %d\r\n, WaterPulseCount); } } } void System_Init_Config(void) { RCC_Configuration(); GPIO_Configuration(); SPI_Configuration(); EXTI_Configuration(); ADC_Configuration(); }四、实物展示效果演示如图所示传感器和磁铁在至于同一平面时只有从下往上计数会加1从上往下则不会。磁极的“盲区”与极性 (Magnet Orientation)这一串磁铁磁极通常是在圆面的两头轴向充磁。磁场角度AH812 这种线性霍尔传感器最喜欢垂直穿过它身体的磁力线。当你由下往上划时磁铁底部的磁场刚好以最佳角度“切”过了传感器。而当你换个方向划磁场的角度发生了细微偏转导致垂直分量变小电压就达不到 2.67V 了。
网站建设 高端定制 企业官网