缝合怪的电赛纪实

2020年9月21日,我忽然收到一位教授的邀请。这位教授是我高中时课题研究的指导老师,他知道个人电子与计算机大概是什么水平,而他邀请我参加的正是电子设计竞赛。html

我去作了点功课。往年,电子设计竞赛都在暑假里举办,今年由于特殊状况改到开学之后。教授则是学校里负责该竞赛的“出口”。由于以上种种机缘巧合,我才能有此次机会。git

比赛需三人组队,这是比较难办的,相比之下历届题目比较简单,若是是我来选题的话。我所处的理科试验班都是些次顶尖的学数学物理的人,找不到人一块儿参赛,只能先把密院ECE专业的女友拉下水,让她再去找一我的。有几我的表示有兴趣可是没时间,尽管如今看来“有兴趣”的意思是“有兴趣一块儿拿个奖”。咱们找了一我的聊聊,我简述了我准备比赛的计划,对方只是点点头,对着电脑不知看些什么。结束之后我跟女友商量说,要不就咱们俩参赛吧。github

中午咱们去电院开会。除了咱们组以外,别人都是人工智能大二学生,参赛能够在电子电路系统实验课程中得高分。我是来体验一下的,由于我一直不清楚本身的水平。之前作过几个项目,但都是本身定的目标,如今要在别人出的题中选一道完成,我能作到吗?个人项目都是肝出来的,从原理图到PCB到焊接到编程通常都要一个星期,如今要在4天3夜里完成,我能作到吗?一直都是一我的作的,如今要合做,虽然都是本身人但仍是跟独立完成不同的,我能作到吗?算法

因此我要好好准备。仔细分析了一下2019年的题,感受只有C题D题是有可能作的。这类测控题好就好在只需电路,不涉及小车、无人机等机械结构,后者是我没有接触过的。编程

我备赛的宗旨“别让比胜过程中的小事搞坏心态”。好比,去年C题和D题都要求设备能输出必定频率的正弦波,因此得把DAC或DDS调通;频率高了之后ADC跟不上,就得用精密整流电路和施密特触发器来检测幅度和相位;这些都不该该留到比赛现场才完成。更基本地,用按键或旋转编码器选择功能、蜂鸣器响表示测量完成、屏幕上显示测量结果等功能都是必需的。数组

这样一来就能够决定要做什么准备了:缓存

  • 再作一块咱们熟悉的开发板框架

  • 作一个IO模块,放经常使用的输入输出设备,它经过I²C与开发板链接;异步

  • 设计一系列模拟电路模块,实现各类经常使用功能,如线性运算、精密整流等。函数

当时还在准备9月30日的数分高代考试,就没有直接参与准备,把IO模块的设计丢给女友让她设计年轻人的第一块PCB。要说工做也是有的,我在淘宝上下了12个单买元器件和模块。

↑有关的、无关的PCB

 

十一期间只在家里待了三天半就去学校了,这三天半里也有大半都是焊接。做为老焊工,焊接的过程就省略了。在确认下载器能够检测到单片机之后,我就带着这些去学校了,可是且慢……

彼时个人元器件库存已经比较成系统了,但新到的那么多快递仍是带来了不小的压力。最麻烦的是我要带一些元器件和模块到学校去,由于听说实验室里的阻容不怎么齐全。根据个人日记描述,仅后来选题之后感受能用上的就有:

  • 挺全的色环电阻;

  • 挺全的独石电容;

  • 少许电解电容;

  • 2N390四、2N3906(直插很少,贴片买了,有转接板);

  • 模拟开关405一、405二、405三、4066(各2片);

  • 继电器(5个),二极管;

  • 运放LMV358(5片)或LM358(20片);

  • 数字电位器X9C103S(5片);

  • 直插74HC595(5片);

实际带的还有各类模块,包括DAC、DDS等,还有一些小车能用上的,但整体来讲仍是把赌注往模拟电路上押的。

在学校,除了一天半的做业时间之外,别的都是写bug与debug。全部这些bug都是有关总线的,一个I²C的,别的都是SPI的。

忘了说IO模块的结构了。ATmega328P单片机,I²C接开发板,SPI上接74HC59五、16五、DAC和OLED屏,用一片138来作片选。595接4个LED和OLED的两个控制信号,165接4个按键和旋转编码器。SPI上挂了4个设备,不免出现各类bug。

首先是595调不出来,不管怎么写都是QH亮。把板子翻过来一看,原来是595和165焊反了。用热风枪拆下来后焊到正确的位置,过程当中还经历了学校的焊锡不化和烙铁头不沾锡的问题。而后165的C引脚始终读到0,考虑到这片165是用热风枪拆了两次的,就认为这个引脚坏了,因而用飞线把这个点和一个未使用的GPIO接起来了。我想过换一片165,可是找不到能够换的片,并且铺铜上的绿皮也由于不得不开到400度的电烙铁而脱落了很多,换个片极可能致使整块板报废。

用GPIO驱动165很是顺利,可是改用SPI后就发生了很奇怪的现象:第1位能正常读到,可是第2位读到的始终与第1位相同,后面的很乱讲不清楚,大致就是位与位之间有关联。我又开始怀疑165损坏,可是换用GPIO的程序仍是正常。试了几回之后我把SPI时钟频率从4 MHz降到0.5 MHz,终于能正确读取了。原来我为了避免让165的输出与下载器的MISO冲突,给前者串联了一个1k电阻,这使该信号的频率上限严重降低,再加上那片165多少沾点nt,4MHz就这样爆了。

某天半夜调DAC。DAC复位后应该输出0V,但写了正确的指令后用ADC测出来像是高阻。把10位数据的低4位都写0,其他从零开始增加,获得分段增加的输出电压,我感受是数据被移位了。果真,以前想固然地选择SPI mode 3,而实际上该用mode 2。

OLED的RESD/C控制信号接在了595上,SPI与单片机直接相连,跨了两层,问题也出在这里。屏幕和接线都跟之前我作过的一个模块同样,只把u8g2的GPIO回调函数改了一下,可是没法显示,测电压之后发现电荷泵都没打开。依然是先怀疑屏幕坏了,但这要软件上调不出才能下结论。我在回调函数里加了点串口输出,发现每次在SPI上发送一两个字节以前都会先设置D/C的电平,该电平须要写595才能设置,而写595会破坏OLED的片选信号,致使始终没有完整的指令发送给OLED。解决方案是切断原来595输出到D/C的链接,改用飞线链接到另外一个未使用的GPIO上。

后来屏幕成功点亮。初始化中执行了清空缓存并更新现实,可是屏幕上只有前8行像素被清零,其他的很随机,是未初始化的状态。最后发现是队友把初始化函数选错了,应该选择后缀为_f的,在内存中存放整个显存。

debug的这几天,新作的PCB也到货了,是24个模拟电路模块,两个方向上都是20*4+15+1间距*4=99 mm。没有作V割,由于出不起拼板费。我新买的小台锯就是用来切PCB的,只是放在了家里。我想着学校应该会有可用的设备,但跑遍学校也只有激光切割机,工做人员说没有切过PCB,试了一下的确不行。没办法,只能让家里人把台锯送过来。

10月8日,假期的最后一天,去实验室熟悉了一下设备。直流电源、信号发生器和数字万用表比较平凡,示波器得好好研究,尤为是触发功能。那天去的实验室里是Rohde & Schwarz的示波器,不当心碰了一下屏幕之后咱们发现它居然是触摸屏的!总之就是很是厉害。焊了一个滞回比较器模块,用带噪音的正弦波做输入,输出没有在输入接近地时快速抖动,这说明实验是成功的。在这种时候作这么简单的实验只是想找回一点自信心,由于此前几天的debug过程让咱们很是担忧比赛时会继续遇到各类各样的bug。

↑VSSOP-10封装,0.5 mm引脚间距

 

10月9日固然没什么心情上课啦。晚上调着DAC和DDS模块,忽然群里轰来好几个文件,一看居然是比赛题目!是网站方的失误,把题目提早放了出来,组委会也决定将错就错,提早开始了比赛,但不提前结束。

咱们开始选题。A题涉及两个早就公布的芯片,咱们查过淘宝上已经有不少方案了,可见别的组都早有准备;B题电源,没学过;C题小车,没学过;D题无人机,没学过;E题模拟电路,是咱们准备过的方向;F题上海不选,能选也不会;G题识别,没学过。综上所述,选E题

我连夜写了一份非正式报告,包括实现方案、附加功能、可能遇到的问题等,写到早上5点。10日,教授说电子系的全都选了E题,我切身体会到了什么叫内卷。

可是换题已经没有可能了,咱们只好卷下去。咱们先去另外一间实验室熟悉环境——咱们将在那里待上4天3夜。开了一台示波器,从Windows的logo就开始不对劲,开机之后发现是花屏了。又开了一台,也花屏。我开始怀疑这间实验室是废旧仪器仓库,后来教授带着终于凑齐了一套好用的电源、信号发生器、示波器和万用表。

审题放在下一节讲。方案离不开共射放大电路,我开始用Multisim来调参数。无失真、顶部失真、交越失真都没有问题,双向失真暂时没有思路,而在底部失真的仿真中我发现了很奇怪的现象:底部失真本应是输出波形的底部被削平,但仿真结果倒是底部波形上翻。用面包板搭建电路后也是如此。问教授后得知通常发射极都要加电容,在保持直流工做点的同时提升放大倍数。这下双向失真也很容易实现了。至于不加电容时波形会上翻,是由于集电极电压不能低于发射极,而放大倍数不很大时基极电压的变化就会反映在输出上。

队友用面包板搭建了一个两级负反馈三极管放大电路,原本打算用做前级小信号放大的。搭面包板的过程当中,咱们发现仍是本身带的电阻电容比较齐全。

晚上,队友写了个C++程序试试FFT和THD。把FFT采样频率改到与正弦波频率的几倍差一点,发现THD比较小,这说明THD的测量对采样频率的精度要求不高。

说说别的组。我一早上就去实验室了,其余3组到中午才有人来,有一组的另两我的晚上才来,这才完成了选题。此时,咱们已经有了方案,就等次日开始制做了。

↑模拟电路模块

 

我一开始的想法是设计5个放大电路,用模拟开关来切换通道。教授说能够经过改变放大倍数实现,我以为这个想法也不错,可是仔细思考又感受不对:放大倍数小的时候是正弦波,大了之后要么顶部失真,要么底部失真,再大变成双向失真,因此为了同时得到顶部和底部失真须要调整直流工做点;并且这种方法不能涵盖交越失真。这些意味着须要好多级的切换。虽然各类模拟开关我都有,可是会让设计的层次不那么分明,比较复杂。最终仍是采用了原来的方案。

在内卷的竞争中,咱们必须在附加功能上花工夫才能脱颖而出,因此除了题目要求的功能之外咱们还打算加入波形显示和声音输出的功能。

设备共由4块板组成:一块洞洞板对外接12 V电源、输入和输出,板上有LDO、模拟开关和三极管放大电路,以及与其余板链接的引脚,直流工做点均可以用电位器来调整;一块洞洞板上焊接两个模块并粘了一个扬声器,负责信号的运算,即把12 V范围内的信号耦合到5 V之内;一块开发板;一个IO模块做UI。

算法部分,FFT选用了Arduino FHT库,以1 kHz的32倍频采样,FFT规模256,计算16位线性幅度。而后根据题目里的公式取相应的FFT结果来计算THD——fht_lin_out[0]是直流份量的幅度,[8]是基频,[16]是两倍频等。一开始是16倍采样频率,规模128,为了精度和频率分辨率再加一倍,可是效果不太理想,最后只可以用就好了。

在25 MHz主频下,1 kHz的32倍频对应781.25个周期,尽管没法让ADC采样精确地发生在分数周期时刻,但也要避免0.25周期累加产生的影响。为此,以4次为周期,OCR1A寄存器的值取1次781、3次780。后来发现这点精度损失彻底能够忽略不计。

IO模块的按键是事件驱动的,按下时IO模块会经过I²C通知开发板。程序切换一个波形后,须要先等待1秒让直流工做点稳定,再以0.5 s为周期执行采集、计算、显示等操做,只有空闲的时候才容许退出。尽管定义过事件启用禁用的指令,可是一是怕出现一些破坏原子性的状况,二是异步终止一个过程的流程很差写,因此我又把异步事件改回同步——在回调函数里设置标志位,在流程里须要的时刻轮询。

THD计算中须要开根号,FFT到频谱图须要取对数,均可以用二分算法来实现。开根号的过程是对结果进行二分查找。一个小细节是AVR开发中int默认是16位,uint16_tuint16_t会溢出,要先转换为uint32_t。取对数是把0-10000映射到0-48。先在Excel中生成指数表,做为数组放进程序,写一个相似std::lower_bound的二分查找算法获取index,即为结果。

示波器稳定图像的方法是使用触发功能,基于这种想法咱们在256长的数据中找出第一个在512±16滞回比较器中的上升沿,做为2波形周期64项的开始。后来有了硬件滞回比较器,但仍是沿用了软比较器做触发。

最后一天还想加点功能,教授说题目里没有明确说明要测THD的都是1 kHz的信号。用FFT直接计算基频是不许的,由于频率分辨率只有31.25 Hz,但FFT能给出基频的范围,即第一个峰值附近,我定义为比左右两边都大且超过最大值的一半的第一个值。找出这个index,把它右边一格对应的周期做为周期的下限。而后用链接到硬件滞回比较器的GPIO检测上升沿,累加上升沿间隔直到超过下限,记录下通过的周期数。测量16次,排序,取中间8个的平均值做为信号的周期。而后32倍频ADC采样,后续流程相同。

↑滞回比较器的输入与输出波形(先用运放凑合一下)

 

11日开始制做设备。上一次焊洞洞板仍是刚接触PCB的时候,那时作了一个电位器调音量的电路,最后失败了,因此我对洞洞板一直不太看好。此次画PCB已经来不及了,只好硬着头皮上洞洞板了。

洞洞板上共有6个放大电路:前级放大和5种波形对应的电路。每一个子电路和电源都链接到排针做输入输出,两级之间暂时用杜邦线链接。先焊好前级,测试一下没问题,内心就有底了。一下午焊完了6个电路,调好电位器后都能正常工做。

反面的接线挺乱的,尽管元器件是按照信号方向从左到右、电压高低从上到下的规律排列的。典型的如GND分布在每一个子电路的多个电阻上,我直接用电阻的引脚拉到旁边的GND上,每一个子电路汇聚到一个点再接到最下方的一长条焊锡上。有些短程的链接要跨线,我用剪下的引脚或飞线跨接。

模拟开关进入战局后状况就变得不太乐观了。首先是我不知为什么要用两片CD4051,其实只要输出端一片就够了,这几乎把接线的复杂程度翻了一倍。模拟开关工做在12V,单片机输出信号须要转换才能用,我就在洞洞板背面用贴片三极管和贴片电阻焊了3个反相器,输入接排针,输出用飞线接到两片4051上。这一步很困难,原本就是三极管集电极和贴片电阻之间一点点地方,还要接到两个引脚上,还那么靠近。为了测试方便,在排针上面还加了一排高电平,这样用跳线就能够选择通道了。而后又把LDO、输入输出耦合等加进来,一步步地很费时间,作完已是次日凌晨了。

咱们须要为4块板找一块底板固定起来。实验室找不到新的大洞洞板,只能用一块用过一点的大板,把用过的部分切下来。而后用台钻钻3 mm孔,用铜柱和螺丝固定上去。板上的电源和输入输出用的是香蕉和BNC插座,为了焊到板上也是要先钻孔。BNC插座的外层不沾锡,我拿从杜邦线中拆出的铜丝绕引脚一圈焊上,才使链接稳定。

最后咱们听取教授的建议,为了稳定把杜邦线链接改成焊接,个人队友完成了这项工做。第三天晚上完成这些,而后一块儿把报告写了,队友负责软件部分,我负责其他所有。最后一天作的就没有写进报告里了。

↑成品

 

实际过程固然没有这么顺利——又到了喜闻乐见的debug环节。先讲硬件问题。

虚焊出现过两次。用探头测波形,要按下才会有波形显示,开始几回稍微用力便可,后来要按到底才行。从侧面看,按到底的时候焊点已经碰到了桌面,因此我推测是焊接问题。把用转接板和排针链接的三极管换成直插的,解决了问题。此后三极管只敢用直插的了。还有一次是用锡走线没有链接彻底形成的。

输出失真波形的平直段倾斜,测了各级的输出后发现是最后一级耦合到地的问题,把105独石电容换成10 μF电解电容解决了问题。

功放芯片只找到LM386。队友按照datasheet上的电路焊了洞洞板,但扬声器里的声音是必定频率的爆音,且爆音频率与输入电压正相关。想到多是输入耦合的问题,加了电容可是没有改善。我又用面包板搭了一样的电路,换了多个芯片,都是一样的问题。此时她正由于前两天没能帮上什么忙而难过,这下电路没作成更加沮丧,而我也一会儿没想到什么可行的方案。但我深知不能两我的一块儿颓废,情急之下我想到了以前作的模块(还记得准备阶段的目标吗?),正好有一个用三极管扩大运放输出电流的模块能够用做功放。板子早就切好了,焊上电阻电容二三极管,外部只需再加一个电解电容,扬声器就能响了。

12日晚,临写报告时又读了一遍题,发现忘了题中的K1K2两个SPDT。实验室一时半会也找不到开关,我急中生智把开发板上两个用不到的拨动开关拆了下来,焊在洞洞板上,再小改了一下接线。

而后是软件问题。动手写代码以前我就意识到了异步事件的问题,个人队友是搞不定的,因此我就安排她把ADC->FFT->THD的过程写成一个函数,不用管函数调用的位置以及先后须要作什么。可是吧,问题就在于机械革命到了Ryzen这一代品控仍是继续差,队友的笔记本掉屏幕了!还好掉得早,已完成的只占一小部分,后面的代码就都是我在我用了近三年的笔记本上写的了。这是电脑的硬件问题,开发过程当中的软件问题。

第一次跑半完整程序的时候,启动时间远长于预期,至少到了秒的数量级,而正常的启动时间应该不到100 ms。在代码一开始加上翻转引脚电平的指令,接逻辑分析仪发现启动过程有三次复位,而且都是硬件复位。我把初始化过程当中调用的函数一个个注释掉,最后发现是ADC的初始化致使了复位。进一步分析,可能的缘由是开启ADC时AREF上的0.1 μF电容会被充电,使5 V电压忽然降低,降到了brown-out电压如下,触发单片机复位。我把brown-out电压从4.3 V改到2.7 V,单片机就再也不复位了。

用逻辑分析仪看波形时发现I²C指令之间有10 ms量级长的间隔。两边用的I²C驱动是我本身写的异步写同步读,只有在缓冲区满时才会阻塞,从机端的处理也所有在中断中进行。仔细观察波形后我发现是从机在地址字节以后把SCL拉低了,阻止主机发送后续数据,而这是由于程序没有及时进入相应的中断去写寄存器,实际上程序还在处理上一个绘图指令,绘图是比较耗时的。我想到能够用相似的方法把指令放在缓冲区中,在定时器中断中取指令并执行。后来发现效果不怎么理想,一是间隔仍然存在,二是缓冲区受不了128根柱子的数据量,形成数据丢失,因此又换回来了。

Arduino FHT输入为16位带符号数,ADC只能读到10位,这样输出的幅度很小,精度不高。把ADC读到的值左移6位再在低位补上高6位做为输入,却得不到正确的FFT输出和THD值。检查后发现忘记考虑符号了,只需把MSB翻转便可。

开发板处屡次出现内存不足的状况。一开始FFT规模为128,OLED缓冲区占1KB,要显示的字符串太多,占用了不少内存,我就把它们移到flash中去,留出了一百多字节的空余内存。后来FFT规模改到256,内存怎么都省不出来了,只能改OLED的显示方式,只给它分配256字节显存,每幅图像分4次绘制。

以上bug其实占用了有效比赛时间的大部分,因此我实际上是没什么时间睡觉的。天天回一次寝室拿东西,晚上睡在实验室楼下大厅的沙发上。有一天打算1点睡,结果debug到4点才睡;又有一天打算4点睡,队友开玩笑说我怕是要7点睡了,结果我真的7点准时叫她起床了。

↑10月4日,外滩灯光秀

 

比赛结束后我好好睡了一夜,次日睡了一上午、一中午、一下午和一夜。

15日校测,咱们带着箱子到陌生的实验室测试。咱们复原后测试时,发现双向失真的输出波形达不到2 Vpp了,调电位器也没有用。我想起制做时由于双向失真输出峰峰值明显高于其余几个波形,就把下端的分压电阻并联上一个相同阻值的。如今只要把这个额外的电阻取下来就能够了,不用动电烙铁,直接用钳子剪断一端就行了。

咱们很快就准备好了,开始关注其余组的状况,尽管不能看。有一组没有加K1K2,从而有项目没法测试。我以前注意到这点的时候思考过这两个SPDT有什么用,思考的结果是为了验证THD是真实的,即给一个外来的波形要求测THD,不然THD是能够用现成设备测好后硬编码进程序的,尽管我在实验室没有找到过能够测THD的设备。大三的几组都作了很大的板,板上甚至有三极管的阵列,以致于我觉得他们是选电源题的。后来据说这是他们为了大做业作的。

咱们的测试很顺利,而且两个开关的功能正如我所预料的。题目要求能测量1 kHz、2 Vpp的方波和三角波的THD,而后与标准答案比对。咱们的设备测量得有一点偏差,但在合理的偏差范围内。

到了18日位于隔壁华师大的市测,测试的项目大体相同,波形换成了理论THD为8%和20%的,频率仍然是1 kHz。进入这个模式前专家先告诉我,设备显示的THD要能在切换波形时自动更新,这是一个得分点。专家让我调设备进入测量模式,此时尚未信号源,所以我以设备须要先测量信号频率为由拒绝了,并要求先开启信号源,专家赞成了。由于要自动更新,因此得在屏幕上THD的瞬时值和平均值中选择前者来读,第一个是8.5%,第二个20.5%,上下波动均不超过0.2%,我很满意。

最后得了一等奖,但此时这已是次要的了。我很累。据说电赛不能找室友组队,由于室友之后还要一块儿住;而我选择了最亲近的人一块儿参赛,能够想象咱们经历了多少困难。若是还有机会,我不想再参赛了。

回想起来,比赛的几天我没有过任何重大技术突破,全部技术要点都是炒冷饭。那么时间都用哪去了呢?大概是以上十几个bug吧。我不想之后回忆起这段参赛经历只想得起我睡得多少、有多累,而是经验——那些踩过的坑、避过的雷、de过的bug,故为此文。

那些借用来的技术要点以及它们的来源包括:

  • I²C通讯、整个流程控制框架,来自我高中时的课题,本博客没有;

  • 三极管放大电路、FFT,自制蓝牙音箱的手册

  • 示波器,AVR单片机教程——示波器

  • 二分算法,来自遥远的C++、DSA记忆;

  • 硬件、软件的debug经验,分布于个人开发经历中;

  • 等等……

我愿称之为“缝合怪”。

↑本身作的电赛限定版PCB钥匙扣

相关文章
相关标签/搜索