做一个数字采样示波器一直是我长久以来的愿望,不过毕竟这个目标难度比较大,涉及的方面实在太多,模拟前端电路、高速adc、单片机、cpld/fpga、通讯、上位机程序、数据处理等等,不是一下子就能成的,慢慢一步步来呗,呵呵,好歹有个目标,一直在学习各方面的知识,也有动力:)由于高速adc涉及到采样后的数据存储问题,大量的数据涌入使得单片机无法承受,因此通常需要用外部高速ram加cpld配合,或者干脆用大容量的 fpga做数据存储处理等,然后通知单片机将数据发送出去。这部分实在是难度比较大,电路非常复杂,自己是有心无力啊,还得慢慢地技术积累。。。
正好st新推出市场的以cortex-m3为核心的stm32,内部集成了2个1msps 12bit的独立adc,并且内部高达72mhz的主频,高达1.25dmips/mhz的处理速度,高速的dma传输功能,灵活强大的4个timer等等,这些真是非常有吸引力,何不用它来实现一个低频的数字示波器功能呢,我的目标是暂时只要定量定性地分析20khz以下的低频信号就行了,目标不高吧,用stm32可以方便地实现,等有了一定经验之后慢慢再用fpga和高速adc搞个100msps采样的示波器!
1、 adc转换:stm32增强型芯片内置的2个独立adc,可以有16个通道,并且2个通道可以并行的同步采样,触发方式很灵活,可以通过timer以及外部电平等方式触发,并行方式下adc2自动同步于adc1;adc在最高速采样的时候需要1.5+12.5个adc周期,在14m的adc时钟下达到 1msps的速度,因为我主频是72m所以4分频后稍微高了点,18mhz的adc时钟,采样速度应该高于1m了。adc 采样2路同时采样方式,用tim2 cc2来生成时钟信号触发adc来实现指定频率的采样。adc1/adc2采样的结果是一个word
2、采样频率控制:由于stm32内部的4个timer非常强大,每个timer又有4个通道,再加上独立的预分配器,实际上可以实现任意分频,因此用tim2 cc2来产生指定频率的时钟,用来触发adc1连续采样。
3、采样数据传输及每次采样深度控制:adc产生的转换数据通过高速dma 通道1来传输置指定的内部ram中,并且将dma通道一设置成最高优先级,以保证数据准确,并且用dma每次传输的个数来控制采样的深度,例如我要采集 100个点那么就设置dma传输100个次,每次从32位adc转换寄存器传输一个word到ram中,等完成了100次传输后,dma通道自动停止(实际上adc是一直按照要求的采样频率连续在后台采样,只是我去取数据而已),下次采集的时候我只要再设置下采样的个数使能dma channel1就行了。
4、与上位机通讯:通讯也是个难题,要达到快速地将大量数据发给上位机的目的,传输的速率肯定低不了,开始我想先用串口,不过很快就放弃了,一则即使我用外部usb转串口的芯片最高也只能达到1m的速度,并且数据会丢失;后来还是采用了网络传输的方式,用spi 接口的enc28j60芯片,这个芯片我在mega32和at91sam7s64上都用过,接口简单挺方便的,速度还可以,在sam7s64上dma凡是用udp协议单向发送的速度可以达到400kb/s以上,这次用了stm32发现速度大增,经过我用stm32的dma传输后,同样udp协议单向发速度竟然达到了500kb/s以上,甚至最高可以达到600kb/s,这个真是意外的收获。
5、上位机程序:还是用vs2005,我还是喜欢用c#,主要是微软的c#做得是在太舒服了,编辑器智能化程度真高,我只要刚刚输个开头的字母,马上就感知出来一堆让你选择,连挨个敲字符的功夫都省了,还不用担心拼写出错到时候找原因的麻烦,呵呵,缺点就是程序执行时候cpu利用率要高点,什么时候它的c++ 编辑器也到这个程度我就换回c++,哈哈。波形显示还是用ni的measurementstudio8来实现,一个是漂亮方便,另外最要紧的就是 measurementstudio8里面有一大堆数据处理的库,从简单的波形有效值计算,频率计算,到各种各样的函数滤波器功能,还有fft频域分析,时域分析等等,但凡要用到的仪器相关处理里面都有,另外本来我打算要在模拟前端里面加一个相位锁定的电路,以固定显示的波形起点,后来发现 measurementstudio8里面有个peakdetector的类,用这个来实现波形的锁定连这个电路都可以省了。用 measurementstudio8来实现实在是非常方便,并且准确。只是我没啥资料,还在探索当中
显示的界面及部分照片:
数据采样后输出到pc上显示的图形很精确,包括max038产生的正弦波上部的小尖峰也很清楚,stm32的adc精度很稳定性相当好,对于音频范围的低频信号来说,1msps的采样也基本够用了。只要采集足够的点送给measurementsudio提供的函数来分析,可以达到非常精确的程度,12bit 的分辨率相当于数字表的3位半的效果,用来测试信号的频率、真有效值、峰值、峰峰值等等非常方便和精确,和我用硬件实现的频率计和真有效值的读数相同(这也说明了我做的信号发生器的硬件是准确的,哈哈,之前跟数字表总对不上,看来是数字表准确度差),实现完全可以当作低频示波器来用,再加上个模拟前端电路,完全可以实用化了
正弦波:
点击查看图片
上位机的程序:
上位机的程序还处在对于measuremenstudio的摸索当中,只是初步了解到了几个函数,用它来实现数据处理实在是方便,look public void datareceived_proc() //udp数据接收、数据处理、数据显示函数
{
try
{
while (bstates)
{
myudpcomm.receive(ref commreceivebuffer);
received_command = bytes2struct(ref commreceivebuffer);
//textbox3.text = received_command.samplerate.tostring() + (acestimate++).tostring();
dadc1_result = new double[received_command.sampledepth];
dadc2_result = new double[received_command.sampledepth];
//数据处理,将通讯接收区中的adc数据传入绘图用数组中
for (int i = 0; i 《 (int)(received_command.sampledepth); i++)
{
dadc1_result = (bitconverter.touint16(commreceivebuffer, 40 + 4 * (i + 0))) * (3.3 / 4096.0);
dadc2_result = (bitconverter.touint16(commreceivebuffer, 40 + 4 * (i + 0) + 2)) * (3.3 / 4096.0);
}
str = “通道a(绿色)\r\n”;
//测试真有效值
measurements.acdcestimator(dadc1_result, out acestimate, out dcestimate);//交流(ac方式相当于信号通过一个电容隔直后进行测量)和直流(dc直通方式进行测量)真有效值测量
str += “ac方式有效值:” + ((int)(acestimate * 1000)).tostring() + “mv” + “dc方式有效值” + ((int)(dcestimate * 1000)).tostring() + “mv\r\n”;
//测试信号频率、振幅vp
mysingletoneinformationadc1 = new singletoneinformation(dadc1_result, received_command.samplerate);
str += “频率:” + ((int)(acestimate * 1000)==0 ? 0int )mysingletoneinformationadc1.frequency).tostring() + “hz” + “振幅vp:” + ((int )mysingletoneinformationadc1.amplitude*1000).tostring() + “mv\r\n”;
str += “\r\n通道b(红色)\r\n”;
//测试真有效值
measurements.acdcestimator(dadc2_result, out acestimate, out dcestimate);//交流(ac方式相当于信号通过一个电容隔直后进行测量)和直流(dc直通方式进行测量)真有效值测量
str += “ac方式有效值:” + ((int)(acestimate * 1000)).tostring() + “mv” + “dc方式有效值” + ((int)(dcestimate * 1000)).tostring() + “mv\r\n”;
//测试信号频率、振幅vp
mysingletoneinformationadc2 = new singletoneinformation(dadc2_result, received_command.samplerate);
str += “频率:” + ((int)(acestimate * 1000) == 0 ? 0 : (int)mysingletoneinformationadc1.frequency).tostring() + “hz” + “振幅vp:” + ((int)mysingletoneinformationadc1.amplitude * 1000).tostring() + “mv\r\n”;
textbox3.text = str;
//thresholdpeakdetector.analyze用来找出从波谷到波峰上升沿顶点的数组序号
//可以用于固定显示波形从上升沿的某固定点开始,相当与硬件的同步触发电路功能
//b = thresholdpeakdetector.analyze(dadc2_result, 2, 10);
//foreach (int k in b)
//{
//textbox3.text += k.tostring() + “ ”;
//}
//for (int i = 0; i 《 received_command.sampledepth - b[1]; i++)
{
//dadc1_result = dadc2_result[i + b[1]];
}
//textbox3.text += b[b.length - 1].tostring();
//bisudpdatareceived = true;//表示接收到了udp数据,允许进行再次发送
bisdatareadyforplot = true;
mygraphplotproc();//绘图输出*/
//myd1 = new mymethoddelegate(h);
//myd1(1);
}
}
catch (exception e1)
{
timer1.enabled = false;
messagebox.show(e1.tostring());
}
finally
{
timer1.enabled = false;
}
}
/************************************************************************************
* 绘图输出过程函数供,myggraphplotthread进程调用
* 始终循环检测bisdatareadyforplot,一旦为真则进行绘图,绘图完成后置标志为false
* **********************************************************************************/
public void mygraphplotproc()//绘图输出函数
{
//while (true )
{
if(bisdatareadyforplot)
{
waveformplot1.ploty(dadc1_result);
waveformplot2.ploty(dadc2_result);
bisdatareadyforplot = false;
}
}
}
下位机的程序:
下位机的程序,也还在完善,现在只做到了基本的功能,还不稳定,主要问题还是在传输上的,这次为了一次传输比较多的数据,要将udp数据包分解,分成多个小于1518字节的帧发送,因此发现当数据发送快的时候很容易导致数据停止发送,以前用mega32和sam7的时候没注意过,当时的处理速度也慢,没暴露出来,想来想去可能是由于连续发送的时候速度太快导致的冲突,enc28j60出错挂起了,还是enc28j60没有吃透,对于里面的流控、以太网冲突检测这些还需要进一步研究。
/******************** (c) copyright 2007 stmicroelectronics ********************
*stm32f10*** 双通道adc数据采集并通过enc28j60实现udp通讯传输
*作者:alien2006
*环境:keil for arm mdk 3.15b
*版本:v0.2
*时间:20071202
*说明:v0.2
*一、网络通讯部分
*1、先采用stm32 spi轮询方式进行传输试验,ping 192.168.1.100 -l 1400 -n 10
*在轮询方式下未改进spi1_sendbyte()函数(内部直接用st提供的函数语句)需 avg=9ms时间
*轮询方式下将spi1_sendbyte()函数中的4条语句修改为直接寄存器存取后avg提高到7ms
*轮询方式下取消spi1_sendbyte()直接代之以函数中四语句avg提高到6ms
*经过上述的逐步修改,传输udp1400个字符时双向传输(接收1400个字节再发送这1400个字节)间隔4ms可达210kb/s
*2、enc28j60.c修改增加stm32 spi传输dma和非dma编译选项,dma方式下网络最大传输速度测试达到350kb/s
*3、改进了zyp_udp.c实现了当要发送的udp数据长度超过单帧所能容纳时,将udp数据
*自动进行分组,并可在编译时自定义每个分组长度;
*改进了enc28j60.c加入了enc28j60dma空闲和网络发送完毕的判断,解决了当发送速度过快时导
*致传输出错问题。测试单向发送速度超过500kb/s;
*二、stm32数据采集部分
*1、adc1/adc2实现并行同时数据采集,12bit最高可达1msps采样速度并通过stm32的dma传输放入内存中
*2、tim2 cc2实现对adc采样的触发,adc_sample_frequency_set函数实现自定义tim2 oc2频率输出,
*3、采样的频率和采样个数通过接收到的udp控制命令来指定
*采样的频率为20hz~1mhz;
*采样深度为1~4000个数据(受限于stm32内存20kb容量,一个数据为2个12bitadc通道读数,需一个word)
*4、定义了简单的udp控制命令结构,用于实现与pc通讯和控制采样频率和采样深度
*三、其他
*1、程序待解决问题:udp分组发送出错问题未完全解决,有待进一步解决
*2、期待增加模拟前端电路,并实现放大倍数程控,通过上位机程序可以设置
*
* v0.1:最初程序,实现简单固定频率和深度的并行adc采样和udp通讯,并编制了简单的上位机程序,
*可以进行采样波形的显示
检查与预防PCB电路板短路的6个方面详解
CDN到底有多重要,电商网站服务器为什么需要它
天马前三季度OLED出货暴涨300%
工业机器人周边运动控制部分有哪些?
用氮化镓消除激光雷达的障碍
基于STM32内置ADC实现简易示波器的程序设计与实现
OPPO即将进入智能电视行业 首款电视产品将在今年下半年正式发布
振弦传感器、振弦采集仪及在线监测系统的岩土工程监测案例
机器人产业关键的市场驱动力及未来五年的发展和部署
NokiaX6评测 充分展示诺基亚放手一搏的姿态
视频格式转换神器,万兴优转:支持超过1000种格式转换
关于Q1动力电池装机电量的解析
ptn技术优势
digilentUSB转UART接口介绍
3D NAND技术的应用发展趋势
程控开关模块使用的继电器类型与特点
数字媒体的标杆——触摸一体机
比特币不会取代法定货币但它也不会消失
小米11系列的亮点一览
太阳能光伏企业清源科技荣获厦门市龙头骨干民营企业