1. 项目概述与核心需求解析
今天想和大家分享一个我最近刚做完的雨水收集罐水位监测与保护项目。这个项目的起因很简单,我家后院装了几个大号的雨水收集罐,用来浇花、洗车,但每次想知道罐里还有多少水,都得跑过去掀开盖子看,非常不方便。更麻烦的是,罐子底部接了一个潜水泵,用来抽水灌溉,好几次因为水快用光了没及时发现,导致水泵空转,差点烧掉。所以,我就琢磨着能不能自己做一个“智能”监测盒,既能远程查看水位,又能自动保护水泵。
这个监测盒的核心目标有两个:第一,实现远程水位读取,我坐在屋里就能知道罐子里的水还有多少;第二,具备自动保护功能,当水位低到危险值时,能自动切断潜水泵的电源,防止干烧损坏。为了实现非接触、耐用的测量,我选择了电容式传感方案——简单说,就是利用两根绝缘导线浸入水中,通过测量它们之间电容的变化来反推水位高低。整个系统的“大脑”我选用了一颗经典的微控制器PIC16F628A,利用它内置的比较器模块来构建一个振荡电路,电容的变化会直接改变振荡频率,MCU通过测量这个频率就能算出水位。
整个项目涉及硬件设计、单片机编程、通信协议和简单的本地交互,算是一个比较典型的嵌入式系统小应用。无论你是电子爱好者想复现一个类似装置,还是正在学习如何将模拟传感器信号通过MCU处理并实现远程通信,相信这个分享都能给你一些直接的参考和启发。
2. 系统整体设计与方案选型考量
2.1 为什么选择电容式水位传感?
在开始画电路图之前,传感器的选型是第一个要解决的问题。常见的液位传感器有浮球式、压力式、超声波式和电容式等。浮球式结构简单但机械部件易卡死,且不适合需要连续测量或输出模拟/数字信号的场景。压力式(投入式)精度高,但传感器头需要长期浸水,对密封和材料防腐要求高。超声波式非接触,但安装复杂,成本较高,且易受水面泡沫或罐内结构干扰。
电容式方案在这里有几个突出优势:
- 无活动部件,寿命长:传感器就是两根平行的绝缘导线(或同轴电缆),没有任何机械运动部分,从根本上避免了卡滞和磨损。
- 介质适应性好:只要绝缘层完好,传感器本身与水不直接接触,避免了腐蚀和结垢问题,非常适合雨水这种可能含有杂质的环境。
- 原理简单,易于实现:电容变化可以通过简单的RC振荡电路转换为频率信号,非常适合用单片机内置的比较器来捕获和处理。
- 成本低廉:主要材料就是导线和绝缘皮,硬件成本极低。
它的工作原理是基于水的介电常数(约80)远大于空气(约1)。当两根绝缘导线浸入水中时,它们之间的等效电容会显著增加。将这个电容接入一个振荡器中,其振荡频率就会随电容(也就是水位)变化。我们只需要测量这个频率,就能推算出水位高度。
注意:电容式测量对绝缘层的完整性要求极高。任何微小的破损导致导线与水直接接触,都会使电容值剧增并失控,导致测量完全失效。因此,选择高质量、耐水解的绝缘材料(如特氟龙)至关重要。
2.2 主控芯片PIC16F628A的选型理由
手头的8位单片机不少,为什么偏偏选中了这颗有些年头的PIC16F628A呢?这主要是基于项目需求和芯片特性的精准匹配:
- 内置模拟比较器:这是最关键的一点。PIC16F628A拥有两个模拟比较器,且可以灵活配置成多种模式,其中就包括“带参考电压的比较器振荡器”模式。这让我们无需外接专门的振荡芯片(如555定时器),仅用片内资源和少数几个外部电阻电容,就能构建一个将电容变化转为频率信号的电路,极大地简化了硬件设计。
- 足够的I/O和外围资源:它具备RS-232兼容的USART模块,可以方便地转换为RS485通信;支持I2C主控模式,可以驱动OLED或LCD显示屏;还有足够的GPIO来控制继电器和按键。资源刚好够用,没有浪费。
- ICSP编程接口:支持在线串行编程,调试和烧录程序非常方便,不需要频繁拔插芯片。
- 低功耗与稳定性:Microchip的PIC系列以高抗干扰性和稳定性著称,这对于长期在户外工作的设备非常重要。
- 个人熟悉度与成本:这颗芯片资料丰富,我个人对其架构和寄存器操作比较熟悉,且价格非常便宜。
当然,它也有局限,比如处理速度较慢、内存有限。但对于本项目中主要进行的频率测量、简单计算、状态判断和通信任务来说,其性能完全绰绰有余。选择熟悉的、合适的,往往比追求“新”和“强”更重要。
2.3 通信与交互方案确定
远程通信和本地交互是项目的另外两个核心。
远程通信:RS485总线
- 为什么不是Wi-Fi或蓝牙?我的雨水罐位于后院,距离房屋有一定距离,Wi-Fi信号可能不稳定。蓝牙则传输距离太短。RS485采用差分信号传输,具有极强的抗共模干扰能力,非常适合长达数十米甚至上百米的远距离、有电气噪声的环境(如靠近水泵电机)。
- 实现方式:利用PIC16F628A的USART模块,通过一个RS485收发器芯片(如MAX485或SN75176)转换为差分信号。我将采用半双工模式,即监测盒平时作为从设备,等待主设备(如屋内的树莓派或PC)的查询指令,再回复当前水位数据。协议可以自定义一个简单的问答帧结构。
本地交互:I2C总线连接显示屏与按键
- 为什么选择I2C?I2C总线只需两根线(数据SDA和时钟SCL),就可以挂载多个设备,节省宝贵的I/O口。这里我计划连接一个小型OLED显示屏(如SSD1306驱动)来实时显示水位百分比和系统状态,同时连接几个实体按键用于本地设置阈值、手动开关泵等。
- 分工明确:RS485负责“对外”远程数据透传和控制,I2C负责“对内”的人机界面,两者互不干扰,架构清晰。
执行单元:继电器控制
- 使用一个单路继电器模块,由单片机的一个I/O口(RB3)通过三极管或MOS管驱动。当单片机判断水位低于设定的保护阈值时,拉低该I/O口,继电器断开,从而切断潜水泵的供电回路。这是最后的安全屏障。
3. 硬件电路设计与核心细节解析
3.1 电容传感与比较器振荡器电路
这是整个系统的信号源头,其稳定性和线性度直接决定测量精度。我使用了PIC16F628A比较器模块的“Two Common Reference Comparators with Outputs”模式(CM2:CM0 = 110)。
电路连接详解:
- 传感电容(C_sense):由两根平行铺设、绝缘良好的导线构成,垂直悬挂于水罐中。导线长度根据罐体高度确定,其电容变化范围(空罐~满罐)需要提前估算或实测,这决定了外部RC元件的取值。
- 振荡电路:比较器1(C1)被配置为弛张振荡器。
- C1Vin- (RA0):连接外部RC网络。具体来说,接一个固定电阻R1到VCC,同时接传感电容C_sense到地。这个节点的电压就是电容的充电电压。
- C1Vin+ (RA2):连接内部参考电压VREF。我通过软件将VREF设置为一个固定值(如0.6Vcc)。这个电压就是比较器的阈值。
- C1VOUT (RA3):这是比较器的输出,同时也是反馈端。它通过另一个电阻R2连接到C1Vin-节点。
- 工作原理:
- 上电时,假设C1VOUT输出高电平,通过R2向C_sense充电,C1Vin-电压上升。
- 当C1Vin-电压超过C1Vin+的VREF时,比较器翻转,C1VOUT输出低电平。
- 此时,C_sense通过R2向C1VOUT放电(实际是C1Vin-通过R2被拉低),C1Vin-电压下降。
- 当C1Vin-电压低于VREF时,比较器再次翻转,C1VOUT回到高电平,循环重复。
- 这样,在C1VOUT引脚上就产生了一个方波。C_sense越大,充放电时间越长,方波的频率就越低。水位升高,C_sense增大,频率下降。
关键参数计算与选择:振荡频率近似公式为f ≈ 1 / (2 * R2 * C_sense * ln((VCC-VREF)/VCC * (VCC/VREF)))。为了获得合适的频率范围(例如几百Hz到几KHz,便于单片机定时器测量),需要精心选择R1和R2。
- R1的作用:它和R2并联,影响充电时间常数。通常选择R1 >> R2,这样充电主要由R2决定,简化计算。我选择R1=100kΩ, R2=10kΩ。
- VREF的选择:设置一个合适的VREF(如0.25Vcc或0.5Vcc)可以优化动态范围。我通过试验发现,设为0.33Vcc时,在整个水位变化范围内频率变化相对线性。
- 校准:实际制作中,需要在“空罐”和“满罐”两种状态下,用频率计测量实际的输出频率,得到频率-水位的对应关系,用于软件校准。
实操心得:在焊接前,务必先用面包板搭建这个振荡电路,用示波器观察输出波形。确保在传感电容极端变化(可以用一个可调电容模拟)时,电路仍能稳定振荡,没有停振或波形畸变。同时,注意将R1、R2和连接传感电容的引线尽量缩短,并远离噪声源,以提升稳定性。
3.2 单片机外围电路与接口设计
主控电路围绕PIC16F628A展开,力求稳定可靠。
电源部分:
- 输入采用12V DC适配器,为继电器和可能的显示模块供电。
- 使用LM7805线性稳压芯片将12V降至5V,为单片机、RS485芯片和振荡电路供电。在7805的输入和输出端就近并联滤波电容(如100uF电解电容 + 0.1uF陶瓷电容),以抑制电源噪声。
编程接口(ICSP):
- 严格按照PIC ICSP接口定义,将PGC(RB6)、PGD(RB7)、MCLR(VPP)、VDD、VSS引出至一个5针或6针的排针。这样我就可以使用PICKit等编程器在不拆芯片的情况下更新固件。
RS485接口电路:
- 使用MAX485芯片。其RO(接收输出)接PIC的RB1/RX,DI(发送输入)接RB2/TX。
- RE(接收使能)和DE(发送使能)引脚短接,并由PIC的另一个I/O口(如RB0)控制。当RB0为高时,MAX485处于发送模式;为低时,处于接收模式。这是实现半双工通信的关键。
- 在A、B差分信号线上各串联一个120Ω的电阻(用于阻抗匹配,长距离时尤为重要),并在A、B之间并接一个120Ω的终端电阻(如果该监测盒是总线最末端的设备)。
I2C与继电器驱动:
- I2C的SDA(RB4)和SCL(RB5)引脚需要接上拉电阻(通常4.7kΩ到10kΩ)至5V。
- 继电器控制端(RB3)不能直接驱动继电器线圈。我使用一个NPN三极管(如2N2222)作为开关。RB3通过一个1kΩ限流电阻连接到三极管基极,三极管集电极接继电器线圈,发射极接地。继电器线圈两端必须反向并联一个续流二极管(如1N4148),以吸收断开时产生的反向电动势,保护三极管。
抗干扰设计:
- 在单片机的每个电源引脚(VDD)和最近的地(VSS)之间,都放置一个0.1uF的陶瓷去耦电容。
- 模拟部分(比较器参考电压、RC网络)的电源,可以考虑通过一个磁珠或小电阻从数字电源分离,再加强滤波。
- 所有外部接口(RS485、电源输入)可以考虑增加TVS管或压敏电阻,进行浪涌防护。
4. 软件固件开发与逻辑实现
4.1 开发环境搭建与项目配置
我使用的是MPLAB X IDE v6.05和XC8编译器(免费版)。虽然PIC16F628A可以用汇编语言获得极致效率,但为了代码可读性和开发速度,我选择使用C语言。
项目初始化关键步骤:
- 配置字(Configuration Bits)设置:这是PIC单片机特有的,必须在程序开头设置。它决定了芯片的一些基础工作模式。
FOSC = INTOSCIO:使用内部RC振荡器(4MHz),节省外部晶振。WDTE = OFF:关闭看门狗,调试时更方便,产品化时应开启。PWRTE = ON:上电延时定时器使能,让电源稳定后再开始运行。MCLRE = ON:MCLR引脚功能使能,用于复位和编程。BOREN = ON:欠压复位使能,防止电源波动导致程序跑飞。LVP = OFF:禁止低电压编程,释放RB3/PGM引脚作为普通I/O使用。
- 端口初始化:将用到的端口设置为数字I/O,并定义输入/输出方向。例如,RB3(继电器)、RB0(485方向控制)设为输出;按键对应的引脚设为输入。
- 模块初始化:
- 比较器模块:通过
CMCON寄存器配置为模式110,并设置VRCON寄存器来使能并设定内部参考电压VREF。 - 定时器模块:配置Timer1或Timer2用于测量比较器输出的频率。我选择Timer1(16位)在门控模式下工作,精度更高。
- USART模块:初始化波特率(如9600 bps)、数据位、停止位,使能接收中断。
- I2C模块:初始化为主模式,设置时钟频率(如100kHz)。
- 比较器模块:通过
4.2 核心功能模块代码解析
1. 频率测量模块:这是将模拟量转换为数字量的核心。我利用比较器输出(C1OUT)连接到Timer1的闸门控制引脚(T1G)这一特性。
- 原理:将Timer1配置为门控模式,其计数使能由T1G引脚(即C1OUT)的电平控制。当C1OUT为高时,Timer1开始对内部指令周期时钟进行计数;当C1OUT变低时,停止计数。
- 实现:在一个循环中,我连续测量多个完整方波周期(例如10个)内Timer1的计数值。为了提高精度,我测量的是高电平时间。假设测量了N个高电平周期,总计数为
count_total,那么单个高电平时间T_high = (count_total / N) * T_cy,其中T_cy是指令周期(对于4MHz主频,T_cy = 1us)。频率f = 1 / (2 * T_high)(因为方波周期是2倍高电平时间)。 - 滤波:连续采样10次频率值,去掉最大最小值后取平均,以抑制偶然干扰。
// 伪代码示例:测量10个高电平脉冲的Timer1计数 unsigned long measure_frequency(void) { unsigned long total_counts = 0; T1CONbits.TMR1ON = 0; // 确保Timer1关闭 TMR1H = 0; TMR1L = 0; // 清零计数器 for(int i=0; i<10; i++) { while(C1OUT_bit == 0); // 等待低电平结束(上升沿) T1CONbits.TMR1ON = 1; // 启动Timer1计数(此时C1OUT为高,闸门开) while(C1OUT_bit == 1); // 等待高电平结束(下降沿) T1CONbits.TMR1ON = 0; // 停止Timer1计数(闸门关) total_counts += ((unsigned long)TMR1H << 8) | TMR1L; TMR1H = 0; TMR1L = 0; // 为下一次测量清零 } unsigned long average_counts = total_counts / 10; // 根据average_counts和时钟周期计算频率... return calculated_frequency; }2. 水位计算与校准:得到频率f后,需要转换为水位高度h。这需要校准。
- 两点校准法:在已知“空罐”(h=0)和“满罐”(h=H_max)时,分别测量频率
f_empty和f_full。 - 线性拟合(假设线性度较好):水位百分比
level_percent = (f - f_empty) * 100 / (f_full - f_empty)。如果线性度不好,可能需要分段线性拟合或查表法。 - 软件实现:将
f_empty和f_full作为常量存储在EEPROM或代码中。每次测量后,进行上述计算,并对结果进行限幅(0%~100%)。
3. RS485通信协议与实现:我设计了一个简单的基于问答的协议。
- 查询帧(主->从):
0x01 0x03 0x00 0x00 0x00 0x01 0x84 0x0A(示例,仿Modbus RTU格式)。其中0x01是从机地址,0x03是功能码(读保持寄存器),0x00 0x00是起始寄存器地址,0x00 0x01是寄存器数量,最后两个字节是CRC校验。 - 响应帧(从->主):
0x01 0x03 0x02 0xHH 0xLL 0xCRC1 0xCRC2。0x02是字节数,0xHH 0xLL是水位数据(例如,0x03E8代表100.0%)。 - 软件流程:单片机USART使能接收中断。当收到一帧完整且校验正确的查询帧时,在中断服务程序或主循环中解析。如果是读水位命令,则立即读取当前计算好的水位值,组装响应帧,将RB0拉高切换到发送模式,发送数据,发送完成后拉低RB0切回接收模式。
4. I2C驱动与显示逻辑:
- OLED显示:使用现成的SSD1306驱动库。在主循环中,定期(如每秒)更新显示内容,包括水位百分比图标、数值、继电器状态(ON/OFF)、通信状态等。
- 按键扫描:采用状态机进行消抖处理。定义几个按键功能:菜单/确认、增加、减少、手动泵开关。按键操作可以设置水位报警阈值、校准参数等,这些参数可以保存到单片机的EEPROM中。
5. 继电器保护逻辑:这是一个简单的闭环控制。
// 在主循环中 unsigned char current_level = get_water_level_percent(); // 获取当前水位百分比 unsigned char pump_protect_threshold = eeprom_read(THRESHOLD_ADDR); // 从EEPROM读取保护阈值 if (current_level <= pump_protect_threshold) { PUMP_RELAY = 0; // 拉低控制引脚,继电器断开,泵停止 pump_status = PUMP_OFF_SAFE; } else if (current_level > (pump_protect_threshold + 5)) { // 加入回差,防止频繁启停 if (pump_status == PUMP_OFF_SAFE) { PUMP_RELAY = 1; // 拉高控制引脚,继电器吸合,泵启动(需考虑手动/自动模式) pump_status = PUMP_ON; } } // 同时,在显示屏和RS485回复中上报pump_status4.3 程序主循环与中断设计
一个清晰的主循环和中断服务程序(ISR)结构是系统稳定运行的保障。
中断服务程序(ISR):
- USART接收中断:当收到一个字节时触发。将字节存入环形缓冲区,并检查是否收到一帧完整的数据(例如通过超时或特定帧尾判断)。切忌在ISR内进行复杂的数据解析和响应发送,只做简单的数据搬运和标志位设置。
- 定时器中断:可以用于产生精确的延时,或者定时唤醒进行水位测量(如果使用低功耗模式)。
主循环(main loop):采用前后台系统模型,主循环不断查询各种标志位并执行相应任务。
void main(void) { sys_init(); // 系统初始化 while(1) { if(flag_measure) { // 测量标志,例如由定时器中断置位 flag_measure = 0; measure_and_process(); // 测量频率、计算水位 update_display(); // 更新本地显示 check_pump_status(); // 检查并控制水泵 } if(flag_rs485_cmd_received) { // RS485命令接收完成标志 flag_rs485_cmd_received = 0; parse_and_response_rs485(); // 解析命令并准备响应数据 } scan_buttons(); // 扫描按键 // ... 其他任务 SLEEP(); // 如果任务都完成,进入休眠模式省电(需配置) } }5. 系统集成、调试与实测心得
5.1 组装、布线与环境测试
硬件焊接完成后,不要急于通电。先用万用表仔细检查:
- 电源短路:测量5V和GND之间的电阻,确保没有直接短路。
- 连接正确:对照原理图,检查所有芯片的电源、地、关键信号线是否连接正确。
- 上电测试:先不插单片机,上电测量5V电压是否稳定正常。然后断电,插入单片机,再次上电。
分模块调试:
- 振荡电路:用示波器探头测量RA3(C1OUT)引脚,观察是否有稳定的方波。用手触摸或靠近传感电容的引线,看频率是否有变化,验证电路灵敏度。
- 单片机最小系统:编写一个最简单的LED闪烁程序,通过ICSP烧录,测试单片机能否正常工作。
- 频率测量:将振荡器输出接入已编程的频率测量代码,通过调试器或串口打印出测量的频率值,改变传感电容(可用不同容值的电容并联模拟),看测量值是否随之正确变化。
- RS485通信:使用USB转RS485适配器连接电脑,用串口助手(如Putty、SecureCRT)发送自定义的查询帧,看监测盒是否能返回正确的数据。注意设置正确的波特率、数据位、停止位和校验位。
- I2C显示:单独测试OLED显示,确保能正常点亮并显示预设内容。
- 继电器控制:编写程序控制RB3高低电平变化,用万用表通断档测量继电器输出端是否随之通断。务必先接一个灯泡或小风扇测试,不要直接接水泵!
5.2 校准与安装部署
校准步骤:
- 空罐校准:将传感器完全提出水面(或置于空罐中),在设备菜单或通过通信命令,触发“空罐校准”操作。设备会记录此时的频率值
f_empty并存入EEPROM。 - 满罐校准:将传感器完全浸入水中(模拟满罐),同样触发“满罐校准”操作,记录
f_full。 - 验证:将传感器置于不同深度,查看显示的水位百分比是否大致准确。由于电容与水位并非完全线性,中间点可能存在偏差。如果要求高,可以进行多点校准(记录多个水位-频率对应点,采用分段线性插值)。
现场安装注意事项:
- 传感器固定:使用防水、耐腐蚀的夹具(如不锈钢卡箍)将绝缘导线传感器垂直、牢固地固定在罐壁或支架上,避免晃动。导线从罐盖密封孔引出时,要做好防水密封。
- 设备箱防护:将整个电路板装入防水接线盒(IP65等级以上)。电源线、RS485总线、传感器线缆通过防水格兰头进出。
- 布线:RS485总线使用双绞线(如CAT5网线中的一对),并确保总线两端(或仅末端)接有120Ω终端电阻。电源线尽量远离通信线和传感器信号线,避免干扰。
- 接地:如果条件允许,将设备箱金属外壳和RS485的GND良好接地,有助于抗雷击和浪涌。
5.3 常见问题与排查实录
在实际制作和调试中,我遇到了不少问题,这里把典型的几个和解决方法列出来:
| 问题现象 | 可能原因 | 排查与解决方法 |
|---|---|---|
| 振荡电路无输出或波形异常 | 1. 比较器模式配置错误。 2. VREF未使能或设置不当。 3. R1/R2阻值过大或过小,导致无法起振。 4. 传感电容引线短路或绝缘不良。 | 1. 检查CMCON寄存器配置。2. 检查 VRCON寄存器,用万用表测量RA2电压确认VREF。3. 用示波器测量RA0节点电压,看是否有充放电三角波。调整R2阻值(通常在几K到几十K之间尝试)。 4. 用万用表测量传感器引线间电阻,应呈开路(兆欧级)。 |
| 频率测量值跳动大,不稳定 | 1. 电源噪声大。 2. 传感器引线受干扰(如靠近水泵电源线)。 3. 软件滤波算法不够强。 4. 振荡电路本身不稳定。 | 1. 检查电源滤波电容,示波器看5V电源纹波。 2. 将传感器信号线使用屏蔽线,屏蔽层单端接地。远离动力线。 3. 增加软件采样次数,采用更稳健的滤波算法(如中值平均滤波)。 4. 在RA0对地加一个小电容(如10pF~100pF)滤除高频毛刺。 |
| RS485通信失败,收不到数据 | 1. A/B线接反。 2. 波特率、数据格式不匹配。 3. 终端电阻未接或接错位置。 4. 方向控制引脚RE/DE时序错误。 5. 总线有多个设备地址冲突。 | 1. 交换A/B线试试。 2. 确认主机和从机波特率、数据位、停止位、校验位完全一致。 3. 在总线最远的两个设备上接120Ω终端电阻。 4. 用逻辑分析仪或示波器观察RE/DE引脚和差分信号波形,确保发送前切发送模式,发送后切接收模式。 5. 为每个设备设置唯一地址。 |
| 继电器偶尔误动作 | 1. 单片机I/O口驱动能力不足,在干扰下电平翻转。 2. 三极管基极电阻过大,导致三极管未完全饱和。 3. 续流二极管损坏或未接,线圈反电动势击穿三极管。 | 1. 在单片机控制引脚和地之间加一个10kΩ下拉电阻,确保默认状态稳定为低。 2. 减小基极电阻,确保基极电流足够使三极管深度饱和(Ib > Ic/β)。 3. 检查并更换续流二极管。 |
| 水位显示为0%或100%不变 | 1. 频率测量代码有bug,读到的Timer值始终为0或固定值。 2. 校准参数 f_empty和f_full丢失或错误(EEPROM读写问题)。3. 传感器完全失效(开路或短路)。 | 1. 通过调试输出原始频率值,检查测量逻辑。 2. 重新进行校准操作,并检查EEPROM读写函数是否正确。 3. 测量传感器两端电容,空罐和浸水时应有明显变化。 |
最后一点个人体会:这类嵌入式项目,硬件是基础,软件是灵魂,而调试则是连接两者的桥梁。耐心和细致的调试往往比编码本身花费更多时间。务必养成“分模块调试、逐项验证”的习惯,并善用示波器、逻辑分析仪这些“眼睛”。当看到自己设计的电路按照预想工作,传感器信号被准确采集、处理并通过网络传回时,那种成就感是无可替代的。这个雨水罐监测盒已经稳定运行了几个月,再也没为水泵干烧担心过,手机或电脑上随时可查水量的感觉非常好。如果你也想做一个,不妨就从最基础的振荡电路搭起,一步步来,遇到问题正是学习的好机会。