想要為您的下一個桌面角色扮演游戲帶來一些獨特之處嗎?帶有自定義圖形的電子D20如何處理重大打擊和遺漏?今天,我將向您展示如何使用Arduino和一些簡單的零件來構建自己的產品。
如果您以前從未使用過Arduino,請不要擔心,我們有一個入門指南。
構建計劃
這是一個簡單的項目。 Arduino將驅動OLED顯示屏,并且一個按鈕將使模具死掉。自定義圖形將顯示關鍵命中或關鍵錯位。您可以輕松地將代碼修改為D8,D10或D12。
您需要的內容
1 x Arduino
1 x 0.96英寸I2C OLED顯示屏
1 x按鈕
1 x 10k?電阻器
1 x面包板
各種連接線
此處完整代碼,如果您不想完全按照書面說明進行操作。
這些是構建自己的D20所需的核心部分。您可能希望將其安裝在外殼中(如下所述),并將電路焊接到更永久的狀態。以下是您需要執行此操作的其他零件:
4 x M2 x 10mm(0.4英寸)螺栓
4 x M2螺母
4個7毫米(0.28英寸)墊圈
9V電池卡扣(或合適的替代品)
各種熱縮管
這些OLED顯示器非常涼。通常可以購買白色,藍色,黃色或這三種的混合物。我購買了藍色的,以匹配我的情況。確保您獲得的是 I2C 模型而不是 SPI 。
幾乎所有Arduino都適用。我選擇了Nano,因為它們足夠小,可以放入箱子中。請查看我們的購買指南以獲取有關Arduino型號的更多信息。
電路
這是您需要的電路:
將OLED顯示屏上的 VCC 和 GND 連接到Arduino + 5V 和接地。將Arduino上的模擬4 連接到標有 SDA 的引腳。將模擬5 連接到 SCL 引腳。這些引腳包含使用I2C總線驅動顯示器所需的電路。確切的引腳會因型號而異,但是Nano和Uno會使用A4和A5。如果您未使用Uno或Nano,請查看模型的線庫文檔。
將電池接地并使用 VIN 引腳。這表示輸入電壓,可以接受各種不同的DC電壓-但請先檢查您的特定型號,有時可能會略有不同。
將按鈕連接到數字引腳2 。注意10k如何?電阻接地。這個非常重要!這稱為下拉電阻,它可以防止Arduino在按下按鈕時檢測到虛假數據或干擾。它還可以保護電路板。如果不使用該電阻,則+ 5V會直接接地。這被稱為短短路,是殺死Arduino的簡便方法。
如果要焊接此電路,請使用熱縮管保護連接:
請確保不要將其加熱過多,并且只有在確定電路能夠正常工作后才進行加熱。您可能還希望將電纜成對絞合。這樣可以使它們保持整潔并有助于保護它們免受不必要的壓力:
按鈕測試
現在,您已經建立了電路,請上傳此測試代碼(請確保從 Tools》 Board 和 Tools》 Port 菜單中選擇正確的電路板和端口):
const int buttonPin = 2; // the number of the button pin
void setup() {
pinMode(buttonPin, INPUT); // setup button
Serial.begin(9600); // setup serial
}
void loop(){
if(digitalRead(buttonPin) == HIGH) {
Serial.print(“It Works”);
delay(250);
}
}
上傳后,保持Arduino通過USB連接并打開串行監視器(右上角》串行監視器)。每次按下按鈕,您應該會看到它有效字樣。
如果什么也沒發生,請仔細檢查電路。
OLED設置
您需要安裝兩個庫來驅動顯示。從Github下載Adafruit_SSD1306和Adafruit-GFX [不再可用]庫,并將它們保存到您的庫文件夾中。如果不確定庫文件夾在哪里,請閱讀我的復古游戲教程,在該教程中我會更詳細地配置相同的顯示器。
重新啟動Arduino IDE并從 File上傳測試草圖》示例菜單。選擇 Adafruit SSD1306 ,然后選擇 ssd1306_128x64_i2c 。上載此代碼(需要一些時間),您應該會在顯示器上看到許多形狀和圖案:
如果什么都沒有發生,請仔細檢查您的聯系。如果在檢查后仍然無法使用,則需要修改示例代碼。
更改此行(在 setup 函數的開頭):
display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
對此:
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
這會告訴庫有關正在使用的顯示的特定詳細信息。現在應該將所有內容設置為繼續進行構建。
案例
如果要在面包板上構建,或者不希望將其裝箱,則可以跳過此步驟。
我設計了此框并進行了3D打印。在Thingiverse上獲取文件。如果您沒有3D打印機,請不要擔心-在線服務3D集線器和Shapeways提供在線打印服務。
您可以輕松地用木頭制作此盒子,也可以購買塑料工程盒。
蓋子是簡單的推入配合設計,并且包含一些用于硬件的切口:
代碼 》
現在一切準備就緒,是時候編寫代碼了。以下是它在偽代碼中的工作方式:
if button is pressed
generate random number
if random number is 20
show graphic
else if random number is 1
show graphic
else
show number
為使其正常工作,需要生成一個隨機數-這就是死機。 Arduino有一個稱為 random 的隨機數生成器,但不應使用它。盡管對于基本的隨機任務已經足夠了,但對于電子芯片來說,隨機性還不夠。原因有些復雜,但是如果您對boallen.com感興趣,可以閱讀更多內容。
通過sirleech在Github上下載TrueRandom庫。將此添加到您的庫文件夾中,然后重新啟動IDE。
現在創建一個新文件并設置您的初始代碼(或只是從GitHub上獲取完成的代碼):
#include
#include
#include
#include
#include
Adafruit_SSD1306 display(4);
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // setup the OLED
pinMode(buttonPin, INPUT); // setup button
}
void loop() {
}
此代碼配置OLED,并包括與之通信所需的所有庫以及新的隨機數庫。現在將其添加到主循環中:
if(digitalRead(buttonPin) == HIGH) {
delay(15);
if(digitalRead(buttonPin) == HIGH) {
display.fillScreen(BLACK); // erase the whole display
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(0, 0);
display.println(TrueRandom.random(1, 21)); // print random number
display.display(); // write to display
delay(100);
}
}
這在目前是很基本的,但是它是可以正常工作的D20。每當按下按鈕時,屏幕上就會顯示一個介于1到20之間的隨機數:
這很好,但是有點無聊。讓我們做得更好。創建兩個新方法 drawDie 和 eraseDie :
void drawDie() {
display.drawRect(32, 0, 64, 64, WHITE);
}
這些將在屏幕中間繪制一個骰子。您可能希望通過繪制D20或D12等使事情變得更復雜,但是繪制基本的六面模具更簡單。基本用法如下:
drawDie();
接下來,修改您的主循環以繪制隨機數,該隨機數僅在中間較大。將文本大小和光標更改為:
display.setTextColor(WHITE);
display.setCursor(57, 21);
現在看起來好多了:
唯一的問題是大于9的數字:
解決方法很簡單。小于10的任何數字都將光標設置在與10或更大的數字不同的位置。替換此行:
display.setCursor(57, 21);
與此:
int roll = TrueRandom.random(1, 21); // store the random number
if (roll 《 10) {
// single character number
display.setCursor(57, 21);
}
else {
// dual character number
display.setCursor(47, 21);
}
這是現在的樣子:
現在剩下的只是當您擊中關鍵命中或未命中時的圖像。涉及幾個步驟,但這是一個足夠簡單的過程。
找到您要使用的合適圖像(越簡單越好,因為顯示僅是單色的)。這是我使用的圖像:
《圖id =“ attachment_617869” aria- describeby =“ caption-attachment-617869” class =“ wp-caption aligncenter”》
圖片來源:publicdomainvectors.org
您要使用的任何圖片都需要轉換到十六進制數組。這是代碼形式的圖像表示。有許多工具可以執行此操作,其中一些是專門為OLED顯示器編寫的。最簡單的方法是使用PicturetoC_Hex在線工具。以下是所需的設置:
上傳圖像,并將代碼格式設置為 HEX:0x 。將用于的設置為所有繪制圖像功能的黑色/白色。將所有其他選項保留為默認值。您可以根據需要在此處調整圖像大小。按獲取C字符串,您應該會看到圖像數據出現:
您將在一分鐘內需要此生成的數據。創建兩個名為 drawExplosion 和 drawSkull 的函數(或適合您的版本的名稱)。這是代碼:
void drawExplosion() {
// store image in EEPROM
static const unsigned char PROGMEM imExp[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x78,0x7f,0xff,0xc0,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xf0,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xfb,0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x07,0xff,0xff,0xf9,0xff,0xd8,0x00,0x00,0x00,0x3f,0xff,0xf0,0x0f,0x00,0x00,0x00,0x00,0x1f,0x1f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x01,0xbf,0xff,0xff,0xff,0x30,0x00,0x00,0x00,0x13,0xf7,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
display.drawBitmap(0, 0, imExp, 64, 62, 1); // draw mushroom cloud
}
void drawSkull() {
// store image in EEPROM
static const unsigned char PROGMEM imSku[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x78,0x00,0x07,0xf0,0x00,0x00,0x00,0x00,0xfc,0x00,0x07,0xf8,0x00,0x00,0x00,0x00,0xfe,0x00,0x07,0xf8,0x00,0x00,0x00,0x01,0xfe,0x00,0x07,0xfc,0x00,0x00,0x00,0x01,0xfe,0x00,0x07,0xfe,0x00,0x3f,0xc0,0x03,0xfe,0x00,0x01,0xff,0x81,0xff,0xfc,0x07,0xec,0x00,0x00,0x3f,0xc7,0xff,0xff,0x1f,0xc0,0x00,0x00,0x0f,0xcf,0xff,0xff,0xdf,0x00,0x00,0x00,0x07,0xbf,0xff,0xff,0xee,0x00,0x00,0x00,0x01,0x7f,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x01,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1e,0x3f,0xff,0x3f,0xc7,0x80,0x00,0x00,0x1e,0x0c,0x0f,0x00,0x07,0x80,0x00,0x00,0x1e,0x00,0x0f,0x00,0x0f,0x80,0x00,0x00,0x1e,0x00,0x19,0x80,0x0f,0x00,0x00,0x00,0x0f,0x00,0x19,0x80,0x0f,0x00,0x00,0x00,0x0d,0x00,0x30,0xc0,0x1f,0x00,0x00,0x00,0x05,0x80,0x70,0xc0,0x1e,0x00,0x00,0x00,0x05,0xf0,0xe0,0xe0,0x36,0x00,0x00,0x00,0x01,0xff,0xe0,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0xc4,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0xcc,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0xcc,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0x9e,0x7f,0xf0,0x00,0x00,0x00,0x00,0xff,0xfe,0x7f,0xc0,0x00,0x00,0x00,0x00,0x01,0xff,0xf8,0x1c,0x00,0x00,0x00,0x03,0xe0,0x3f,0x01,0xbf,0x00,0x00,0x00,0x07,0xa6,0x40,0x09,0x9f,0x80,0x00,0x00,0x1f,0x27,0x5a,0x39,0x9f,0xf8,0x00,0x01,0xff,0x27,0xdb,0x39,0x0f,0xfc,0x00,0x03,0xfe,0x31,0x7f,0x39,0x07,0xfc,0x00,0x03,0xfc,0x10,0x1a,0x02,0x03,0xf8,0x00,0x03,0xf8,0x10,0x00,0x02,0x01,0xf0,0x00,0x01,0xf8,0x10,0x00,0x02,0x01,0xe0,0x00,0x00,0x78,0x10,0x00,0x02,0x00,0xe0,0x00,0x00,0x70,0x30,0x00,0x02,0x00,0x00,0x00,0x00,0x30,0x20,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x64,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x73,0x55,0x63,0x00,0x00,0x00,0x00,0x00,0xf9,0x55,0x4f,0x00,0x00,0x00,0x00,0x00,0x7f,0x14,0x1f,0x00,0x00,0x00,0x00,0x00,0x1f,0xe0,0xfe,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x03,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
display.drawBitmap(0, 0, imSku, 60, 64, 1); // draw skull cloud
}
如果您想使用我使用過的圖像,請繼續并復制代碼。如果要使用自己生成的圖像,請根據需要將字節碼復制到 imSku 和 imExp 數組中。
以下是這些圖像在顯示屏上看起來像:
該代碼最重要的部分是這一行:
static const unsigned char PROGMEM imSku[]
這告訴Arduino將圖像存儲在EEPROM(什么是EEPROM?)中而不是其RAM中(RAM的快速指南)。這樣做的原因是簡單的; Arduino的內存有限,并且全部用于存儲圖像可能不會留下任何剩余代碼供您執行
修改主 if 語句以在出現以下情況時顯示這些新圖形:一卷或二十卷。請注意以下代碼行,以顯示與圖像一起滾動的數字:
if(roll == 20) {
drawExplosion();
display.setCursor(80, 21);
display.println(“20”);
}
else if(roll == 1) {
display.setCursor(24, 21);
display.println(“1”);
drawSkull();
}
else if (roll 《 10) {
// single character number
display.setCursor(57, 21);
display.println(roll); // write the roll
drawDie(); // draw the outline
}
else {
// dual character number
display.setCursor(47, 21);
display.println(roll); // write the roll
drawDie(); // draw the outline
}
這些新滾動的外觀如下:
這就是代碼方面的全部內容(如果您跳過了所有代碼,請從GitHub獲取代碼)。您可以輕松地將其修改為D12,D8等。
最終裝配
現在,其他所有操作都已完成,現在該將所有內容整理好了。將顯示屏固定在螺栓上,確保不要過度擰緊螺栓。這可能是最困難的部分。我這樣做是為了使顯示器破裂,所以您不妨使用一些塑料墊圈。我從Plasticard中切出了一些方塊:
小的螺母和螺栓可能很難連接。 提示:在螺絲起子的末端使用一小塊Blu-Tack首先固定螺母:
擰緊按下按鈕,連接電池并合上蓋子。注意不要夾住任何電線,或將它們捆得太緊,以免造成短路。根據尾線的長度,您可能需要使用某種絕緣保護裸露的連接(串行盒效果很好):
看起來像里面:
這是成品:
您現在應該是電子D20的驕傲擁有者!
責任編輯:wv
-
OLED
+關注
關注
119文章
6203瀏覽量
224329 -
Arduino
+關注
關注
188文章
6471瀏覽量
187244
發布評論請先 登錄
相關推薦
評論