0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Arduino和布尔运算:条件为真时永远大于零!

abdkjshd 来源:DevicePlus 作者:DevicePlus 2023-03-14 18:13 次阅读

这篇文章来源于DevicePlus.com英语网站的翻译稿。

目录
1 布尔逻辑运算
1.1 晶体管逻辑电路与二进制
2 示例
2.1 逻辑运算符
2.2 双继电器状态机

1 Arduino布尔逻辑运算

二进制和布尔运算有时候看起来就像是流行语一样,尤其是“二进制”,但这只是因为人们一旦了解了之后就会马上喜欢上这种思维模式。提示:它们就是法拉利的酷极客。
在这些事物的核心模块中,二进制属于机器的部分,如果您想要控制机器,尤其是微控制器,那么您必须时常对二进制进行深入研究。尤其是Arduino Uno(atmega328p),它只有2KB SRAM。这是一个精益系统,如果您想要它运行更大的项目,那就要很聪明地使用二进制才行。如果要将大型阵列存储在PROGMEM和EEPROM(闪存)中,您必须使用这个方法。

1.1 晶体管逻辑电路和二进制

“为什么不直接使用十进制系统?”这一问题非常重要,必须首先解答。一旦您理解了二进制系统的设计初衷,您就会更加喜欢布尔逻辑运算的。
设想有一个晶体管,它在任何给定时间都可能处于“ON”或“OFF”状态。该晶体管可以描述两个值(2**1)。但是,如果您想要计数更大的值该怎么办?添加另一个晶体管,您可以数到4(2**2),三个(2**3)可以让您数到8,以此类推。为了增加您的学习乐趣,可以打开一个python脚本,然后将以下内容复制粘贴到您的脚本中来查看8位/1字节的可能状态:


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字节:


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)

在十进制系统中,仅仅使用16个手指和脚趾不可能数出65,535只宝可梦(包括起始值0)。但是使用二进制就可以!
如果看起来有点晦涩难懂的话,不要气馁。把每个二进制数字想像成一个晶体管:1是“ON”,0是“OFF”。使用十进制系统来描述数字255需要256只晶体管(包括0),而使用二进制系统,我们可以只用8只晶体管来描述256种状态。它是“0b11111111”,8位为一个字节。它在早期的计算机实验室种节省了大量空间,因为那个时候晶体管既不小也不高效(您见过真空管吗?)。
这就是我们在平板电脑手机上玩Pokémon Go的时候计算所捕获宝可梦数量的方式。除了内存限制,它的计数大小是没有上限的。
使用Arduino时,我们使用“字节”型数据类型(实际上是uint_8t)来告诉编译器我们想要一个0-255范围内的值。然而,布尔型变量要简单得多!布尔型变量可以仅用一个晶体管来表示,真(true)为“ON”,假(false)为“OFF”。您可以使用一个很小的状态机来确定您的电机是否在运行,并在setup()函数之前对其进行全局声明。


bool is_motor_running = false ; // or 0


当电机启动时,您需要对其进行更新,使用以下代码:


// flip it, else use true/1
bool is_motor_running = ! is_motor_running ;

您可以使用它来控制系统的行为,例如,保证您的Arduino在电机运行时不进行任何操作。


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
    }
}

您可能已经注意到了符号“!”,这是逻辑非运算符,在人类语言中的意思是“不是”。Arduino C++中可用的关系运算符是“!=”、“>=”、“<=”、“>”,但今天讲述的是布尔逻辑运算。这与变量之间的关系无关(例如确定一个值是否大于另一个值),因为逻辑运算符“!”—逻辑非,“&&”—逻辑与,和“||”—逻辑或已经足以创建出令人生畏的复杂表达式了。虽然有时候我们称之为二进制运算符,但是不要偏离了方向。
如果到目前为止您都能理解了,可以查看更高级的逻辑运算。

2 示例

2.1 逻辑运算符

按照上面的二进制位,我们在实例中使用逻辑运算符。我们使用了Arduino IDE,请参阅此文的简介。
现在,让我们用二进制的方式读到“1”!


byte Sum = 0
bool Transistor1 = true ;
if ( Transistor1 ) Sum = 1
else if ( ! Transistor1 ) Sum = 0

这看似简单,但是功能非常强大。让我们做一个更长的复合表达!
[ 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弹出串行监视器,并输入一个4位值,以空格分隔,类似“1 0 1 0”这样的数据,然后按下“Send(发送)”。您将看到以下输出:
poYBAGPy04KAFg0FAACppYb5xoY441.png
如果幸运的话,您将看到以下内容:
pYYBAGPy04SAIIIeAADSSFsjBYE348.png
该Arduino草图展示了布尔逻辑运算的多种用途。无论在哪个应用中需要使用“真”,或者是“假”,我们都可以使用布尔逻辑运算。

2.2 双继电器状态机

2.1中的示例只是一个用来演示逻辑运算符的小程序。本节所创建的是一个有用的状态追踪中继模块,您可以进行修改和添加。将代码复制到Arduino IDE一个新的草图中,然后使用CTRL+U上传。然后,使用CTRL+SHIFT+M(或在Linux/MacOS上 使用“python3 -m serial.tools.miniterm”,Windows上使用TeraTerm/Putty)查看串行监视器。如果输入“0”并发送,则可以查看当前继电器状态(为“ON”或“OFF”)。
如果您输入“1”,您将切换到继电器1,如果它是“OFF”为“ON”,如果是“ON”则为“OFF”。发送“2”则会对继电器2进行相同的操作。对于这两个继电器,状态保存在布尔型变量(“relay1State”和“relay2State”)中,并且对于每个继电器,LED会在其真正为“ON”时亮起。
除了Arduino之外,不需要任何其他东西来使用该程序。制作之前先玩一下吧!
poYBAGPy04eARWWwAAGhBkSzraA898.jpg
以下代码是专门按照适合于在Arduino IDE上使用布尔值的方式来编写的。
硬件方面,我从不信任那些用于重载的蓝色5V继电器,但是已经确认了这些继电器在高达~200W的负载下性能良好。那么开始享受制作的乐趣吧!

2x 2N7000 N沟道MOSFET https://www.newark.com/on-semiconductor/2n7000/n-channel-mosfet-60v-200ma-to/dp/58K9650
2x ROHM SLR343BC4TT32 3mm 蓝色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 开始构建!

按下图所示将所有部件进行连接,首先是面包板,然后是原型板。我们就是这样做的。
pYYBAGPy04mAAnSxAALYQTditZU759.png
poYBAGPy04yAb9tbAAGxiL5bsbQ681.jpg
唯一需要注意的是正确使用BAT86肖特基二极管。您必须将阴极(BAT86上的黑环,通常在别的二极管上是白环)朝向继电器的正极端子(上图右侧),否则会出现问题(短路)。环标记了阴极(k),确保它与正极端子对齐!请看这张图,放大蓝色继电器的部分:
poYBAGPy04-AZ36HAAHtvQPaoks224.jpg
这是组装好的图片。Arduino Nano原型板上的附加组件内容不在本文的范围内,而且这部分也很无趣。

pYYBAGPy05SAFAR4AAHpyVo3jn4733.jpg

!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 ]
现在我们就有了状态追踪功能了,例如,我们可以查看当前的继电器状态,并且可以随意对其进行反转。我们已经介绍了带有逻辑运算符的复合表达式,您可以将此代码用作未来项目的模板。
带RTC的温室水培控制器,带DHT22的高度优化室内温度控制器,以及无线传感器上的DS18B20阵列,甚至HVAC的智能驱动:您可以用自己的技术实现想要的功能!

审核编辑黄宇

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

    关注

    77

    文章

    9562

    浏览量

    137256
  • 逻辑运算
    +关注

    关注

    0

    文章

    51

    浏览量

    9735
  • Arduino
    +关注

    关注

    187

    文章

    6455

    浏览量

    186191
收藏 人收藏

    评论

    相关推荐

    VCA810的直流偏置远大于芯片资料上的偏置电压,为什么?

    最近在使用压控芯片VCA810,感觉它的直流偏置远大于芯片资料上的偏置电压。但又找不到问题所在,下面是实验中0dB和10dB的交流、直流耦合的输出图形,输入信号有效值是110mV。0dB时控制电压
    发表于 09-13 07:20

    LabVIEW结构的使用——条件结构

    字显示控件。在程序框图上放置一个条件结构,调整边框合适大小。在比较运算子模板中选取“大于等于0?”函数,如果数字大于或者等于0则返回
    发表于 02-04 16:16

    请教,while循环中的布尔时如何触发另一个DAQ任务的开始?

    部分的布尔True时,触发 底下的for循环开始任务,经过n次循环后自动停止。当布尔再次时,for循环再次被触发并开始。其中圆圈部分的
    发表于 11-21 20:34

    请问为什么dsp的运算速度会远大于自身的主频?

    c6747主频最高456-MHz,而Peak MMACS可以达到达3648。浮点运算能力可达 2736MFLOPS.请问为什么dsp的运算速度会远大于自身的主频?dsp如何在一个时钟
    发表于 05-25 16:25

    2.4 python布尔

    返回值是True或者False的过程都可以称为布尔运算,例如比较运算布尔值通常用来判断条件是否成立。age = 16if age >= 18: print("你是个成年人"
    发表于 02-21 16:11

    单片机ADC的采样频率和采样速率是不是同一个概念?采样频率、速率要远远大于被采样的信号频率和速率?

    单片机ADC的采样频率和采样速率是不是同一个概念?采样频率、速率要远远大于被采样的信号频率和速率?
    发表于 11-15 19:09

    STM32F4 ADC采样速率远大于输入信号频率怎么办呢?

    STM32F4 ADC采样速率远大于输入信号频率怎么办呢?
    发表于 05-09 14:26

    提高多边形布尔运算健壮性的顶点融合技术_白萌

    提高多边形布尔运算健壮性的顶点融合技术_白萌
    发表于 03-15 14:07 0次下载

    Shell程序设计的流程控制

    和其他高级程序设计语言一样,Shell提供了用来控制程序执行流程的命令,包括条件分支和循环结构,用户可以用这些命令创建非常复杂的程序。 与传统语言不同的是,Shell用于指定条件值的不是布尔运算
    发表于 11-07 11:07 0次下载

    基于大规模网络模型间布尔运算

    为了解决产品设计阶段中大规模网格模型间的布尔运算无法实现立等可得的速度瓶颈,提出了一种新算法。该算法利用离散化采样获得射线段点云模型,将三角面片间的3D布尔运算转换为射线段间的1D布尔运算,对相交处
    发表于 11-30 17:39 0次下载
    基于大规模网络模型间<b class='flag-5'>布尔运算</b>

    基于延迟切割的三角网格布尔运算优化

    规则化的布尔运算被广泛应用在三维建模系统中.近年来,随着图形硬件的发展,基于三角网格的规则化布尔算法由于输出结果能直接被图形硬件处理,表现出了明显的优势.但是传统的算法由于采用CSG树局部评估策略
    发表于 01-08 13:59 0次下载

    四个方面分析一季度动力电池出货量远大于装机量

    GGII调研数据显示,2018年第一季度中国动力电池出货量8.6GWh,一季度动力电池装机量4.41GWh,出货量远大于装机量。
    的头像 发表于 05-03 15:30 6443次阅读
    四个方面分析一季度动力电池出货量<b class='flag-5'>远大于</b>装机量

    折叠屏手机短时间内难普及,概念意义远大于实用

    尽管,多家国产厂商都已经明确表示,要发布折叠屏手机,但目前来看,其概念意义要远远大于实用。
    发表于 02-17 11:44 1160次阅读

    python布尔值是什么

    表达式调用返回值是True或者False的过程都可以称为布尔运算,例如比较运算布尔值通常用来判断条件是否成立。 age = 16if age = 18: print("你是个成年人
    的头像 发表于 02-21 16:10 6743次阅读

    逻辑运算符两侧运算对象的数据类型是

    符包括与运算()、或运算(||)和非运算(!)。与运算符用于判断两个条件是否同时
    的头像 发表于 11-30 14:15 1441次阅读