這篇文章來源于DevicePlus.com英語網(wǎng)站的翻譯稿。
目錄
1 布爾邏輯運(yùn)算
1.1 晶體管邏輯電路與二進(jìn)制
2 示例
2.1 邏輯運(yùn)算符
2.2 雙繼電器狀態(tài)機(jī)
1 Arduino布爾邏輯運(yùn)算
二進(jìn)制和布爾運(yùn)算有時(shí)候看起來就像是流行語一樣,尤其是“二進(jìn)制”,但這只是因?yàn)槿藗円坏┝私饬酥缶蜁R上喜歡上這種思維模式。提示:它們就是法拉利的酷極客。
在這些事物的核心模塊中,二進(jìn)制屬于機(jī)器的部分,如果您想要控制機(jī)器,尤其是微控制器,那么您必須時(shí)常對二進(jìn)制進(jìn)行深入研究。尤其是Arduino Uno(atmega328p),它只有2KB SRAM。這是一個(gè)精益系統(tǒng),如果您想要它運(yùn)行更大的項(xiàng)目,那就要很聰明地使用二進(jìn)制才行。如果要將大型陣列存儲在PROGMEM和EEPROM(閃存)中,您必須使用這個(gè)方法。
1.1 晶體管邏輯電路和二進(jìn)制
“為什么不直接使用十進(jìn)制系統(tǒng)?”這一問題非常重要,必須首先解答。一旦您理解了二進(jìn)制系統(tǒng)的設(shè)計(jì)初衷,您就會更加喜歡布爾邏輯運(yùn)算的。
設(shè)想有一個(gè)晶體管,它在任何給定時(shí)間都可能處于“ON”或“OFF”狀態(tài)。該晶體管可以描述兩個(gè)值(2**1)。但是,如果您想要計(jì)數(shù)更大的值該怎么辦?添加另一個(gè)晶體管,您可以數(shù)到4(2**2),三個(gè)(2**3)可以讓您數(shù)到8,以此類推。為了增加您的學(xué)習(xí)樂趣,可以打開一個(gè)python腳本,然后將以下內(nèi)容復(fù)制粘貼到您的腳本中來查看8位/1字節(jié)的可能狀態(tài):
for i in range( 1, 8+1 ): print("Possible states for %i bits => %i (%s)" % ( i, 2**i, bin((2**i-1))))
輸出如下:
Possible states for 1 bits => 2 (0b1) Possible states for 2 bits => 4 (0b11) Possible states for 3 bits => 8 (0b111) Possible states for 4 bits => 16 (0b1111) Possible states for 5 bits => 32 (0b11111) Possible states for 6 bits => 64 (0b111111) Possible states for 7 bits => 128 (0b1111111) Possible states for 8 bits => 256 (0b11111111)
以及最高16位/2字節(jié):
for i in range( 9, 16+1 ): print( "Possible states for %i bits => %i (%s)" % ( i, 2**i, bin((2**i-1))))
輸出如下:
Possible states for 9 bits => 512 (0b111111111) Possible states for 10 bits => 1024 (0b1111111111) Possible states for 11 bits => 2048 (0b11111111111) Possible states for 12 bits => 4096 (0b111111111111) Possible states for 13 bits => 8192 (0b1111111111111) Possible states for 14 bits => 16384 (0b11111111111111) Possible states for 15 bits => 32768 (0b111111111111111) Possible states for 16 bits => 65536 (0b1111111111111111)
在十進(jìn)制系統(tǒng)中,僅僅使用16個(gè)手指和腳趾不可能數(shù)出65,535只寶可夢(包括起始值0)。但是使用二進(jìn)制就可以!
如果看起來有點(diǎn)晦澀難懂的話,不要?dú)怵H。把每個(gè)二進(jìn)制數(shù)字想像成一個(gè)晶體管:1是“ON”,0是“OFF”。使用十進(jìn)制系統(tǒng)來描述數(shù)字255需要256只晶體管(包括0),而使用二進(jìn)制系統(tǒng),我們可以只用8只晶體管來描述256種狀態(tài)。它是“0b11111111”,8位為一個(gè)字節(jié)。它在早期的計(jì)算機(jī)實(shí)驗(yàn)室種節(jié)省了大量空間,因?yàn)槟莻€(gè)時(shí)候晶體管既不小也不高效(您見過真空管嗎?)。
這就是我們在平板電腦和手機(jī)上玩Pokémon Go的時(shí)候計(jì)算所捕獲寶可夢數(shù)量的方式。除了內(nèi)存限制,它的計(jì)數(shù)大小是沒有上限的。
使用Arduino時(shí),我們使用“字節(jié)”型數(shù)據(jù)類型(實(shí)際上是uint_8t)來告訴編譯器我們想要一個(gè)0-255范圍內(nèi)的值。然而,布爾型變量要簡單得多!布爾型變量可以僅用一個(gè)晶體管來表示,真(true)為“ON”,假(false)為“OFF”。您可以使用一個(gè)很小的狀態(tài)機(jī)來確定您的電機(jī)是否在運(yùn)行,并在setup()函數(shù)之前對其進(jìn)行全局聲明。
bool is_motor_running = false ; // or 0
當(dāng)電機(jī)啟動時(shí),您需要對其進(jìn)行更新,使用以下代碼:
// flip it, else use true/1 bool is_motor_running = ! is_motor_running ;
您可以使用它來控制系統(tǒng)的行為,例如,保證您的Arduino在電機(jī)運(yùn)行時(shí)不進(jìn)行任何操作。
while ( 1 ) { if ( is_motor_running ) { // It does indeed run! // If something-something, check stuff. // Is motor still running? if( ! is_motor_running ) break ; delay( 100 ) ; } // It's not running, do something! else if ( ! is_motor_running ) { Serial.println( F( "*Mumble*mumble* Motor inactive..." ) ) ; // Do something, anything } }
您可能已經(jīng)注意到了符號“!”,這是邏輯非運(yùn)算符,在人類語言中的意思是“不是”。Arduino C++中可用的關(guān)系運(yùn)算符是“!=”、“>=”、“<=”、“>”,但今天講述的是布爾邏輯運(yùn)算。這與變量之間的關(guān)系無關(guān)(例如確定一個(gè)值是否大于另一個(gè)值),因?yàn)檫壿嬤\(yùn)算符“!”—邏輯非,“&&”—邏輯與,和“||”—邏輯或已經(jīng)足以創(chuàng)建出令人生畏的復(fù)雜表達(dá)式了。雖然有時(shí)候我們稱之為二進(jìn)制運(yùn)算符,但是不要偏離了方向。
如果到目前為止您都能理解了,可以查看更高級的邏輯運(yùn)算。
2 示例
2.1 邏輯運(yùn)算符
按照上面的二進(jìn)制位,我們在實(shí)例中使用邏輯運(yùn)算符。我們使用了Arduino IDE,請參閱此文的簡介。
現(xiàn)在,讓我們用二進(jìn)制的方式讀到“1”!
byte Sum = 0 bool Transistor1 = true ; if ( Transistor1 ) Sum = 1 else if ( ! Transistor1 ) Sum = 0
這看似簡單,但是功能非常強(qiáng)大。讓我們做一個(gè)更長的復(fù)合表達(dá)!
[ begin Boolean_logical_operators.ino ]
/* Try changing the values of t1, t2, t3, t4 to various combinations of true/false. 16 possible states (4**2), decimal 0 to 15, binary 0b0000 to 0b1111. */ // 0b1010 bool t1 = true ; // Transistor 1: it's on! bool t2 = false ; // Transistor 2: it's off! bool t3 = true ; // Transistor 3: it's on! bool t4 = false ; // Transistor 4: it's off! bool did_serial_entry = false ; // Did user input data? const byte targetSum = 0b0111 ; // 7 void setup( void ) { Serial.begin( 9600 ) ; Serial.setTimeout( 2500 ) ; // Timeout in milliseconds } void loop( void ) { byte Sum = 0 ; /* Try changing the values of t1, t2, t3, t4 to various combinations of true/false. 16 possible states (4**2), decimal 0 to 15, binary 0b0000 to 0b1111. */ Serial.println( F( "[!] Enter binary in range '0 0 0 0' to '1 1 1 1' and hit ENTER" ) ) ; // Input over Serial Monitor? Press CTRL+SHIFT+M to open it. // Note that Serial.available() is 'true' if any serial input // is in buffer... Is '> 0' really necessary here? if( Serial.available() > 0 ) { t1 = Serial.parseInt() ; t2 = Serial.parseInt() ; t3 = Serial.parseInt() ; t4 = Serial.parseInt() ; // Flush serial buffer while( Serial.available() ) Serial.read() ; Serial.print( "[!] Got "" ) ; Serial.print( t1 ) ; Serial.print( " " ) ; Serial.print( t2 ) ; Serial.print( " " ) ; Serial.print( t3 ) ; Serial.print( " " ) ; Serial.print( t4 ) ; Serial.println(""") ; // Keep state, only print MINIGAME if true did_serial_entry = true ; } else did_serial_entry = false ; // 0b0000 if ( ! t1 && ! t2 && ! t3 && ! t4 ) Sum = 0 ; // 0b0001 else if ( ! t1 && ! t2 && ! t3 && t4 ) Sum = 1 ; // 0b0010 else if ( ! t1 && ! t2 && t3 && ! t4 ) Sum = 2 ; // 0b0011 else if ( ! t1 && ! t2 && t3 && t4 ) Sum = 3 ; // 0b0100 else if ( ! t1 && t2 && ! t3 && ! t4 ) Sum = 4 ; // 0b0101 else if ( ! t1 && t2 && ! t3 && t4 ) Sum = 5 ; // 0b0110 else if ( ! t1 && t2 && t3 && ! t4 ) Sum = 6 ; // 0b0111 else if ( ! t1 && t2 && t3 && t4 ) Sum = 7 ; // 0b1000 else if ( t1 && ! t2 && ! t3 && ! t4 ) Sum = 8 ; // 0b1001 else if ( t1 && ! t2 && ! t3 && t4 ) Sum = 9 ; // 0b1010 else if ( t1 && ! t2 && t3 && ! t4 ) Sum = 10 ; // 0b1011 else if ( t1 && ! t2 && t3 && t4 ) Sum = 11 ; // 0b1100 else if ( t1 && t2 && ! t3 && ! t4 ) Sum = 12 ; // 0b1101 else if ( t1 && t2 && ! t3 && t4 ) Sum = 13 ; // 0b1110 else if ( t1 && t2 && t3 && ! t4 ) Sum = 14 ; // 0b1111 else if ( t1 && t2 && t3 && t4 ) Sum = 15 ; Serial.print( "Sum (DEC) = " ) ; Serial.println( Sum, DEC ) ; Serial.print( "Sum (BIN) = " ) ; Serial.println( Sum, BIN ) ; // MINIGAME // Did user enter data? if( did_serial_entry ) { if ( Sum > targetSum || Sum < targetSum ) // Or '!=' Serial.println( F( "[!] You swing and you miss! Try again!" ) ) ; if ( Sum < targetSum ) Serial.println( F( "[!] HINT! Go higher ..." ) ) ; else if ( Sum > targetSum ) Serial.println( F( "[!] HINT! Go lower ..." ) ) ; else if ( Sum == targetSum ) { Serial.println( F( "[!] You win!" ) ) ; for ( int it = 0 ; it < 3 ; it ++ ) { for ( int it2 = 0 ; it2 < 25 ; it2 ++ ) { Serial.print( ";) " ) ; delay( 25 ) ; } Serial.println() ; } // *Celebratory pause* delay( 2500 ) ; } } delay( 2500 ) ; }
[ end Boolean_logical_operators.ino ]
按下CTRL+SHIFT+M彈出串行監(jiān)視器,并輸入一個(gè)4位值,以空格分隔,類似“1 0 1 0”這樣的數(shù)據(jù),然后按下“Send(發(fā)送)”。您將看到以下輸出:
如果幸運(yùn)的話,您將看到以下內(nèi)容:
該Arduino草圖展示了布爾邏輯運(yùn)算的多種用途。無論在哪個(gè)應(yīng)用中需要使用“真”,或者是“假”,我們都可以使用布爾邏輯運(yùn)算。
2.2 雙繼電器狀態(tài)機(jī)
2.1中的示例只是一個(gè)用來演示邏輯運(yùn)算符的小程序。本節(jié)所創(chuàng)建的是一個(gè)有用的狀態(tài)追蹤中繼模塊,您可以進(jìn)行修改和添加。將代碼復(fù)制到Arduino IDE一個(gè)新的草圖中,然后使用CTRL+U上傳。然后,使用CTRL+SHIFT+M(或在Linux/MacOS上 使用“python3 -m serial.tools.miniterm”,Windows上使用TeraTerm/Putty)查看串行監(jiān)視器。如果輸入“0”并發(fā)送,則可以查看當(dāng)前繼電器狀態(tài)(為“ON”或“OFF”)。
如果您輸入“1”,您將切換到繼電器1,如果它是“OFF”為“ON”,如果是“ON”則為“OFF”。發(fā)送“2”則會對繼電器2進(jìn)行相同的操作。對于這兩個(gè)繼電器,狀態(tài)保存在布爾型變量(“relay1State”和“relay2State”)中,并且對于每個(gè)繼電器,LED會在其真正為“ON”時(shí)亮起。
除了Arduino之外,不需要任何其他東西來使用該程序。制作之前先玩一下吧!
以下代碼是專門按照適合于在Arduino IDE上使用布爾值的方式來編寫的。
在硬件方面,我從不信任那些用于重載的藍(lán)色5V繼電器,但是已經(jīng)確認(rèn)了這些繼電器在高達(dá)~200W的負(fù)載下性能良好。那么開始享受制作的樂趣吧!
2x 2N7000 N溝道MOSFET | https://www.newark.com/on-semiconductor/2n7000/n-channel-mosfet-60v-200ma-to/dp/58K9650 |
2x ROHM SLR343BC4TT32 3mm 藍(lán)色LED | https://www.avnet.com/shop/us/products/rohm/slr343bc4tt32-3074457345627700657?CMP=EMA_ECIA_inventoryfeed_VSE?aka_re=1 |
2x BAT86 肖特基二極管 | https://www.newark.com/search?st=bat86%20schottky%20diode |
Arduino Uno 或 Arduino Nano |
https://store.arduino.cc/arduino-uno-rev3 https://store.arduino.cc/arduino-nano |
2x 4.7 千歐 + 2x 470 歐姆電阻 | https://www.newark.com/multicomp/cfr0w4je006kil/resistor-kit-carbon-film-axial/dp/24M1011 |
面包板 | https://www.newark.com/twin-industries/tw-e41-1020/breadboard-solderless-830-tie/dp/56T0251 |
杜邦線 | https://www.newark.com/adafruit/759/kit-contents/dp/88W2571 |
2x 5V 繼電器 | https://www.newark.com/omron-electronic-components/g5le-1a4-dc5/relay-spst-no-250vac-30vdc-10a/dp/83F5375 |
2.2.1 開始構(gòu)建!
按下圖所示將所有部件進(jìn)行連接,首先是面包板,然后是原型板。我們就是這樣做的。
唯一需要注意的是正確使用BAT86肖特基二極管。您必須將陰極(BAT86上的黑環(huán),通常在別的二極管上是白環(huán))朝向繼電器的正極端子(上圖右側(cè)),否則會出現(xiàn)問題(短路)。環(huán)標(biāo)記了陰極(k),確保它與正極端子對齊!請看這張圖,放大藍(lán)色繼電器的部分:
這是組裝好的圖片。Arduino Nano原型板上的附加組件內(nèi)容不在本文的范圍內(nèi),而且這部分也很無趣。
!prettyStateMachine, 這是“真”嗎?
您可以查看以下代碼:
[ begin prettyStateMachine.ino ]
/* Toggle relays on/off relative to their previous states. It's boolean! */ const byte relay1LED = 4 ; // D4 const byte relay1Pin = 6 ; // D6 const byte relay2LED = 8 ; // D8 const byte relay2Pin = 10 ; // D10 bool relay1State = false ; // or 0, 'OFF' bool relay2State = false ; // or 0, 'OFF' byte buffer = 0 ; void setup( void ) { Serial.begin( 9600 ) ; Serial.setTimeout( 500 ) ; pinMode( relay1LED, OUTPUT ) ; pinMode( relay1Pin, OUTPUT ) ; pinMode( relay2LED, OUTPUT ) ; pinMode( relay2Pin, OUTPUT ) ; } void loop( void ) { Serial.println( F( "[!] 0=show statesn[!] 1=flip relay 1n[!] 2=flip relay 2" ) ) ; Serial.println( F( "[?] Input: " ) ) ; buffer = Serial.parseInt() ; // Returns 0 on timeout switch( buffer ) { case 0: Serial.print( F( "[!] Relay 1 => " ) ) ; if ( relay1State ) Serial.println( "ON" ) ; else if ( ! relay1State ) // 'else' is enough Serial.println( "OFF" ) ; Serial.print( F( "[!] Relay 2 => " ) ) ; if ( relay2State ) Serial.println( "ON" ) ; else if ( ! relay2State ) // 'else' is enough Serial.println( "OFF" ) ; break ; case 1: if( relay1State ) { digitalWrite( relay1Pin, LOW ) ; digitalWrite( relay1LED, LOW ) ; //relay1State = false ; // OK relay1State = ! relay1State ; // Better } else if ( ! relay1State ) { // 'else' is enough digitalWrite( relay1Pin, HIGH ) ; digitalWrite( relay1LED, HIGH ) ; //relay1State = true ; // OK relay1State = ! relay1State ; // Better } break ; case 2: if( relay2State ) { digitalWrite( relay2Pin, LOW ) ; digitalWrite( relay2LED, LOW ) ; //relay2State = false ; // OK relay2State = ! relay2State ; // Better } else if ( ! relay2State ) { // 'else' is enough digitalWrite( relay2Pin, HIGH ) ; digitalWrite( relay2LED, HIGH ) ; //relay2State = true ; // OK relay2State = ! relay2State ; // Better } break ; } delay( 2000 ) ; }
[ end prettyStateMachine.ino ]
現(xiàn)在我們就有了狀態(tài)追蹤功能了,例如,我們可以查看當(dāng)前的繼電器狀態(tài),并且可以隨意對其進(jìn)行反轉(zhuǎn)。我們已經(jīng)介紹了帶有邏輯運(yùn)算符的復(fù)合表達(dá)式,您可以將此代碼用作未來項(xiàng)目的模板。
帶RTC的溫室水培控制器,帶DHT22的高度優(yōu)化室內(nèi)溫度控制器,以及無線傳感器上的DS18B20陣列,甚至HVAC的智能驅(qū)動:您可以用自己的技術(shù)實(shí)現(xiàn)想要的功能!審核編輯黃宇
-
晶體管
+關(guān)注
關(guān)注
77文章
9983瀏覽量
140750 -
邏輯運(yùn)算
+關(guān)注
關(guān)注
0文章
57瀏覽量
9931 -
Arduino
+關(guān)注
關(guān)注
189文章
6492瀏覽量
190174
發(fā)布評論請先 登錄
VCA810的直流偏置遠(yuǎn)大于芯片資料上的偏置電壓,為什么?
LabVIEW結(jié)構(gòu)的使用——條件結(jié)構(gòu)
請教,while循環(huán)中的布爾為真時(shí)如何觸發(fā)另一個(gè)DAQ任務(wù)的開始?
請問為什么dsp的運(yùn)算速度會遠(yuǎn)大于自身的主頻?
2.4 python布爾值
單片機(jī)ADC的采樣頻率和采樣速率是不是同一個(gè)概念?采樣頻率、速率要遠(yuǎn)遠(yuǎn)大于被采樣的信號頻率和速率?
提高多邊形布爾運(yùn)算健壯性的頂點(diǎn)融合技術(shù)_白萌
Shell程序設(shè)計(jì)的流程控制
基于大規(guī)模網(wǎng)絡(luò)模型間布爾運(yùn)算

基于延遲切割的三角網(wǎng)格布爾運(yùn)算優(yōu)化
四個(gè)方面分析一季度動力電池出貨量遠(yuǎn)大于裝機(jī)量

評論