几天前,我发表了一篇文章,在文中我介绍了一个不用绝对值电路,而是用运放放大交流输入信号,同时在同相端输入直流,将输入的交流信号的电压抬升到单片机0-3.3V之间的电路。
有几个网页留言说可以计量芯片,就我设计的产品来说,其需要控制的增氧泵数量多; 
如果用计量芯片,则每路增氧泵的控制至少增加5元成本。
而且计量芯片还需要一些限流电阻、滤波电容、晶振等外围器件,会占用大量的PCB板面积。
所以,我所选用的是非常有竞争力的技术方案。
但是,需要非常深厚的软、硬件功底。
特别是对于软件,需要解决:
1) MCU资源分配问题,怎么样有限的MCU的ROM、RAM以及算力在A/D转换、真有效值计算、故障判断及保护、4g通信上做合理的安排。
2) A/D转换,怎么样进行16路A/D的转换,如何触发,怎么分时采样,采样结果怎么存储。
3) 数据处理,转换得到的数据如何做真有效值计算,如何标定。

MCU资源分配

我选用了STM32F103RCT6处理器,该款MCU主要有以下资源:
256Kbytes ROM空间,4K用于bootloader, 100K是应用程序区,100K用的固件升级时的固件存储;剩下的52K用于配置参数存储(比如标定参数,用户编写的程序等)。
64Kbytes RAM空间,4Kbytes用作与4G模块通信的接收环形队列,1Kbytes通信接收缓存。
2Kbytes为发送缓存。2Kbytes用于MODBUS通信,2Kbytes用于ADC的DMA缓存。RAM远用不完。
DMA用到3个通道,一个通道用于A/D转换,一个通道用于与4G模块的串口接收,一个用于与4G模块的串口发送。
Timer用了若干,其中一个用于A/D转换的触发,一个用来产生2ms, 8ms, 100ms, 1s等时基。
ADC用了16个通道,采用"Regular group"功能进行转换。
中断方面,使能了100us左右的中断,用于产生时间,以前耗时时间短的需要立即处理的事件。
比如modbus接收和发送超时计时。
由于复用以前的RS485代码,RS485的通信没有用DMA,而是用发送和接收中断处理。

但是发送和接收中断只搬运数据,而没有任何逻辑处理,因此所有中断加一起耗时不到10us,保证了主程序的实时性。

A/D的实现

1) 市电周期为20ms,对于每一个通道,在一个周期内共采样64个点。
一次采样的时间为:312.5us。
2) 将ADC设置为定时器触发,触发周期为312.5us,将全部16个通道设置为"Regular group“,使能"Regular group"转换功能。
这样定时器每隔312.5us触发启动A/D,A/D模块自动转换完所有16个通道。
3) 设置DMA,利用DMA模块将结果搬移到缓存。
4) 主程序实时查询DMA的缓存,判断是否有新的转换数据,如果有,则将数据取数,根据数据所在的指针位置判断所在的通道,再对该值做真有效值计算)。


真有效值的算法

真有效值均方根值,即每次转换出来的数值跟平均值做运算,推导过程如下:
0d74958b9f1642f4aae39e74b4208b4d~noop.image?_iz=58558&from=article.jpg
真有效值计算公式(少乘了N)

定义两个64位的变量,用于累加每一次转换的AD值,以及AD的平方值。
在一个周期64点转换完成之后,经过下述算式算出AD值的真有效值:
1) AD的平方值的累加值-AD值的累加值*AD值的累加值/N
2) 第1步算出的数值除以N
3) 第2步片出的数值开方;
6d93b4c88ef94a53bbf3d63de4e5cb3f~noop.image?_iz=58558&from=article.jpg
真有效值计算程序

真实物理量的标定



上述步骤算出的是AD值的有效值,而非真实物理量的有效值,要得到物理量的有效值,还需要进行标定转换。
我一般采用线性标定进行转换,即物理量=k*AD+b,为了避免耗时的浮点数运算,
我将k转为乘以整数除以另一个整数。
如果线性度比较差,我会采用分段线性化的方法,即根据AD范围分多段区间进行标定。
标定过程以及分段线性化由一个专门的软件模块完成,后面文章再详述。

来源:物联网全栈开发