×

一种配置任意数量开关的方法

消耗积分:0 | 格式:zip | 大小:0.03 MB | 2022-10-28

李玉鑫

分享资料个

描述

背景和起源

在本文中,我介绍了一种配置任意数量的开关的方法,这些开关链接到单个(公共)中断服务例程 (ISR)。该方法完全是软件驱动的,不依赖于开关的任何物理接线来中断引脚。

这篇文章源于之前开发一个库的工作,该库可以有效地处理任何类型的开关并以不同的方案连接 - ez_switch_lib.

总而言之,它ez_switch_lib 提供了一些有趣且独特的功能:

  • 可以配置任何开关类型,例如按钮、拨动开关等
  • 支持常见的开关接线方案
  • 可同时配置多个不同类型和接线方案的开关
  • 开关去抖动会自动处理,这也可以由用户配置
  • 可以随时测试开关的状态,例如测试开关是否处于转换状态、打开或关闭等
  • 开关可以自动链接到其他数字输出引脚,以便在发生切换时也触发链接的输出引脚(设置或清除)

本文重点介绍的正是后者,将开关链接到其他数字输出引脚,并以此为基础。

将开关链接到中断

本文展示了我们如何能够轻松地将任意数量的、任何类型的、以不同方案接线的开关链接(关联)到中断或任何额外的接线 - 没有电线将开关连接到中断!

为了使示例简单,我们将使用单个 ISR 来处理所有开关,但这是可变的 - 同样,我们可以根据需要使用任意数量的 ISR 和外部中断引脚(当然,要达到微控制器的设计限制)。

那么,我们如何做到这一点呢?

如上所述,该ez_switch_lib 库提供了一个特定功能,允许将开关链接到数字输出引脚,以便在启动开关时自动设置/清除相关的输出引脚。这个函数被调用link_switch_to_output 并且只有三个参数:

  • 数字输出引脚要链接到的开关的 ID
  • 要链接的数字输出引脚的引脚号
  • 链接输出引脚的初始设置(即 LOW 或 HIGH)

一旦声明/定义了开关,就可以使用上述功能将其与数字输出引脚相关联。这是该方法的精髓——我们需要做的就是定义一个 ISR,使用该attachInterrupt 函数来处理任何合适的外部中断数字引脚上的开关事件。

我们将看到我们如何能够声明许多不同类型的开关,并以不同的方式连接,但这样每个开关在启动时都会自动触发一个定义的和常见的 ISR。此 ISR 处理开关的作用不在本文的范围内,但读者将看到 ISR 中存在各种“钩子”的位置,并草绘添加特定的最终用户代码来处理每种可能的开关中断事件类型。

让我们看一下示例草图及其配置的开关。

示例草图将使用七个数字引脚,六个用于开关,一个用于公共中断引脚,根据下表分配和接线:

pYYBAGNYtJ6APm91AADkJ2DUs3Y010.png
开关配置
 

(使用面包板按照上表和下图连接组件。)

需要注意的是:

  • 我们使用数字引脚 2 作为分配给 ISR 的公共引脚,观察该引脚没有任何物理连接
  • ' circuit_C1' 和 ' circuit_C2' 是ez_switch_lib库中的保留字,分别代表一个带有外部 10k ohm 下拉电阻的威廉希尔官方网站 和一个基本威廉希尔官方网站 (除了开关本身没有额外的组件)

我们将数字引脚 3-8 分配给开关,如下所示:

  • 3 个与下拉 10k 欧姆电阻器相连的拨动开关 - ' circuit_C1'(参见下面的示意图)
  • 3 x 按钮开关直接接线,' circuit_C2'(参见下面的示意图)
  • 所有开关都是软件链接到一个公共数字引脚 2(ISR 引脚),link_switch_to_output在每个开关创建后使用该函数(add_switch 函数)

上述开关配置是任意的,用于展示ez_switch_lib库的灵活性,开关可以链接到单个 ISR,但可以使用任何组合开关类型、开关威廉希尔官方网站 布线和多个 ISR。

素描设计

草图有六个主要部分:

  • ez_switch_lib声明-ez_switch_lib库的声明(即#include "ez_switch_lib.h")。要运行草图,您需要将ez_switch_lib库文件(.cpp、.h 和 .txt)复制到 Arduino 库目录到名为“ ez_switch_lib”的目录中,即../Arduino/libraries/ez_switch_lib(请参阅ez_switch_lib文章以访问和下载这些文件)。
  • create instance - 创建和建立大小等于我们希望配置的交换机数量(这里是六个)的库实例。草图为我们用来为所有功能和资源添加前缀的实例分配名称'',例如' '等。 ez_switch_libez_switch_libmy_switchesez_switch_lib my_switches.add_switch(..)
  • 定义交换机配置数据- 定义我们的交换机配置的数据。草图的核心是开关配置数据,它保存在一个名为 ' ' 的二维数组中,每一行定义与每个开关关联的数据,如下所示: my_switch_data
column[0] - 表示开关类型(' button_switch' 或 ' toggle_switch')。(同样,' button_switch' 或 ' toggle_switch' 是ez_switch_lib库保留字并定义所考虑的开关类型。)
column[1] - 这是分配给开关的数字引脚
column[2] - 表示开关接线方案(保留字' circuit_C1'或' circuit_C2')
  • setup 函数——你会注意到,这是我们使用该add_switch函数将每个开关声明到库的地方,并将公共中断引脚分配给每个开关(link_switch_to_output函数)。
  • 主循环处理在检查时,主循环似乎根本没有做太多事情——它只是使用该read_switch 函数不断地轮询每个开关,寻找状态变化。这是因为该方法完全是软件驱动的,因此需要不断地寻找状态变化。当状态改变发生时,会发生两件事:
1. 开关相关联的输出引脚(公共中断引脚)自动升为高电平(RISING),从而触发 ISR,该 ISR 将处理致动开关的开关事件,并且
2. 完成 ISR 处理后,该read_switch函数将返回一个值 ' switched'(也是一个保留的ez_switch_lib 库字),如果需要,该值可以在主循环中进一步处理 - 两口相同的樱桃!
  • 中断服务程序 (ISR) - 一个相当简单的 ISR,旨在使用可用变量识别不同的开关类型及其相关特性。ez_switch_lib 您会注意到 ISR 只是向串行监视器报告触发了哪个开关事件。在一般情况下,不推荐使用串行打印 I/O,这里使用它只是为了提供视觉确认,即草图正在做它应该做的事情。根据您的项目需要,在每个“挂钩”处添加您自己的最终用户代码。

好的,它是如何工作的?

ez_switch_lib 消除了我们对开关弹跳或开关接线方式的任何担忧。它还可以为我们提供有关开关的非常有用的状态信息,例如开关类型、开关是否正在转换或已转换或其他情况、拨动开关当前是打开还是关闭等。但最重要的是,它为我们提供了能够自动将开关链接到另一个数字输出引脚,当相关开关被启动时,我们可以使用它来触发 ISR。

现在,在我们的示例草图中,每个声明的开关触发相同的 ISR,所以问题是 ISR 如何确定哪个开关已启动,即哪个开关触发了 ISR?再次,ez_switch_lib 迎合这个。它提供最后一个启动的开关的开关 ID。正是这一特性为 ISR 提供​​了处理正确切换的方法。特定的库变量称为“ last_switched_id”。

有了这些知识,ISR 就可以处理驱动开关的特定要求。

都好?是的,只要您认识到按钮和拨动式开关各有其自己的特征,ISR 也必须满足这些特征。具体来说:

按钮式开关- 在可以说已完全切换之前,驱动周期会从关闭再返回关闭。
拨动式开关- 拨动开关有两个驱动周期 - 它们可以从关闭或开关转换。

同样,ez_switch_lib 允许这些特定的开关特性,为最终用户(和 ISR)提供适当处理每种事件类型的方法。

当您检查 ISR 代码时,您将看到它如何具体而简单地处理上述场景。

此外,我们不要忘记,虽然 ISR 将处理开关驱动,但还有一个额外的点可以应用进一步的处理。如果您检查主循环,您将看到每个开关都被直接和不断地轮询和读取。正是这种对开关的轮询允许触发开关的 ISR。但是,每次触发开关 ISR 时,开关本身也将被视为已启动 (' switched')。如果开关已启动,则轮询循环中函数的答案read_switch将显示为 ' '。switched因此,如果需要,或者如果开关没有链接的 ISR 输出引脚,它提供了在主轮询循环中添加进一步开关处理的额外机会。

谁说我们不能吃蛋糕?!!

最后

我希望你对这篇文章感兴趣,并且值得为你自己的项目考虑。我确实建议您更全面地浏览ez_switch_lib 这篇文章并下载其用户指南婴儿床单,以全面了解功能。


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

评论(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:'一种配置任意数量开关的方法',//标题 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);