該項(xiàng)目是一個(gè)實(shí)體的便攜式 LED 標(biāo)志,形狀為 Counter-Strike : Global Offensive (CS:GO) 團(tuán)隊(duì) Astralis 的標(biāo)志。它主要基于 FastLED 庫(kù)以及可編程的 WB2812B LED 燈條。一切都由 Arduino Nano 和便攜式移動(dòng)電源供電。
這旨在遍歷項(xiàng)目的各個(gè)部分,例如:
標(biāo)牌是如何建造的?
標(biāo)志的主要部分由木質(zhì)刨花板制成,并按照 Astralis 標(biāo)志的輪廓切割而成。切口的高度為 50 厘米,寬度為 40 厘米。手柄由 2、1 厘米 x 2、1 厘米的木梁組成,用膠帶包裹,以提高長(zhǎng)時(shí)間握持時(shí)的舒適度。
連接物理接口的控制箱由makercase.com 制作,它可以生成給定形狀的切口 - 在這種情況下,是一個(gè)打開(kāi)的盒子 - 具有不同的測(cè)量值,可以導(dǎo)出為 SVG 文件。然后將該文件導(dǎo)入 Adob??e Illustrator,在其中添加最終細(xì)節(jié),例如控件的文本雕刻和按鈕的剪切。然后用激光切割機(jī)切割控制箱,最后用木膠粘在一起。請(qǐng)參閱圖像文件夾下的圖像。
使用什么硬件?
用于使標(biāo)志工作的組件如下:
WS2812B RGB LED燈條
該項(xiàng)目的核心是能夠以不同類(lèi)型的照明序列照亮標(biāo)志本身。WS2812B 可尋址 LED 燈條有多種型號(hào),尺寸、密封劑或LED 密度不同。對(duì)于這個(gè)項(xiàng)目,我使用了 60 個(gè) LED 的密度。儀表不防水,因?yàn)樗鼘⒃诒荣惼陂g在室內(nèi)使用。條帶用雙面膠帶直接粘在板上。它直接從為該項(xiàng)目中的所有組件供電的移動(dòng)電源提供 5v 電壓,以及一個(gè) 1000 μF 的電容器,以節(jié)省燈帶上的第一個(gè) LED 以應(yīng)對(duì)潛在的電涌,從而將它們煎炸。你可以在這里閱讀更多。
7段顯示
該顯示器內(nèi)部只有 8 個(gè) LED。它被分成稱(chēng)為 a、b、c、d、e、f、g 和 DP 的段,并且可以以不同的組合點(diǎn)亮以表示阿拉伯?dāng)?shù)字和點(diǎn) (DP)。此 GIF 顯示了每個(gè) LED 的尋址方式:
為了快速識(shí)別標(biāo)志正在運(yùn)行的照明順序,可以相當(dāng)快地讀出數(shù)字,因?yàn)樗挥诒趁娴捻樞虬粹o旁邊。當(dāng)序列循環(huán)時(shí),數(shù)字將從“1”開(kāi)始,表示序列已重置。作為故障保險(xiǎn),如果發(fā)生錯(cuò)誤,顯示器被編程為顯示“E”。
顯示的數(shù)字取決于通過(guò) 74HC595 移位寄存器發(fā)送多少位,這將在下一節(jié)中詳細(xì)說(shuō)明。
您可以在此鏈接上進(jìn)一步閱讀 7 段顯示器以及其他用途。
74HC595 - 位移位寄存器
通常,為了控制 7 段顯示器中的每個(gè) LED,需要將每個(gè)引腳連接到 Arduino。這樣,如果您要使用多個(gè)數(shù)字引腳,您將很快用完引腳。這就是移位寄存器派上用場(chǎng)的地方。通過(guò)串聯(lián)一個(gè)移位寄存器,我們只需使用 3 個(gè) I/O 引腳就可以完成控制多達(dá) 8 個(gè) LED 的任務(wù)。不僅如此;如果您想控制更多顯示器,您可以將更多的移位寄存器鏈接在一起,從而節(jié)省更多的引腳。對(duì)于這個(gè)項(xiàng)目,一個(gè)數(shù)字就足夠了。
595 有兩個(gè)寄存器(可以認(rèn)為是“內(nèi)存容器”),每個(gè)寄存器只有 8 位數(shù)據(jù)。根據(jù)您發(fā)送到 595 的數(shù)據(jù),數(shù)據(jù)將首先被存儲(chǔ),并且只有在 595 被鎖存后才傳輸?shù)捷敵鲆_。
您可以在此詳細(xì)指南中閱讀有關(guān) 74HC595 的更深入說(shuō)明。
序列按鈕
標(biāo)志本身的想法是它存儲(chǔ)了多個(gè)照明序列,您可以通過(guò)一個(gè)簡(jiǎn)單的按鈕在它們之間切換。主要思想是,通過(guò)單次按下,一旦按鈕被按下和釋放,標(biāo)志應(yīng)該進(jìn)入下一個(gè)照明序列。按鈕有多種尺寸和形狀,但在發(fā)送 HIGH 或 LOW 信號(hào)方面,它們中的許多都有相同的問(wèn)題。這通常被稱(chēng)為“彈跳”信號(hào),其中信號(hào)在短時(shí)間內(nèi)(通常為幾毫秒)快速上下跳躍多次。這可以通過(guò)實(shí)施所謂的“去抖動(dòng)”來(lái)解決。下圖是一個(gè)按鈕被按下和釋放的例子,在穩(wěn)定之前反彈信號(hào)。
去抖
當(dāng)您物理按下普通按鈕時(shí),兩塊金屬會(huì)相互接觸。如果這兩個(gè)小金屬片不是完全平坦或完全對(duì)齊(而且它們不是),那么它們可以建立和斷開(kāi)幾次接觸,然后再牢固地壓在一起以使其始終導(dǎo)電。對(duì)于微控制器來(lái)說(shuō),當(dāng)您認(rèn)為您只按下了一次按鈕時(shí),該按鈕似乎被多次按下且持續(xù)時(shí)間極短。去抖動(dòng)就是要確保您和微控制器就按鈕按下或釋放事件發(fā)生的時(shí)間達(dá)成一致。這就是在沒(méi)有任何形式的去抖動(dòng)的情況下注冊(cè)按鈕按下的方式。
最簡(jiǎn)單的硬件解決方案(如上圖所示)是使用 10K 歐姆電阻和 1μF 電容去抖動(dòng)。對(duì)于這個(gè)項(xiàng)目,去抖動(dòng)功能至關(guān)重要,因?yàn)闃?biāo)志存儲(chǔ)了多個(gè)照明序列。如果按鈕在一個(gè)按鈕中記錄了多個(gè)“推動(dòng)”,則序列將快速循環(huán),從而導(dǎo)致錯(cuò)誤的循環(huán)。
有關(guān)更詳細(xì)的說(shuō)明,您可以在此處進(jìn)一步閱讀。
亮度控制
在控制界面的最左側(cè),可以控制 LED 的亮度。這是通過(guò)使用電位計(jì)完成的,該電位計(jì)充當(dāng)可變電阻器,通常用于控制電氣設(shè)備,例如音量控制,或者在這種情況下是照明。但是,根據(jù)電位器的轉(zhuǎn)動(dòng)程度,電阻器只允許總電流的一部分,可以通過(guò)模擬信號(hào)讀取。軟件部分將進(jìn)一步解釋如何讀取和使用該信號(hào)。
有關(guān)電位器如何工作的更詳細(xì)說(shuō)明,您可以在此處閱讀更多信息。
代碼是如何工作的?
運(yùn)行 WS2812B LED 燈條的代碼是在FastLED庫(kù)的幫助下編寫(xiě)的。FastLED 庫(kù)是一種簡(jiǎn)單快捷的方法,可以按照您希望的順序點(diǎn)亮單個(gè) LED,并生成照明模式。
燈光效果主要基于這個(gè)網(wǎng)站,展示了一些效果以及代碼和設(shè)置。這些效果基于for
循環(huán)的概念,是運(yùn)行這些效果的好方法。但是,該項(xiàng)目實(shí)現(xiàn)了添加一個(gè)按鈕以在效果之間進(jìn)行切換,并且此功能帶有一個(gè)問(wèn)題。循環(huán)“for
占用”正在運(yùn)行的代碼,并且僅在循環(huán)完成后繼續(xù)。因此,如果您在for
循環(huán)運(yùn)行時(shí)按下按鈕,則推送不會(huì)注冊(cè)。
正因?yàn)槿绱?,為了通過(guò)使用全局變量來(lái)解決這個(gè)問(wèn)題并減少使用的循環(huán)數(shù)量,已經(jīng)重寫(xiě)了所使用的效果。for
下面顯示的兩個(gè)示例具有相同的效果,但以?xún)煞N不同的方式編寫(xiě)。第一個(gè)是原始效果,在運(yùn)行時(shí)沒(méi)有注冊(cè)按鈕按下,而第二個(gè)示例這樣做是因?yàn)樗褂昧巳肿兞?,可以在函?shù)外部使用theaterChase.
示例一:
void theaterChase(byte red, byte green, byte blue, int SpeedDelay) {
for (int j=0; j<10; j++) {
//do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < NUM_LEDS; i=i+3) {
setPixel(i+q, red, green, blue);
//turn every third pixel on
}
showStrip();
delay(SpeedDelay);
for (int i=0; i < NUM_LEDS; i=i+3) {
setPixel(i+q, 0,0,0); //turn every third pixel off
}
}
}
}
示例二:
int theaterDistance = 3;
int theaterDelay = 300;
int theaterJ = 0;
int theaterI = 0;
void theaterChase(byte red, byte green, byte blue) {
if (theaterI == 0) {
for (int i=0; i < NUM_LEDS; i++) {
setPixel(i, 0,0,0);
}
for (int i=0; i < NUM_LEDS; i+=theaterDistance) {
setPixel(i+theaterJ, red, green, blue);
//turn every theaterDistance pixel on
}
showStrip();
theaterJ = (theaterJ + 1) % theaterDistance;
}
theaterI = (theaterI + 1) % theaterDelay;
}
如前所述,LED 的亮度通過(guò)電位器進(jìn)行控制。信號(hào)最初被讀取為 0 到 1023 之間的值。FastLED 庫(kù)僅使用 0 到 255 之間的數(shù)字來(lái)定義亮度。然后需要用map
函數(shù)映射數(shù)字,如下所示,然后用變量MIN_BRIGHTNESS
和進(jìn)行約束MAX_BRIGHTNESS
,用作限制器。
int brightnessValue = map(analogRead(brightnessPin), 0, 1023, 0, 255);
FastLED.setBrightness(constrain(brightnessValue, MIN_BRIGHTNESS, MAX_BRIGHTNESS));
正如硬件中的去抖部分所討論的,按鈕在按下和釋放時(shí)往往會(huì)產(chǎn)生“噪音”。下面的代碼會(huì)在短時(shí)間內(nèi)檢查兩次,以確保確實(shí)按下了按鈕。
按鈕按下后加sequenceNumber
一,并運(yùn)行與數(shù)字對(duì)應(yīng)的照明功能。它還清除應(yīng)該保留在 LED 中的所有數(shù)據(jù),setAll(0, 0, 0);
并將正確的數(shù)字轉(zhuǎn)移到 74HC595 以點(diǎn)亮 7 段顯示器上的相應(yīng)序列號(hào)。
// LED lightning sequence control
buttonState = digitalRead(buttonPin);
if (buttonState != lastButtonState) {
if (buttonState == HIGH) {
sequenceNumber = (sequenceNumber+1) % 5;
writeAndShift(sequenceNumber + 1);
setAll(0, 0, 0);
}
} // save the current state as the last state, for next time through theloop
lastButtonState = buttonState;
最后,Arduino 需要知道根據(jù)sequenceNumber
變量運(yùn)行哪個(gè)照明序列。這是通過(guò)使用switch
和case
語(yǔ)句完成的。這些工作就像if
語(yǔ)句一樣,但更好看。switch(sequenceNumber)
用于定義語(yǔ)句應(yīng)該使用哪個(gè)聲明case
。如果等于 1,則將運(yùn)行,如果case 1:
等于2 ,依此類(lèi)推。在 every 下,您定義應(yīng)該執(zhí)行的代碼。sequenceNumber
case 2:
sequenceNumber
case
switch(sequenceNumber){
case 0:
FadeInOut(0xff, 0x00, 0x00); // Only using red
break;
default:
case
如果值超出給定語(yǔ)句,則用作故障保護(hù)。與該語(yǔ)句非常相似else
,如果上述語(yǔ)句均不成立,則您定義應(yīng)該執(zhí)行的內(nèi)容。
附加圖像
特別感謝
我要親自感謝Duckapple和Jlndk幫助我編寫(xiě)代碼。
評(píng)論