×

简单的掷骰子草图开源分享

消耗积分:0 | 格式:zip | 大小:0.03 MB | 2023-02-08

分享资料个

描述

掷骰子,第 1 部分

我最近为我的孙子制作了一个简单的掷骰子草图,供他在玩棋盘游戏时使用。他对结果非常满意,但我认为分享“掷骰子”草图并提供另一种掷两个骰子的版本可能会对其他人有所启发(请参阅掷骰子,第 2 部分文章)。

在本文中,我提供了两个“掷骰子”草图的第 1 部分 - 掷一个骰子。第 1 部分模具草图和组件的设计非常简单——它使用 7 个 LED 代表标准模具的六个面/侧面中每一个上的每个标准点图案和一个简单连接的按钮开关。

如果您想知道为什么使用七个而不是六个 LED,那是因为需要七个 LED 来反映传统标准裸片所有面的所有可能布局组合(见下文)。七个 LED 中的每一个都映射并连接到微控制器数字 IO 端口。对于单个裸片,这没问题,但如果我们开始考虑添加两个或更多裸片,那么不行,需要太多的微控制器端口。但不用担心,这就是“掷骰子,第 2 部分”文章加快步伐并展示我们如何使用低成本串行并行输入/输出 IC(例如 74HC595 IC)来实现这一点,以添加尽可能多的骰子我们想要。但是,对于本文的第 1 部分,我们首先将一个裸片及其 LED 直接连接到微控制器。让我们开始看这第 1 部分的文章..

设计 - 硬件

发光二极管

如上所述,电路设计具有 7 个 LED 和一个按钮开关。本设计中使用了七个 LED,这样我们就可以将它们布置在面包板上的物理排列中,以反映传统六面模具每个面/侧面的点(点)布局,因此:

pYYBAGPi_7qAEOnlAAAdNQ_ggTA552.png
每个芯片侧面/面的 pip LED 布局 - X 为开,0 为关
 

我最终得到的面包板安排是:

poYBAGPi__-ALPSHAAtHtHuPn7w311.jpg
半尺寸面包板是理想的
 

我决定使用不同颜色的 LED 只是为了增加一点趣味性,但任何颜色都可以。我为不同颜色的短跳线道歉,因为我从我的跳线套件中选择的是有限的。需要注意的是,这些跳线连接到每个 LED 正极端子,然后沿着面包板进一步连接到微控制器连接线。如果没有这些跳线,LED 就会被电线弄得乱七八糟,因此耐心地连接电路板是值得的。

作为参考,LED 到微控制器数字引脚分配如下(请注意,面包板上 LED 的方向如上图所示):

  • 右下方(红色)LED - 数字引脚 2
  • 底部中间(绿色)LED - 数字引脚 3
  • 左下方(蓝色)LED - 数字引脚 4
  • 中间(黄色)LED - 数字引脚 5
  • 右上角(红色)LED - 数字引脚 6
  • 顶部中间(绿色)LED - 数字引脚 7
  • 向左(蓝色)LED - 数字引脚 8
  • 最后,按钮开关连接到数字引脚 9

按钮开关

设计中使用了一个按钮开关,以便在按下和释放时启动新的掷骰子动作。草图使用ez_switch_lib简化设计的库。ez_switch_lib 实例针对单个开关进行初始化,并在设置(add_switch功能)中进一步定义为一个按钮开关,只需简单地连接而无需下拉电阻。请注意,该add_switch 函数的参数包括两个库宏 - ' button_switch' 和 ' circuit_C2'。这些在ez_switch_lib 头文件 (.h) 中定义,因此只需引用即可。

声明库、创建实例并添加/创建按钮开关后,所需要做的就是不断测试在主循环中完成的开关状态。如果按下并释放按钮开关,switched则返回状态“”(也是ez_switch_lib 库的定义宏)。

按钮开关可以位于面包板上任何方便的地方,并根据示意图接线。我设法将它挤压在左侧边缘,这样可以轻松访问。有关组件布局的图表,请参见示意图。

设计 - 素描

在解释草图的中心部分之前,我应该提一下,我在其中包含了一个心跳监视器,它旨在以 1 赫兹的频率(每个周期 1 个周期)闪烁内置微控制器 LED(LED_BUILTIN通常在引脚 13 上)第二)。这提供了草图正在运行(或未运行)的一些物理指示。如果不需要草图的这一方面,则可以通过将心跳声明部分中的宏定义设置为“ false”来禁用它。即设置' #define heart_beat_on false'。心跳监视器的关联数据是:

// Define heart beat data...
//
#define heart_beat_pin   LED_BUILTIN  // digital pin for heart beat LED
#define heart_beat_on    true         // determines if the implementation uses the heartbeat
long unsigned heart_beat_freq = 1000; // time(milliseconds) of heart beat frequency
long unsigned heart_beat_on_off_time; // the time the LED is on and off - 1/2 frequency
long unsigned last_heart_beat_time;   // time in milliseconds of last heart beat status change
bool heart_beat_status = HIGH;        // current status of heart beat, start high 

我已经提到代码使用板载 LED ( LEDBUILTIN) 以及如何在不需要时禁用监视器,但是如果您希望改变监视器的频率,请将变量“ heart_beat_freq”编辑为每个周期的总数第二个愿望。请注意,一个完整的周期是打开然后关闭,因此闪光率会自动计算为所选频率的 1/2。

heart_beat 功能很简单,但心跳只有在定期调用该功能时才会运行。因此,如草图所示,应在整个代码中调用它。

继续,草图通过监视连接的按钮开关是否被按下来运行。按钮开关是使用库配置的,该ez_switch_lib 库从草图设计中消除了去抖动的任何麻烦。要访问ez_switch_lib 项目中心文章并下载库文件,请点击此链接 - ez_switch_lib

要合并库,请在本地 Arduino/libraries 目录下创建一个名为“ ez_switch_lib”的目录,然后从项目中心文章将三个文件下载到该目录中:

1.ez_switch_lib.h

2.ez_switch_lib.cpp

3.keywords.txt

现在让我们看看草图的其他主要部分:

图书馆宣言启动

开关库声明如下:

#include 

并通过以下方式启动单个开关:

Switches my_switches(1); 

在这里,我们创建了一个开关实例,其大小仅适用于一个开关,并使用“ my_switches”作为其实例名称。我们还没有定义它的类型(参见 参考资料setup)。

setup - setup 函数初始化草图所需的一切:

  • add_switch()我们使用该功能设置按钮开关。这具有三个参数 - 开关类型、开关引脚和电路类型,其中开关类型由库保留宏“ button_switch”定义,开关引脚定义为“ button_switch_pin”,我们决定在草图中使用的数字引脚 (12),和由库保留宏“”定义的电路类型circuit_C2这会通知开关库,开关无需 10k 欧姆下拉电阻即可简单接线。
  • 声明的 LED 和
  • 心跳监视器

需要注意的是,按钮开关的分配过程已验证成功。如果出于任何原因无法分配开关,则草图将终止。如果已配置心跳监视器并且观察到未运行(闪烁),则会看到这一点。' button_switch_pin' 参数的值由草图宏定义。

announce_throw - 此函数在掷骰子(按下按钮开关)之间调用,并显示骰子的短频闪模式以指示掷骰即将开始。

该函数执行两个频闪周期,点亮由映射到 LED 的数字端口定义的每个 LED。模式是任意的,可以配置成任何想要的。

void announce_throw() {
 uint8_t led;
 // Start by clearing down the existing die pips/score
 clear_pips();
 for (uint8_t cycle = 1; cycle <= 2; cycle++) {// do 2 cycles
   for (uint8_t led = 0; led < max_leds; led++) {
     digitalWrite(pip_pins[led], HIGH);
     digitalWrite(pip_pins[max_leds - led - 1], HIGH);
     delay(60);
     heart_beat(); // keep pumping the heart beat timer whilst doing the announcing the throw
     digitalWrite(pip_pins[led], LOW);
     digitalWrite(pip_pins[max_leds - led - 1], LOW);
     delay(20);
     heart_beat(); // keep pumping the heart beat timer whilst doing the announcing the throw
   }
 }
}

throw the die - 该throw_die()函数首先“宣布”即将开始掷骰子,方法是通过调用该announce_throw()函数在两个周期内对七个 LED 中的每一个进行频闪。

此后,该函数在每次调用时重置随机种子,然后在 0-5(或现实世界中的 1-6)范围内确定投掷值(骰子的随机面/面)。

使用此值,该函数然后检查是否为该面的每个点定义了 LED,如果是,则点亮关联的 LED。

...
#define faces_per_die      6
#define max_pips_per_face  6
uint8_t pip_patterns[faces_per_die][max_pips_per_face] = {
// LEDs that represent die pip patterns, faces/side 1-6 (array index 0-5) across 7 leds
 5, 0, 0, 0, 0, 0, // 1 pip, just the central LED
 3, 7, 0, 0, 0, 0, // 2 pips, each central two outer LEDs
 2, 5, 8, 0, 0, 0, // 3 pips, diagonal LEDs
 2, 4, 6, 8, 0, 0, // 4 pips, each corner LED
 2, 4, 5, 6, 8, 0, // 5 pips, all LEDs
 2, 3, 4, 6, 7, 8, // 6 pips, each outer column of 3 LEDs
};
...
void throw_die() {
  announce_throw();   // 'announce' the throw of the die
  randomSeed(analogRead(A0) * 31 +
            analogRead(A1) * 37 +
            random(1023, 10000)); // keep changing the seed
  uint8_t die_face = (random(1, 104640) % faces_per_die); // range 0-(faces_per_die-1)
  // Now display the pips on the die
  for (uint8_t column = 0; column < max_pips_per_face; column++) {
    uint8_t led = pip_patterns[die_face][column];
    if (led != 0) {
      // A pip LED is defined so illuminate it
      digitalWrite(led, HIGH);
    }
  }
}

主循环- 草图的主循环非常简单,并使用read_switch 函数 ( myswitches.read_switch(switch_id)) 不断循环检查按钮开关的状态。仅当检测到按下/释放周期(开关读取函数返回值“ ”)时,才会通过调用该函数switched来执行掷骰子操作:throw_die()

void loop() {
 do {
   heart_beat(); // keep pumping the heart beat timer every cycle
   if (my_switches.read_switch(switch_id) == switched) {
     // the value 'switched' is defined by ez_switch_lib.h
     // Switch has been pressed and released, so throw the die...
     throw_die();
   }
 } while (true);
}

结论

就是这样,我希望您在棋盘游戏中使用它会得到一些乐趣,但如果您想使用多个骰子,那么为什么不探索第2 部分文章,该文章提供了连接两个或更多骰子的替代方法。


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

评论(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.lene-v.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.lene-v.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);