原创 用STM32内置的1MspsADC进行数据采样,并通过ENC28J60以太网接口发送到PC上波形显示

2008-5-13 14:31 4662 8 16 分类: 测试测量
几周来学习STM32的阶段性成果:用STM32内置的1MspsADC进行数据采样,并通过ENC28J60以太网接口发送到PC上波形显示,实现低频示波器功能,在这里特别感谢下GRANT兄:)

--------------------------------------------

    做一个数字采样示波器一直是我长久以来的愿望,不过毕竟这个目标难度比较大,涉及的方面实在太多,模拟前端电路、高速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采样的示波器!
    说来也真是幸运,得到了GRANT兄相赠的STM32F103VB以及评估版的电路板,这些日子一直在学习STM32,不断地做实验,也算是稍微有点入门了,真是了解越多越喜欢这个芯片,呵呵。

    想来这个论坛上对数据采样以及数字示波器感兴趣的朋友很多,下面我简单描述下实现方式,发帖也跟大家分享下我的喜悦:)
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;
                }
            }
        }


保护版权哈


http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=862510&bbs_page_no=1&search_mode=1&search_text=示波器&bbs_id=9999

文章评论8条评论)

登录后参与讨论

用户377235 2014-3-12 20:17

学习中楼主能否发我一份呢 798238495@qq.com

用户377235 2014-3-12 20:14

楼主你好我也在学ADC 转 以太网 传到PC不过我现在只想将数据穿到PC 用网口助手观测数据。请问能不能把程序发我一份呢

用户377235 2012-11-24 14:10

很好。楼主可否发我一份程序?ztj18130@163.com

jizzll_617398179 2008-5-21 22:16

谢谢

用户149535 2008-5-20 00:21

这个还可以

jizzll_617398179 2008-5-18 23:52

谢谢哈

用户394922 2008-5-17 20:55

支持哈

用户137602 2008-5-13 18:28

很好很强大,有图片
相关推荐阅读
jizzll_617398179 2010-02-08 10:53
正确理解A/D转换器的输入
http://www.freescale.com.cn/tech_ariticles/2005/1102_1.asp 许多嵌入式应用都会用到A/D转换器。然而,如果错误连接了A/D转换器输入端的电路,...
jizzll_617398179 2010-01-12 13:37
好久没来,都长草了
好久没来,都长草了,呵呵。整天忙得很,不过估计再过两个月会轻松点~\(≧▽≦)/~啦啦啦...
jizzll_617398179 2009-03-16 21:57
很奇怪,我收到站内信,但是却找不到发信人呢
发信人是个[],点击就跳到我自己的主页了。只好在这里给那位朋友留言了。 我不知道你说的哪篇文章,还有我也不知道你的EDN的ID。你可以在博客上面留言的。...
jizzll_617398179 2009-03-14 13:08
如何在EXCEL中使用16进制数
最近需要计算串口发送的数据,太多而且比较麻烦。知道EXECL功能强大,所以网上找了找,刚好,不错,很方便。网上找到的http://hi.bccn.net/space-99452-do-blog-id-...
jizzll_617398179 2009-03-05 14:37
〖常识〗不同晶振的最大波特率及其误差
最近犯了个错误,呵呵,晶振和波特率的问题,特查了记在这里,O(∩_∩)O~〖常识〗不同晶振的最大波特率及其误差http://www.aoxue.org/bbs/read.php?tid=65585不同...
jizzll_617398179 2009-02-11 14:30
大端模式和小端模式
转载http://www.cnblogs.com/TsuiLei/archive/2008/10/29/1322504.html大端格式:在这种格式中,字数据的高字节存储在低地址中,而字数据的低字节则...
我要评论
8
8
关闭 站长推荐上一条 /2 下一条