×

基于Arduino的双通道示波器

消耗积分:2 | 格式:zip | 大小:0.01 MB | 2023-02-03

张燕

分享资料个

描述

我制作了 2 种不同的示波器,这些都在这个平台上有特色。现在我想到了双通道示波器。这个有主要的微控制器作为 Arduino 和1.3" OLED 显示器。这次我还有电池操作选项和板载充电威廉希尔官方网站 。您可以先在面包板上制作它,然后使用下面给出的 PCB 布局。非常感谢 JLCPCB赞助这个双通道 Arduino 示波器项目。

mini_20220320_113232_yVRzn4MTQW.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

这不仅是范围,还有 DDS_PWM(具有 8 种不同波形的函数发生器)、脉冲发生器和频率计数器的一些额外功能。我在日语网页上找到了这个项目,但所有的解释都在这里给你们看。

特征:

最大实时采样率为 17.2ksps(2 个通道)和 307ksps(一个通道)。单通道最大等效时间采样率为 16Msps。

20220320_111601_VVX5aHKUM7.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

单通道-30Khz带宽

屏幕 - 伏特/格和时间/格

占空比监控

小型 1.3 英寸 I2C

交流/直流测量选项

模式改变,保持状态功能

双通道切换模式

脉冲发生器选项

DDS_PWM波形发生器

频率计数器

低电池消耗

便携式和袖珍型

重要的提示:

该项目仅用于教育目的,展示了 16Mhz 8 位微控制器板的功能。此 MCU 可支持 50KHz 以下的频率,因此不适用于商业和专业用途。这样,该项目也可以为我命名为 POOR MAN OSCILLOSCOPE。我还发现这对下面与音频相关的项目很有帮助。

展示:

mini_20220320_112957_mcMp7Ayn5U.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

1.3寸OLED显示屏带I2C功能,有SSD1306和SH1106两种不同型号,可根据需要改码。我们必须取消注释我们在这个项目中使用的是哪个版本的 LCD。并且屏幕能够在两个通道中用占空比和频率来表示波的性质。

使用的组件:

阿杜诺纳米

1M电阻

10k电阻

1.3英寸OLED显示屏

100nF 电容

4个触觉按钮

5v电源

威廉希尔官方网站 图:

ice_screenshot_20220320-225332_BzZ0cwGm1i.png?auto=compress%2Cformat&w=740&h=555&fit=max

与往常一样,这是图示威廉希尔官方网站 ,我将威廉希尔官方网站 最小化为一个通道的操作。如果您想使用两个通道,只需按照下面给出的主威廉希尔官方网站 图进行操作即可。

非常感谢“ Cirkit designer ”软件,证明它是一个以图形格式呈现威廉希尔官方网站 和布线的好工具。对于新手或学生来说,这将是一种更容易理解的方法。

目前,cirkit designer 对所有人免费提供(从此处下载),因此没有理由不利用此优惠。作为回顾,我发现这对我的项目非常有帮助。该软件的一些特殊功能是:代码编译、BOM 管理器、面包板和自定义组件创建。

威廉希尔官方网站 图:

ice_screenshot_20220322-120530_buiTKLAUX1.png?auto=compress%2Cformat&w=740&h=555&fit=max

1 / 2 •双通道简化示意图

威廉希尔官方网站 说明:

 

Pin usage
A0 oscilloscope probe ch1
A1 oscilloscope probe ch2
A4 I2C SDA
A5 I2C SCL
D3 PWM output for trigger level
D4 Up button
D6 trigger level input
D8 Down button
D9 Right button
D10 Pulse generator output
D11 PWM DDS output
D12 Left button

 

这种小型示波器可以使用 5volts @200mA 供电。您可以在上面看到两个不同的威廉希尔官方网站 ,两者都很好,但我制作的威廉希尔官方网站 经过简化并且在所有情况下都最有用。您可以根据自己的情况修改威廉希尔官方网站 。

看看示波器中那些漂亮的波浪就知道了。

square_380hz_noCLB8Z73B.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

1 / 4 •方形 380HZ

这次威廉希尔官方网站 还具有外部频率测量和 PWM、DDS 脉冲输出选项,具有 2 个通道。4 触觉按钮在下拉时触发。所有的电阻都是为了适当的baising。作为一项改进,您可以制作威廉希尔官方网站 的 PCB 布局,并以 2 美元的价格从JLCPCB订购它们。顺便说一句,如果你想使用我的,下面给出你可以下载。使用我的链接注册将为您提供 PCB 优惠券作为原型 SMT 服务的奖励。为什么不免费使用价值 27 美元的优惠券。

探索菜单:

完整菜单比以前的 arduscope 项目有更多的选项。然而,我没有得到大屏幕。可能下次我会使用 TFT 和 mega2560 板构建一个。

通道切换选项:

不使用时关闭第二个通道,因为这也会增加采样率。

电压读数:

还将显示信号的最大值和最小值,称为幅度。

电压/分区:

时间/部门:

代码:

我得到了十六进制格式的代码,但确认在 INO Arduino 文件中有一些支持文件。我得到了这些支持文件的 Arduino INO 代码。一旦我得到完整的代码,我会分享,你会自己改变它。HEX 文件仍然正常工作。如果您不知道如何使用 HEX文件对 Arduino 进行编程,请查看本教程。从这里下载这个项目的代码。

频率计数器:

 

//int dataMin;                   // buffer minimum value (smallest=0)
//int dataMax;                   //        maximum value (largest=1023)
//int dataAve;                   // 10 x average value (use 10x value to keep accuracy. so, max=10230)
//int dataRms;                   // 10x rms. value

void dataAnalize() {                       // 波形の分析 get various information from wave form
  long d;
  long sum = 0;
  byte *waveBuff = data[sample+0];

  // search max and min value
  dataMin = 255;                          // min value initialize to big number
  dataMax = 0;                             // max value initialize to small number
  for (int i = 0; i < SAMPLES; i++) {     // serach max min value
    d = waveBuff[i];
    sum = sum + d;
    if (d < dataMin) {                     // update min
      dataMin = d;
    }
    if (d > dataMax) {                     // updata max
      dataMax = d;
    }
  }

  // calculate average
  dataAve = (10 * sum + (SAMPLES / 2)) / SAMPLES;  // Average value calculation (calculated by 10 times to improve accuracy)

  // 実効値の計算 rms value calc.
//  sum = 0;
//  for (int i = 0; i < SAMPLES; i++) {     // バッファ全体に対し to all buffer
//    d = waveBuff[i] - (dataAve + 5) / 10;  // オーバーフロー防止のため生の値で計算(10倍しない)
//    sum += d * d;                          // 二乗和を積分
//  }
//  dataRms = sqrt(sum / SAMPLES);          // 実効値の10倍の値 get rms value
}

void freqDuty() {                               // 周波数とデューティ比を求める detect frequency and duty cycle value from waveform data
  int swingCenter;                              // center of wave (half of p-p)
  float p0 = 0;                                 // 1-st posi edge
  float p1 = 0;                                 // total length of cycles
  float p2 = 0;                                 // total length of pulse high time
  float pFine = 0;                              // fine position (0-1.0)
  float lastPosiEdge;                           // last positive edge position

  float pPeriod;                                // pulse period
  float pWidth;                                 // pulse width

  int p1Count = 0;                              // wave cycle count
  int p2Count = 0;                              // High time count

  boolean a0Detected = false;
  //  boolean b0Detected = false;
  boolean posiSerch = true;                     // true when serching posi edge

  swingCenter = (3 * (dataMin + dataMax)) / 2;  // calculate wave center value

  for (int i = 1; i < SAMPLES - 2; i++) {      // scan all over the buffer
    if (posiSerch == true) {   // posi slope (frequency serch)
      if ((sum3(i) <= swingCenter) && (sum3(i + 1) > swingCenter)) {  // if across the center when rising (+-3data used to eliminate noize)
        pFine = (float)(swingCenter - sum3(i)) / ((swingCenter - sum3(i)) + (sum3(i + 1) - swingCenter) );  // fine cross point calc.
        if (a0Detected == false) {              // if 1-st cross
          a0Detected = true;                    // set find flag
          p0 = i + pFine;                       // save this position as startposition
        } else {
          p1 = i + pFine - p0;                  // record length (length of n*cycle time)
          p1Count++;
        }
        lastPosiEdge = i + pFine;               // record location for Pw calcration
        posiSerch = false;
      }
    } else {   // nega slope serch (duration serch)
      if ((sum3(i) >= swingCenter) && (sum3(i + 1) < swingCenter)) {  // if across the center when falling (+-3data used to eliminate noize)
        pFine = (float)(sum3(i) - swingCenter) / ((sum3(i) - swingCenter) + (swingCenter - sum3(i + 1)) );
        if (a0Detected == true) {
          p2 = p2 + (i + pFine - lastPosiEdge); // calucurate pulse width and accumurate it
          p2Count++;
        }
        posiSerch = true;
      }

 

脉冲发生器:

 

void dataAnalize() {                       // 波形の分析 get various information from wave form
  long d;
  long sum = 0;
  byte *waveBuff = data[sample+0];

  // search max and min value
  dataMin = 255;                          // min value initialize to big number
  dataMax = 0;                             // max value initialize to small number
  for (int i = 0; i < SAMPLES; i++) {     // serach max min value
    d = waveBuff[i];
    sum = sum + d;
    if (d < dataMin) {                     // update min
      dataMin = d;
    }
    if (d > dataMax) {                     // updata max
      dataMax = d;
    }
  }

  // calculate average
  dataAve = (10 * sum + (SAMPLES / 2)) / SAMPLES;  // Average value calculation (calculated by 10 times to improve accuracy)

  // 実効値の計算 rms value calc.
//  sum = 0;
//  for (int i = 0; i < SAMPLES; i++) {     // バッファ全体に対し to all buffer
//    d = waveBuff[i] - (dataAve + 5) / 10;  // オーバーフロー防止のため生の値で計算(10倍しない)
//    sum += d * d;                          // 二乗和を積分
//  }
//  dataRms = sqrt(sum / SAMPLES);          // 実効値の10倍の値 get rms value
}

void freqDuty() {                               // 周波数とデューティ比を求める detect frequency and duty cycle value from waveform data
  int swingCenter;                              // center of wave (half of p-p)
  float p0 = 0;                                 // 1-st posi edge
  float p1 = 0;                                 // total length of cycles
  float p2 = 0;                                 // total length of pulse high time
  float pFine = 0;                              // fine position (0-1.0)
  float lastPosiEdge;                           // last positive edge position

  float pPeriod;                                // pulse period
  float pWidth;                                 // pulse width

  int p1Count = 0;                              // wave cycle count
  int p2Count = 0;                              // High time count

  boolean a0Detected = false;
  //  boolean b0Detected = false;
  boolean posiSerch = true;                     // true when serching posi edge

  swingCenter = (3 * (dataMin + dataMax)) / 2;  // calculate wave center value

  for (int i = 1; i < SAMPLES - 2; i++) {      // scan all over the buffer
    if (posiSerch == true) {   // posi slope (frequency serch)
      if ((sum3(i) <= swingCenter) && (sum3(i + 1) > swingCenter)) {  // if across the center when rising (+-3data used to eliminate noize)
        pFine = (float)(swingCenter - sum3(i)) / ((swingCenter - sum3(i)) + (sum3(i + 1) - swingCenter) );  // fine cross point calc.
        if (a0Detected == false) {              // if 1-st cross
          a0Detected = true;                    // set find flag
          p0 = i + pFine;                       // save this position as startposition
        } else {
          p1 = i + pFine - p0;                  // record length (length of n*cycle time)
          p1Count++;
        }
        lastPosiEdge = i + pFine;               // record location for Pw calcration
        posiSerch = false;
      }
    } else {   // nega slope serch (duration serch)
      if ((sum3(i) >= swingCenter) && (sum3(i + 1) < swingCenter)) {  // if across the center when falling (+-3data used to eliminate noize)
        pFine = (float)(sum3(i) - swingCenter) / ((sum3(i) - swingCenter) + (swingCenter - sum3(i + 1)) );
        if (a0Detected == true) {
          p2 = p2 + (i + pFine - lastPosiEdge); // calucurate pulse width and accumurate it
          p2Count++;
        }
        posiSerch = true;
      }
    }

 

从这里下载代码文件,目前为十六进制格式。要在 Arduino 中上传十六进制文件,请参阅我们之前的教程。

威廉希尔官方网站 板文件:

ghdg_ZQDvB38xfE.png?auto=compress%2Cformat&w=740&h=555&fit=max

感谢积联威廉希尔官方网站 和EasyEda赞助并生成了如此优质的PCB 原型。订购过程也很简单,如下所示。

下载我的 Gerber 文件,转到 JLCPCB,然后选择厚度颜色参数,只需 2 美元即可订购 5 个 pcb。

测量:

这里的大问题是获得正确的频率,正如我所说,最好先使用音频频率。所以我将它与在线音调生成器工具配对。这将使我们能够检查精度以及不同的波形。

此处显示了不同频率下的正弦波测量值。

1_HtmffATKL1.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

1 / 2

测量 2:

3_cfSuPBK40d.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

1 / 2

测量3:

5_WorKlrvMax.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

1 / 2

观察:

8k_8m5DysuPuo.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

回到最大频率和振幅,它能够以 5Khz 的最大频率测量高达 50v 的电压。是的,波在这个频率以上是扭曲的。

下一个更新:

mini_wer_FayxNNPIV5.jpg?auto=compress%2Cformat&w=740&h=555&fit=max

下次我们将返回一个更大的微控制器 (2560),也许还有一个 TFT 屏幕。顺便说一句,这是我上一个 Arduscope 项目的链接,该项目支持高达 10khz 频率的 1 通道和Raspberry pi Pico 项目,模拟信号带宽为 200Khz。再次感谢 JLCPCB。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'基于Arduino的双通道示波器',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);