通过C#和Arduino实现软件示波器


前言

  对于电子爱好者来说,示波器是一件不可或缺的神器。有了示波器的帮助,我们可以根据信号的实际变化来判断我们的电路或单片机程序的正确性。在有错误发生时,通过示波器我们也可以更容易的分析问题的产生点。

  但我们有没有想过,示波器本身就是一个电子电路,它的结构如何,又是如何工作的?作为一个电子电路的爱好者,我们是否可以搭建一个属于自己的示波器呢?下面作者就来通过Arduino作为信号采集电路来实现一个软件示波器。


一、作者对示波器的部分理解

  示波器,顾名思义是一个将信号的波形进行显示的仪器设备。最基本的示波器实际上只需要两个部分——1信号采集、2图像输出。我们直接对信号进行采集,然后将原始信号在屏幕上进行输出这本身已经是一个示波器了。

  但是如此简陋的示波器存在着巨大的问题:一方面,原始信号如果幅值很大或者很小,那么就会出现信号在屏幕上无法正常显示的问题——比如幅度很小的信号在屏幕上也许只是一条笔直的直线;另一方面,如果单纯的将各种信号进行连续的采集并展现在屏幕上,那么对于变化速度极高的信号我们肉眼很可能观看不到任何稳定的信号,只会觉得屏幕上的信号在不断的闪烁。
  要解决上面说到的两个问题,我们就需要对原始示波器的功能进行扩展。一方面,为了解决信号幅值的问题我们应当引入幅值调节;另一方面,为了解决高频率信号的显示问题我们应当引入触发功能

二、软件示波器

  我们在市场上购买的示波器一般是硬件示波器,它从硬件上包含了一台示波器应该具备的完整功能——信号的采集、处理、显示。

  硬件示波器有着完整的硬件结构,使得其成本相对较高。对于我们自己制作示波器而言,为了节约成本,可以选择软示波器——即采用硬件对信号进行采集,而对信号的处理和显示通过软件功能在电脑上进行实现。

  软件示波器,正如前文所提可以分为两个大的部分——一部分是基于电子电路的信号采集部分;另一部分是基于软件的信号处理和显示功能。

  而如果对整个流程进行描述,则是电子电路对原始信号进行采集(ADC),之后通过通信将采集到的数据发送给计算机里运行的软件。软件在接收到原始信号的数值后,对其幅值进行处理,并根据我们设定的触发方式将信号图形显示到图像区域,如下图。
在这里插入图片描述

三、软件示波器的实现

采集部分

  信号采集电路使用STM32F103C8T6最小系统作为基础硬件,通过它所自带的ADC功能来完成信号的采集。采集之后,则通过串口通信将采集到的原始信号传输给我们的软示波器软件。

  当然,也可以通过其它的电路及开发方式以相同的思路来实现这些功能。(如果你需要将手中的STM32F103C8T6配置为Arduino的开发方式,可以参照这篇文章STM32duino——依托Arduino框架玩转STM32(一): 开发环境的配置

第一种方式

  在采集和传输方式上,我们有两种选择:一种是,我们可以选择让Arduino每次采集一个ADC的值,然后通过串口传输,传输完成后再进行下一次的采集。采用这种方式,在编程上是极为简单的,但是在串口传输后再进行下一次的采集将导致采样的频率降低,使得我们无法采集到一些变化较快的信号。

  例如下图中,上半部分黑色实线是我们的原始信号,细点画线是采集发生的时刻;下半部分的点为对应的采集值。我们可以很容易的发现,对于变化频率较低的信号我们的采样基本可以正确的描述其原始状态,但是对于原始图形中出现的尖峰毛刺我们可能会不能正确的对其捕捉。

在这里插入图片描述

第二种方式

  另一种方式则是:连续的进行ADC采集,将采集到的数据存储于单片机的存储区,在存储区域满后进行连续的串口发送。采用这种方式的优点是提高了信号采集时的采集频率,可以将更高频率的信号变化采集出来。

  但这种方式也存在自己的缺点,就是采集是间歇性的,即连续的采集——连续的发送——连续的采集(如果采用STM32原生的DMA传输方式可以最大程度减小这种采集的不连续,但这不在我们此次的讨论范围之内)。第二种方式的采集效果可以参照下图,我们很容易的发现高频的毛刺信号可以被采集到了,但是由于传输阶段的存在,采集变得不再连续。
在这里插入图片描述

本次的选择

  咱本次的软示波器制作中,我们先采用第一种方式进行。但如果使用STM32的原生开发模式,更推荐使用DMA的方式来实现第二种采集方式,并将信号触发的功能也在单片机端实现,以实现示波器最佳的性能!!!

Arduino对模拟量的读取和传输

  Arduino中的代码相当简单。我们先声明一个int变量an用于存储每次模拟量读取的值,然后再setup中声明PA0引脚的工作模式为INPUT(输入模式,含数字量读取和模拟量读取),之后开启串口,并选择9600这个中规中矩的波特率。实际上波特率越高对于模拟示波器来说性能越好,当然也会带来一些问题。在此我们先选择9600这个中规中矩的波特率。

int an;

void setup() {
  pinMode(PA0,INPUT);
  Serial.begin(9600);
}

void loop() {
  an=analogRead(PA0);
  Serial.println(an);
  delay(1);
}

  之后,在Arduino程序的Loop中,我们依次进行模拟量的读取,串口的模拟量值传输,以及1ms的延时。就此,Arduino端的配置就完成了,当你把程序下载到电路板中后,打开Arduino的串口监视器你会看到一系列变化的数字——即PA0脚的模拟量电压(对于STM32F103来说3.3V对应4095),就像下图。
在这里插入图片描述

PC端程序

  在完成了Arduino的配置并能够正常的发送读取的模拟量之后,我们便可以开始PC端程序的设计了。PC端程序从功能上来说主要有三个部分,分别是:1串口读取、2数据处理和触发判断、3绘图。在有了这三部分的功能后,程序即可接收到电路板发出的模拟量数值,然后经过处理最终显示在屏幕上。

界面设计

  针对我们所需要的功能,界面上设计了串口的操作区域——包含串口的选择以及连接、断开操作。设计了触发和扫描方式操作区域,通过这个区域我们可以选择单次扫描(扫描一页图像后停止,在实际的示波器上我们通常用这个功能抓取要分析的信号流)、连续扫描,并设置扫描的触发方式和触发阈值。还加入了一个pictureBox用于显示扫描到的图像结果。

最终的界面设计如下:
在这里插入图片描述

串口读取

  在串口读取部分,我们除了对串口的波特率、较验方式、数据位和停止位进行设置外,最重要的就是绑定串口的接收事件sp.DataReceived += getValue。如此一来,每当电脑的串口接收到电路板发来的模拟量数据,便会触发getValue来进行处理。getValue会读取一行串口数据,然后将数据从字符串转换为int形式,并通过changeValue1来传递到主程序的value中(因为getValue被触发时是在单独的线程中活动的,对于跨线程的内容更改必须通过委托的形式)。

                sp.PortName = comboBox1.Text;//设置端口
                sp.BaudRate = 9600;//设置波特率
                sp.Parity = Parity.None;//设置校验
                sp.DataBits = 8;//设置数据位
                sp.StopBits = StopBits.One;//设置停止位
                sp.DataReceived += getValue;//绑定接收事件处理
                sp.Open();//打开串口
        private void getValue(object obj, SerialDataReceivedEventArgs e)
        {
            string tmp=sp.ReadLine();
            try
            {
                int tmp2 = int.Parse(tmp);
                changeValue1(tmp2);
            }
            catch (Exception)
            {

            }
        }
        private void changeValue1(int v)
        {
            if (InvokeRequired)
            {
                D1 d = new D1(changeValue1);
                this.Invoke(d, v);
            }
            else
            {
                value = v;
            }
        }

数据处理和绘图

  当扫描开始进行后,我们会开启一个单独的扫描线程,由改线程来进行数据的处理和绘图,以防止主界面的阻塞。

		th1 = new Thread(new ThreadStart(scan));//否则进行连续扫描
		th1.Start();

  扫描线程通过Sleep的方式控制两次采集的间隔,以此来达到水平缩放的目的。需要注意的是,实际的示波器的采集间隔是通过单片机定时器中断实现的。在我们的虚拟示波器中,这个功能实际上很不好用——因为我们的最高扫描速度本来就不快,已经没有缩放的必要了。这里依然做出此功能是为了让大家理解实际示波器的工作方式。

  由于在C#的pictureBox中,图像的Y坐标越大图像反而越低,所以我们采用600-valuev_mul600/4096这种方式来对图像进行垂直方向的颠倒。其中,600是我们的pictureBox的高度。

  之后我们通过Graphics对象来将读取到的所有点以直线的方式连续的画到画布(Bitmap)上,并通过changePic将pictureBox的图像内容变为我们的画布,由此完成图像的输出。

            while (true)
            {
                Thread.Sleep(h_mul);//通过延时来实现水平坐标的缩放功能,当h_mul越大,两次取点的间隔越大,实现了图像水平的缩小。在硬件示波器上,也是这样的原理,只是通过时钟中断来控制扫描取点的间隔
                values_tmp[count] = 600-value*v_mul*600/4096;
                count++;
                count2++;
                if (count == 1000)
                {
                    count = 0;
                }
                if (count2>1000)
                {
                    count2 = 1000;
                }
                bmp_tmp = new Bitmap(1000, 600);//创建新的画布
                g = Graphics.FromImage(bmp_tmp);//创建绘画对象
                for (int i = 1; i < count2; i++)//进行绘画
                {
                    g.DrawLine(p, new Point(i - 1, values_tmp[i - 1]), new Point(i, values_tmp[i]));//将每个采集点进行直线绘画
                }
                changePic(bmp_tmp);//更新显示的图像

            }

最终的效果

  打开程序,对串口进行连接,并开启扫描,便可以对PA0端口的电压进行采集并对波形绘图了。
在这里插入图片描述

源码

虚拟示波器的C#程序源码

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Arduino示波器是一种使用Arduino板和相关软件实现基本示波器功能的设备。它可以通过连接模拟信号发生器件到Arduino的模拟输入通道,实时读取和采集输入信号,并使用相关的软件(例如Processing或LabVIEW)将信号以图形方式显示出来。示波器可以帮助用户观察和分析信号的波形、频率、振幅等特性,对于电子实验和测试测量具有很大的帮助作用。Arduino示波器可以通过编写相应的程序来实现不同的功能,如多通道显示、触发设置、时间分辨率和电压幅度分辨率的调整等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [《Arduino开发实战指南:LabVIEW卷》6.3 基于Arduino的简易示波器](https://blog.csdn.net/jxgy01/article/details/118550752)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [四通道Arduino示波器.zip](https://download.csdn.net/download/qq_42821531/12335194)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

soar3033

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值