arduino pinmodeswich pin设置成high是关掉的意思?

本文所属图书&>&
采用Arduino进行电子制作越来越流行,在网络上可以找到很多用Arduino制作机器人、媒体互动产品、电子创意项目的案例。本书用50个项目来介绍Arduino的应用,从最基础的输入输出项目逐渐进入较高级的话题,比如Ard...&&
&代码的第一行如下所示:
//项目1 && LED闪灯器
这是你的代码中的说明文字。可以叫它们注释,因为它是以&//&开始的,这个符号后面所有的文字编译器都将忽略。注释在代码中是非常有用的,它帮助你理解代码是如何工作的。如果你的项目非常复杂,代码超过了几百行,甚至几千行,注释是非常重要的,它使你很容易知道每一段代码的作用。你可能会写出一段迷人的代码,但是,你不可能永远记得它是如何工作的,而注释可以使你回忆起代码的功能。同样,如果你要给其他人看你编写的代码,注释将帮助别人理解你的代码。Arduino的灵魂即它的开放性,是分享代码和原理图。因此我希望当你用Arduino开始做你自己的项目时,也要将它与其他人分享。还有另外一种写注释的方式,它是一个说明块,用/*和*/括起来,例如以下文字:
/* All of the text within
the slash and the asterisks
is a comment and will be
ignored by the compiler */
IDE将自动把注释文字的颜色转化成灰色。程序接下来的一行是这样的:
int ledPin = 10;
这就是所谓的变量,变量是用来存储数据的。在上面的例子里定义了一个变量,类型是int或者说整型。整型表示一个数,范围在&#到32767之间,接下来指定了这个整型数的名字是ledPin,并且给它赋了一个值10。(可以不叫它ledPin,你可以叫它任何你想叫的东西,但是希望你的变量名是有一定意义的,叫它ledPin说明这个变量表示将要去与LED相连的Arduino的引脚。)在这里,使用数字引脚10。在这个声明的结尾是一个分号,它告诉编译器这个声明到此结束。
虽然可以给变量设置任何名字,但在C语言中,变量名必须以一个字母开头,之后可以包含字母、数字和下画线。注意C语言认为大小写字母是不同的。最后,不能使用C语言的任何保留字作为变量名,如main、while、switch等。保留字是常量、变量和函数名,这些都被定义为Arduino语言的一部分。为了避免使用保留字作为变量名,所有保留字在程序中都显示为红色。
想象变量是一个小盒子,在那里存储着东西,在这个程序中,变量在内存中开辟了一个小空间用来存储一个整数,以上的定义表示在变量开辟的存储空间内存了一个数字10。
最后,变量之所以叫变量是因为可以改变它的值。稍后,将对变量进行数学计算以使程序能够做更复杂的事情。
接下来是setup()函数:
void setup() {
&pinMode(ledPin, OUTPUT);
Arduino程序必须包含setup()和loop()两个函数,否则它将不能工作。setup函数只在程序的开头运行一次。在这个函数里可以在主循环开始前为程序设定一些通用的规则,如设置引脚形式、设置波特率等。一般情况下,函数是一组集合在一个程序块中的代码。例如,如果生成一个函数来完成一系列复杂的数学计算,它有好几行代码,这些代码可以运行很多次,每次使用这些代码时只要简单地调用函数名即可,而无须每次都把这些代码重新再写一遍。当你开始动手做自己的项目时,你将对函数有更深入的了解。在本程序里,setup()函数只有一行声明。函数从以下形式开始:
void setup()
它告诉编译器函数叫setup,它不返回数据(void),并且不传递参数给它(空括号),如果函数返回整型值,并且需要给它传递一个整型数(如让函数处理)作为参数,它可以写成如下形式:
int myFunc(int x,int y)
在这里,所生成的函数(或一段代码)叫做myFunc。需要给这个函数传递两个整数作为参数,叫做x和y,如果函数运行完成,它将在程序调用函数处返回一个整数值。
函数中的所有代码在两个花括号之间,&{&符号在代码块的开头,&}&符号在代码块的结尾。这两个符号之间的任何东西都是属于这个函数的。(我将在后面进一步详细地说明函数,所以现在请不必着急。)
在这个程序里有两个函数,一个函数叫做setup,它的目的是在主要的loop函数运行之前为程序做必要的设置。
void setup() {
&pinMode(ledPin, OUTPUT);
setup函数内只有一条语句,那就是pinMode函数,这个函数告诉Arduino设置引脚的模式为输出模式,而不是输入模式。在函数后面的括号内,设定了引脚号和模式(OUTPUT或INPUT),引脚号是ledPin,它在这之前已经被设置为数值10。因此,这条语句只是简单地告诉Arduino数字引脚10被设置为OUTPUT模式。因为setup()函数只运行一次,现在程序移动到主函数loop:
void loop() {
&digitalWrite(ledPin, HIGH);
&delay(1000);
&digitalWrite(ledPin, LOW);
&delay(1000);
loop()函数是主要的过程函数,只要Arduino打开就一直运行。每一条loop()函数(在花括号内的代码)中的代码都要执行,并按顺序逐个执行,直到函数的最后。然后loop函数再次开始,从函数顶部开始运行,一直这样循环下去,直到关闭Arduino或者按下重启按钮。
在这个项目中,希望LED灯亮,保持1秒,然后关闭,保持1秒,并且重复以上动作。因为你希望反复地做以上动作,所以告诉Arduino要这样做的命令设置在loop()函数内。函数内第一个语句是:
digitalwrite(ledPin,HIGH);
在这个语句中,写一个HIGH或LOW值到引脚(在这个例子里,引脚是数字引脚10),设置一个HIGH到引脚中,将输出一个5V电压到那个引脚,当设置引脚为LOW时,这个引脚变成0V,或者地,因此上面的声明表示输出一个5V电压到引脚10,这就点亮了LED。之后的代码是:
delay(1000);
这条语句只是告诉Arduino在执行下一条语句之前等待1000毫秒(1000毫秒是1秒)。下一条语句是:
digitalwrite(ledPin, LOW);
该语句将关闭数字引脚10的电源,因此会熄灭LED。之后是另外一个延时1000毫秒的语句,然后函数结束。然而,因为这个函数是主loop()函数,所以这个函数将重新从头开始执行。
再一步一步看以上程序,你会发现程序是非常简单的。
//项目1 && LED 闪灯器
int ledPin = 10;
void setup() {
& pinMode(ledPin, OUTPUT);
void loop() {
&digitalWrite(ledPin, HIGH);
&delay(1000);
&digitalWrite(ledPin, LOW);
&delay(1000);
从指定一个名为ledPin的变量开始,向这个变量赋值10。之后,执行setup()函数,此处设置数字引脚10为输出模式。在主程序循环里设置数字引脚10为HIGH,输出为5V,之后等待1秒,关闭数字引脚10的5V电源,等待1秒,之后,loop重新开始执行。只要Arduino上电,LED将持续地交替开关。
现在你已经知道代码是如何工作的了,你可以通过改变代码去打开LED并保持一段不同的时间,关闭LED并保持一段不同的时间。例如,想要持续打开2秒,之后关闭0.5秒,可以按照下面这样做:
void loop() {
&digitalWrite(ledPin, HIGH);
&delay(2000);
&digitalWrite(ledPin, LOW);
&delay(500);
如果想要LED保持关闭5秒,然后短暂地闪烁一下(250毫秒),如同汽车报警器上的LED指示灯那样,可以这样做:
void loop() {
&digitalWrite(ledPin, HIGH);
&delay(250);
&digitalWrite(ledPin, LOW);
&delay(5000);
如果想让LED快速开关闪烁,尝试以下方式:
void loop() {
&digitalWrite(ledPin, HIGH);
&delay(50);
&digitalWrite(ledPin, LOW);
&delay(50);
通过改变LED开和关的时间,可以产生任何你希望看到的效果(当然是在单个LED开和关范围内的效果)。在做一些更有意思的东西之前,让我们看一下硬件,看看硬件是如何工作的。
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。
文章下载读书温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
一只笨鸟,却有刨根问底的精神
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
看了几天流水灯的代码,也实践了自己的流水灯,终于悟出,原来LED灯在电路的接法可以有高电平使能和低电平使能两种,而非自己想当然的高电平才能让灯点亮,具体电路的接法在网上搜索之可以找到。拿我这块优龙FS2410的开发板来说,其LED电路就是低电平使能,如下:&因为左边接了VCC,是高电平,而且由LED的接法可知,电流从LED左边流进,右边流出才能点亮,所以如果GPIO是输出高电平,那两边都是同样数值的高电平就导致没有电流(也就是说,有电势差,也就是电压才会有电流),所以必须设置GPIO为低电平输出,也就是说不能上拉,有了高低的电势差,也就是电压,才会有电流,由高电势流向低电势。所以上面的电路接法,是低电平有效或者说使能。还有几个重要概念,高电平/低电平使能,上拉下拉,其实还是没有理解透彻,对于一个硬件电路完全无知者,只有高中电路基础的人,还是有些困难= =| 不过也不妨总结一下:1. 由下面转载的英文可知,上拉电阻是指当pin接到VCC(高电平)时所接的电阻即为Pull up 电阻,反之亦然,pin接地时所接的电阻即pull down电阻2. 上拉寄存器是控制对应端口上拉使能的。当对应位为0时,设置对应引脚上拉使能,为1时,禁止对应引脚上拉使能。如果上拉寄存器使能,无论引脚功能寄存器如何设置(输入,输出,数据,中断等),对应引脚输出高电平。3. pin输出低电平时,将允许外部器件,向pin内灌入电流,这个电流,称为“灌电流”,外部电路称为“灌电流负载”;pin输出高电平时,则允许外部器件,从pin拉出电流,这个电流,称为“拉电流”,外部电路称为“拉电流负载”。下面是网上转来的对我理解这个概念有不小帮助的内容,先来一段简单的,对非电子专业的同学似乎看起来比较通俗易懂:外围器件输入口都会限制输入电流最小值和最大值。GPIO驱动能力很弱,甚至驱动一个LED都有问题,当GPIO驱动能力不足,达不到外围器件输入口最小值的时候加上拉电阻可以提高电平的值。反之,下拉电阻就是在GPIO口电流大于外围器件输入最大值的时候降低电流,以达到外设的输入电流要求。因此,GPIO设置为上拉还是下拉是看你该GPIO口连接的具体外围器件的要求。下面的就高级了,取自一老外博客,&&,写的很基础很好,图文并茂,可了解什么叫Pull up/Pull down RegisterWorking a lot with Raspberry Pi and Arduino stuff lately. The concept of pull-up and pull-down resistors came up quickly and confused me a little at first. So I thought I’d do a little demo of how they work and why they are needed. Doing this helped to clarify it for me, so maybe it’ll help you too.Common scenario. You want to set up something that reads an input of a GPIO pin. Say, you want to know when the user is pressing a switch. You set up a simple circuit like so:And here that is wired up:When you press the button, pin 25 goes high. No press, no high, must be low, right? Well, let’s see…We’ll set up a simple Python script to read the status of pin 25:1234567891011121314151617#! /usr/bin/python&import RPi.GPIO as GPIOimport time&PIN = 25&GPIO.setmode(GPIO.BCM)GPIO.setup(PIN, GPIO.IN)&while True:&&&&&&&&if GPIO.input(PIN) == GPIO.HIGH:&&&&&&&&&&&&&&&&print("pin is high")&&&&&&&&&&&&&&&&time.sleep(.1)&&&&&&&&else:&&&&&&&&&&&&&&&&print("pin is low")&&&&&&&&&&&&&&&&time.sleep(.1)When I run this, I get 20-30 lines saying pin 25 is high, then 20-30 saying it’s low, back and forth, without touching the button. Sure enough when I press the button, it stays high, but apparently the definition of “low” is not “not high”.After too many years in the highly binary world of software programming, some of us delving into hardware may be surprised to learn that a lot of electronics operate on “tri-state logic” as opposed to simple binary. Here, an input can be high, low, or floating. In this particular circuit, high means connected to 3.3 volts, low means connected to ground, and floating means… neither or somewhere in between. Actually, due to the sensitive nature of tiny electronics, system components can pick up various signals that create slight fluctuations in what it is reading. It’s rarely if ever going to pick up exactly 0.000 volts just because it’s not connected to 3.3 volts.So we need to force the issue and say, “Yo! You are LOW!” My first thought on how to do this would probably have been to do something like this:When the switch is in one position, pin 25 is connected directly to ground, sending it solidly low. When the switch is changed, it connects 25 to 3.3 volts, making it high. This will work just fine, but it’s a bit overengineered as it turns out.How about if we go simpler and just connect pin 25 to ground and leave it that way, like so:(Note: DO NOT ACTUALLY BUILD THIS CIRCUIT!)Now, when the switch is open, pin 25 is undoubtedly low. But we have a problem that when you do hit the switch, you now have a short circuit directly between 3.3 volts and ground. Not good. Again, do not do this. The solution? Throw a resistor in there:And in the real world:Now, when the switch is open, pin 25 is connected to ground through the 10K resistor. Even with the resistor though, it’s enough of a connection to make it solidly low. It’s not going to fluctuate.Then we hit the switch, connecting the lower part of the circuit to the 3.3 volts. Because we have a fairly high resistance there, most of the current is going to go to pin 25, sending it solidly high. Some of it is also going to go to ground via R1. But Ohm’s Law tells us that 3.3 volts divided by 10,000 ohms will let about 0.33 milliamps in. That’s not going to break the bank.So in this circuit, R1 is called a pull-down resistor because in its default state it pulls the signal down to 0 volts or a low state.Now let’s swap things around a bit:Now pin 25 is hard-wired to 3.3 volts through R1, making its default state high. However when the button is pressed, pin 25 will be directly connected to ground, sending it low. Because the resistor pulls pin 25 up to 3.3 volts and a high state, it’s now known as a pull-up resistor.So, which one do you use? It depends on whether you want your default signal to be high or low.Hope that helps.
阅读(14126)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_084070',
blogTitle:'关于GPIO PULL UP & Pull Down的理解',
blogAbstract:'个人总结:up/down 的是什么呢?个人理解为电平,电平又是个很抽象的概念,不同于我们都知道的电压电流功率等单位,具体可搜索之,在这里,我们可以把电平简单理解为电压。datasheet中对GPIO的描述中有:The port pull-up register controls the pull-up resister enable/disable of each port group. When the corresponding bit is&0, the pull-up resister of the pin is enabled. When 1, the pull-up resister',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:4,
publishTime:3,
permalink:'blog/static/',
commentCount:1,
mainCommentCount:1,
recommendCount:2,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'一只笨鸟,却有刨根问底的精神',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}Arduino 语法手册变量部分_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Arduino 语法手册变量部分
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩15页未读,
定制HR最喜欢的简历
你可能喜欢Arduino 的程序可以划分为三个主要部分:结构、变量(变量与常量)、函数。
1.1 setup()
1.2 loop()
二、结构控制
2.2 if...else
2.4 switch case
2.6 do... while
2.8 continue
2.9 return
三、扩展语法
3.1 ;(分号)
3.2 {}(花括号)
3.3 //(单行注释)
3.4 /* */(多行注释)
3.5 #define
3.6 #include
四、算数运算符
4.1 =(赋值运算符)
4.2 +(加)
4.3 -(减)
4.4 *(乘)
4.5 /(除)
4.6 %(模)
五、比较运算符
5.1 ==(等于)
5.2 !=(不等于)
5.3 &(小于)
5.4 &(大于)
5.5 &=(小于等于)
5.6 &=(大于等于)
六、布尔运算符
6.1 &&(与)
6.2 ||(或)
6.3 !(非)
七、指针运算符
7.1 * 取消引用运算符
7.2 & 引用运算符
八、位运算符
8.1 & (bitwise and)
8.2 | (bitwise or)
8.3 ^ (bitwise xor)
8.4 ~ (bitwise not)
8.5 && (bitshift left)
8.6 && (bitshift right)
九、复合运算符
9.1 ++ (increment)
9.2 -- (decrement)
9.3 += (compound addition)
9.4 -= (compound subtraction)
9.5 *= (compound multiplication)
9.6 /= (compound division)
9.6 &= (compound bitwise and)
9.8 |= (compound bitwise or)
10.1 HIGH|LOW(引脚电压定义)
10.2 INPUT|OUTPUT(数字引脚(Digital pins)定义)
10.3 true | false(逻辑层定义)
10.4 integer constants(整数常量)
10.5 floating point constants(浮点常量)
十一、数据类型
11.2 boolean(布尔)
11.3 char(有号数据类型)
11.4 unsigned char(无符号数据类型)
11.5 byte(无符号数)
11.6 int(整型)
11.7 unsigned int(无符号整型)
11.9 long(长整数型)
11.10 unsigned long(无符号长整数型)
11.11 float(浮点型数)
11.12 double(双精度浮点数)
11.13 string(char array/字符串)
11.14 String& object(String类)
11.15 array (数组)
十二、数据类型转换
12.1 char()
12.2 byte()
12.3 int()
12.4 word()
12.5 long()
12.6 float()
十三、变量作用域 & 修饰符
13.1 variable scope(变量的作用域)
13.2 static(静态变量)
13.3 volatile
13.4 const
十四、辅助工具
14.1 sizeof()
十五、数字 I/O
15.1 pinMode()
15.2 digitalWrite()
15.3 digitalRead()
十六、模拟 I/O
16.1 analogReference()
16.2 analogRead()
16.3 analogWrite()& PWM
十七、高级 I/O
17.1 tone()
17.2 noTone()
17.3 shiftOut()
17.4 shiftIn()
17.5 pulseIn()
十八、时间
18.1 millis()
18.2 micros()
18.3 delay()
18.4 delayMicroseconds()
十九、数学运算
19.1 min()
19.2 max()
19.3 abs()
19.4 constrain()
19.5 map()
19.6 pow()
19.7 sqrt()
19.8 ceil()
19.9 exp()
19.10 fabs()
19.11 floor()
19.12 fma()
19.13 fmax()
19.14 fmin()
19.15 fmod()
19.16 ldexp()
19.17 log()
19.18 log10()
19.19 round()
19.20 signbit()
19.21 sq()
19.22 square()
19.23 trunc()
二十、三角函数
20.1 sin()
20.2 cos()
20.3 tan()
20.4 acos()
20.5 asin()
20.6 atan()
20.7 atan2()
20.8 cosh()
20.9 degrees()
20.10 hypot()
20.11 radians()
20.12 sinh()
20.13 tanh()
二十一、随机数
21.1 randomSeed()
21.2 random()
二十二、位操作
22.1 lowByte()
22.2 highByte()
22.3 bitRead()
22.4 bitWrite()
22.5 bitSet()
22.6 bitClear()
22.7 bit()
二十三、设置中断函数
23.1 attachInterrupt()
23.2 detachInterrupt()
二十四、开关中断
24.1 interrupts()(中断)
24.2 noInterrupts()(禁止中断)
二十五、通讯
25.1 Serial
& 25.1.1 if (Serial)
25.1.2 Serial.available()
25.1.3 Serial.begin()
25.1.4 Serial.end()
25.1.5 Serial.find()
25.1.6 Serial.findUntil()
25.1.7 Serial.flush()
25.1.8 Serial.parseFloat()
25.1.9 Serial.parseInt()
25.1.10 Serial.peek()
25.1.11 Serial.print()
25.1.12 Serial.println()
25.1.13 Serial.read()
25.1.14 Serial.readBytes()
25.1.15 Serial.readBytesUntil()
25.1.16 Serial.setTimeout()
25.1.17 Serial.write()
25.1.18 Serial.SerialEvent()
25.2 Stream
二十六、USB(仅适用于 Leonardo 和 Due)
26.1 Mouse(键盘)
26.2 Keyboard(鼠标)
以下是示例部分含详细注解
1.1 setup()
在Arduino中程序运行时将首先调用
setup() 函数。用于初始化变量、设置针脚的输出\输入类型、配置串口、引入类库文件等等。每次 Arduino 上电或重启后,setup 函数只运行一次。
int buttonPin = 3;//定义一个变量buttonPin为针脚3
void setup()
& Serial.begin(9600);//定义初始串口波特率为9600
& pinMode(buttonPin, INPUT);//定义buttonPin也就是前面定义的针脚3为input输入针脚
void loop()
1.2 loop()
在 setup() 函数中初始化和定义了变量,然后执行 loop() 函数。顾名思义,该函数在程序运行过程中不断的循环,根据一些反馈,相应改变执行情况。通过该函数动态控制 Arduino 主控板。
int buttonPin = 3;& // setup 中初始化串口和按键针脚.
void setup()
& beginSerial(9600);
& pinMode(buttonPin, INPUT);
// loop 中每次都检查按钮,如果按钮被按下,就发送信息到串口
void loop()
& if (digitalRead(buttonPin)
== HIGH)//通过eigitalRead读取到针脚3的电平值是否为高
&&& serialWrite('H');//是高就通过串口写出H
&&& serialWrite('L');//如果不是就通过串口写出L
& delay(1000);//延时1000毫秒,也就是1秒
二、结构控制
if(条件判断语句)和 ==、!=、&、&(比较运算符)
if 语句与比较运算符一起用于检测某个条件是否达成,如某输入值是否在特定值之上等。if 语句的语法是:
if (someVariable & 50)
& // 执行某些语句
本程序测试
someVariable 变量的值是否大于 50。当大于 50 时,执行一些语句。换句话说,只要 if 后面括号里的结果(称之为测试表达式)为真,则执行大括号中的语句(称之为执行语句块);若为假,则跳过大括号中的语句。 if 语句后的大括号可以省略。若省略大括号,则只有一条语句(以分号结尾)成为执行语句。
&下面几种写法都是正确的:
if (x & 120) digitalWrite(LEDpin, HIGH);//判断x的值是不是大于120,是的话就让LEDpin这个针脚的电平成为高电平
if (x & 120)
digitalWrite(LEDpin, HIGH);&
if (x & 120){ digitalWrite(LEDpin, HIGH); }
if (x & 120){
& digitalWrite(LEDpin1, HIGH);
& digitalWrite(LEDpin2, HIGH);
} & & & & & & & & & & & & & & & &
在小括号里求值的表达式,需要以下操作符:
比较运算操作符:
&x == y(x 等于 y)注意这是等于,并不是赋值,赋值是=
&x != y(x 不等于 y)
&x && y(x 小于 y)
&x && y(x 大于 y)
&x &= y(x 小于等于 y)
&x &= y(x 大于等于 y)
注意使用赋值运算符的情况(如 if (x = 10))。一个“=”表示的是赋值运算符,作用是将 x 的值设为 10(将值 10 放入 x 变量的内存中)。两个“=”表示的是比较运算符(如 if (x == 10)),用于测试 x 和 10 是否相等。后面这个语句只有 x 是 10 时才为真,而前面赋值的那个语句则永远为真。
这是因为 C 语言按以下规则进行运算
if (x=10):10 赋值给 x(只要非 0 的数赋值的语句,其赋值表达式的值永远为真),因此 x 现在值为 10。此时 if 的测试表达式值为 10,该值永远为真,因为非 0 值永远为真。所以,if (x = 10) 将永远为真,这就不是我们运行 if 所期待的结果。另外,x 被赋值为 10,这也不是我们所期待的结果。
if 的另外一种分支条件控制结构是 if...else 形式。
2.2 if...else
if/else是比if更为高级的流程控制语句,它可以进行多次条件测试。比如,检测模拟输入的值,当它小于500时该执行哪些操作,大于或等于500时执行另外的操作。代码如下:
if (pinFiveInput & 500)
& // 执行A操作
& // 执行B操作
else可以进行额外的if检测,所以多个互斥的条件可以同时进行检测。
测试将一个一个进行下去,直到某个测试结果为真,此时该测试相关的执行语句块将被运行,然后程序就跳过剩下的检测,直接执行到if/else的下一条语句。当所有检测都为假时,若存在else语句块,将执行默认的else语句块。
注意else if语句块可以没有else语句块。else if分支语句的数量无限制。
if (pinFiveInput & 500)
& // 执行A操作
else if (pinFiveInput &= 1000)
& // 执行B操作
& // 执行C操作
另外一种进行多种条件分支判断的语句是switch case语句。
for语句用于重复执行一段在花括号之内的代码。通常使用一个增量计数器计数并终止循环。for语句用于重复性的操作非常有效,通常与数组结合起来使用来操作数据、引脚。
for循环开头有3个部分:
(初始化;条件;增量计数){
“初始化”只在循环开始执行一次。每次循环,都会检测一次条件;如果条件为真,则执行语句和“增量计数”,之后再检测条件。当条件为假时,循环终止。&
//用PWM引脚将LED变暗
int PWMpin = 10; //将一个LED与47Ω电阻串联接在10号针脚
void setup()
//无需设置
void loop()
&& for (int i=0; i &= 255;
i++)//定义一个变量i,并赋值为0,当i小于等于255的时候i就加1,也可写成i+=5,这样每循环一次i就加5
&&&&& analogWrite(PWMpin, i);//让10号针脚的电平改变为i
&&&&& delay(10);//延时10毫秒
C语言的for循环语句比BASIC和其他电脑编程语言的for语句更灵活。除了分号以外,其他3个元素都能省略。同时,初始化,条件,增量计算可以是任何包括无关变量的有效C语句,任何C数据类型包括float。这些不寻常的for语句可能会解决一些困难的编程问题。
例如,在增量计数中使用乘法可以得到一个等比数列:
for(int x = 2; x & 100; x = x * 1.5){//定义X为2,当X小于100的时候X重新赋值为它自己的1.5倍
println(x);//打印输出x的值
生成:2,3,4,6,9,13,19,28,42,63,94
另一个例子,使用for循环使LED产生渐亮渐灭的效果:
int PWMpin = 10; //将一个LED与47Ω电阻串联接在10号针脚
void setup()
//无需设置
void loop()
&& int x = 1; &//定义一个整数变量x赋值为1
&& for (int i = 0; i & -1;
i = i + x) &//定义i为0当i小于负一的时候,i的值为它自己加上X,也就是加上1,灯就依次变亮了
&&&&& analogWrite(PWMpin, i); &//让PWMpin针脚的电平变为i
&&&&& if (i == 255) x =
-1; & // 当i等于最大值255的时候,把x改变为负一,这样再循环上去的时候i的值就会依次减一,就由亮变暗了
&&&& delay(10); &//延时10毫秒,如果还想让灯由暗变亮的话就再写个判断
  &if(i==0) x=1; &//当i减小到0的时候又把x变成1,这样i就又依次加1,灯由暗变亮了
  &delay(10);
2.4 switch case
switch / case语句
和if语句相同,switch…case通过程序员设定的在不同条件下执行的代码控制程序的流程。特别地,switch语句将变量值和case语句中设定的值进行比较。当一个case语句中的设定值与变量值相同时,这条case语句将被执行。
关键字break可用于退出switch语句,通常每条case语句都以break结尾。如果没有break语句,switch语句将会一直执行接下来的语句(一直向下)直到遇见一个break,或者直到switch语句结尾。
语法也是先switch然后跟括号()括号内写上变量值,后面跟大括号,大括号里写上case分支
switch (var) {
case 1: &//case 1后面是冒号
& //当var等于1时,执行一些语句
& //当var等于2时,执行一些语句
& //如果没有任何匹配,执行default
& //default可有可不有
switch (var) { &//定义检查var的值
case label1: &//如果var的值是label1的就就执行下面的语句
& // 程序语句
case label2:&//如果var的值是label2的就就执行下面的语句
& //程序语句
default: & //如果var的值都不在上面的里面的话就执行下面的语句
& //程序语句
var: 用于与下面的case中的标签进行比较的变量值
label: 与变量进行比较的值&
while循环会无限的循环,直到括号内的判断语句变为假。必须要有能改变判断语句的东西,要不然while循环将永远不会结束。这在您的代码表现为一个递增的变量,或一个外部条件,如传感器的返回值。&
while(表达){
表达:为真或为假的一个计算结果
var = 0; & //定义一个变量var赋值为0
while(var & 200){ &//当var的值小于200的时候执行下面的语句
var++ & //var依次加1,加200次,直到var的值不小于200为止
2.6 do...while
do…while循环与while循环运行的方式是相近的,不过它的条件判断是在每个循环的最后,所以这个语句至少会被运行一次,然后才被结束。
}while(测试条件);&
delay(50); //延时50秒
X = readSensors(); //给X赋值
}while(X &100);& //当x小于100时,继续运行,当x不小于100的时候就不运行了
break用于退出do,for,while循环,能绕过一般的判断条件。它也能够用于退出switch语句。&
for (x = 0; x & 255; x ++)
&&& digitalWrite(PWMpin, x);
&&& sens =
analogRead(sensorPin);&
&&& if (sens &
threshold){&
&&&&&& x = 0;
& //这里用break就打断循环了,相当于在此结束了,程序就不再循环了
&&& delay(50);
2.8 continue
continue语句跳过当前循环中剩余的迭代部分( do,for 或 while )。它通过检查循环条件表达式,并继续进行任何后续迭代。&
for (x = 0; x & 255; x ++)
&&& if (x & 40 && x
& 120){ & & &
&&&&&&& & // 当x在40与120之间时,跳过后面两句,即迭代。
&&&& digitalWrite(PWMpin, x);
&&& delay(50);
2.9 return
终止一个函数,如有返回值,将从此函数返回给调用函数。
// 两种形式均可
value:任何变量或常量的类型
一个比较传感器输入阈值的函数&
&int checkSensor(){ & //这儿定义了一个整数形函数checkSensor
&&& if (analogRead(0) &
400) { & &//如果读取0针脚的数据大于400的话
&&&&&&& return 1;} & //返回1,相当于调用这个函数后得到的值是1
&&&&&&& return 0; & &//返回0,相当于调用这个函数后得到的值是0
return关键字可以很方便的测试一段代码,而无需“comment out(注释掉)”
大段的可能存在bug的代码。
void loop(){
&//写入漂亮的代码来测试这里。
&//剩下的功能异常的程序
//return后的代码永远不会被执行
程序将会从程序中已有的标记点开始运行,这个东西,少用
&&& //从label处开始运行
不要在C语言中使用goto编程,某些C编程作者认为goto语句永远是不必要的,但用得好,它可以简化某些特定的程序。许多程序员不同意使用goto的原因是, 通过毫无节制地使用goto语句,很容易创建一个程序,这种程序拥有不确定的运行流程,因而无法进行调试。感觉就像你明明在1上一下就跳到了8上,并 不是从上而下的过程。
的确在有的实例中goto语句可以派上用场,并简化代码。例如在一定的条件用if语句来跳出高度嵌入的for循环。&
for(byte r = 0; r & 255; r++){
& for(byte g = 255; g & -1;
&&& for(byte b = 0; b &
255; b++){
&&&&& if (analogRead(0) &
& //这儿有一个goto语句所以程序会跳转到下一个bailout
&&&&& //更多的语句...
bailout: & //goto语句跳转到这儿继续执行
&三、扩展语法
3.1 ;(分号)
用于表示一句代码的结束。
int a = 13;
在每一行忘记使用分号作为结尾,将导致一个编译错误。错误提示可能会清晰的指向缺少分号的那行,也可能不会。如果弹出一个令人费解或看似不合逻辑的编译器错误,第一件事就是在错误附近检查是否缺少分号。
3.2 {}(花括号也称大括号)
大括号(也称为“括号”或“大括号”)是C编程语言中的一个重要组成部分。它们被用来区分几个不同的结构,下面列出的,有时可能使初学者混乱。
左大括号“{”必须与一个右大括号“}”形成闭合。这是一个常常被称为括号平衡的条件。在Arduino IDE(集成开发环境)中有一个方便的功能来检查大括号是否平衡。只需选择一个括号,甚至单击紧接括号的插入点,就能知道这个括号的“伴侣括号”。
目前此功能稍微有些错误,因为IDE会经常会认为在注释中的括号是不正确的。
对于初学者,以及由BASIC语言转向学习C语言的程序员,经常不清楚如何使用括号。毕竟,大括号还会在”return函数”、“endif条件句”以及“loop函数”中被使用到。
由于大括号被用在不同的地方,这有一种很好的编程习惯以避免错误:输入一个大括号后,同时也输入另一个大括号以达到平衡。然后在你的括号之间输入回车,然后再插入语句。这样一来,你的括号就不会变得不平衡了。
不平衡的括号常可导致许多错误,比如令人费解的编译器错误,有时很难在一个程序找到这个错误。由于其不同的用法,括号也是一个程序中非常重要的语法,如果括号发生错误,往往会极大地影响了程序的意义。
大括号中的主要用途
功能 &函数
void myfunction(datatype argument){
& statements(s)
while (boolean expression)
& statement(s)
& statement(s)
& while (boolean expression);
for ( t incrementing expr)
& statement(s)
if (boolean expression)
& statement(s)
else if (boolean expression)
& statement(s)
& statement(s)
3.3 //(单行注释)
Comments(注释)
注释用于提醒自己或他人程序是如何工作的。它们会被编译器忽略掉,也不会传送给处理器,不会执行,所以它们在Atmega芯片上不占用体积。
注释的唯一作用就是使你自己理解或帮你回忆你的程序是怎么工作的或提醒他人你的程序是如何工作的。编写注释有两种写法:
&x = 5;& // 这是一条注释斜杠后面本行内的所有东西是注释
&/* 这是多行注释-用于注释一段代码
&if (gwb == 0){&& // 在多行注释内可使用单行注释
x = 3;&&&&&&&&&& /* 但不允许使用新的多行注释-这是无效的
// 别忘了注释的结尾符号-它们是成对出现的!
当测试代码的时候,注释掉一段可能有问题的代码是非常有效的方法。这能使这段代码成为注释而保留在程序中,而编译器能忽略它们。这个方法用于寻找问题代码或当编译器提示出错或错误很隐蔽时很有效。
3.4 /* */(多行注释)
Comments(注释)
上面已经讲过了跟单行同类型
&x = 5;& // 这是一条注释斜杠后面本行内的所有东西是注释
&/* 这是多行注释-用于注释一段代码
&if (gwb == 0){&& // 在多行注释内可使用单行注释
x = 3;&&&&&&&&&& /* 但不允许使用新的多行注释-这是无效的
// 别忘了注释的结尾符号-它们是成对出现的!
当测试代码的时候,注释掉一段可能有问题的代码是非常有效的方法。这能使这段代码成为注释而保留在程序中,而编译器能忽略它们。这个方法用于寻找问题代码或当编译器提示出错或错误很隐蔽时很有效。
3.5 #define
#define 是一个很有用的C语法,它允许程序员在程序编译之前给常量命名。在Arduino中,定义的常量不会占用芯片上的任何程序内存空间。在编译时编译器会用事先定义的值来取代这些常量。
然而这样做会产生一些副作用,例如,一个已被定义的常量名已经包含在了其他常量名或者变量名中。在这种情况下,文本将被#defined 定义的数字或文本所取代。
通常情况下,优先考虑使用
const 关键字替代 #define 来定义常量。
Arduino 拥有和 C 相同的语法规范。
#define 常量名
常量值 注意,#是必须的。
#define ledPin 3
//在编译时,编译器将使用数值 3 取代任何用到 ledPin 的地方。
在#define 声明后不能有分号。如果存在分号,编译器会抛出语义不明的错误,甚至关闭页面。
#define ledPin 3; //这是一种错误写法
类似的,在#define声明中包含等号也会产生语义不明的编译错误从而导致关闭页面。
#define ledPin = 3 //这是一种错误写法
不能包含等号只能用空格
3.6 #include
#include用于调用程序以外的库。这使得程序能够访问大量标准C库,也能访问用于arduino的库。 AVR C库(Arduino基于AVR标准语法)语法手册请点击这里。
注意#include和#define一样,不能在结尾加分号,如果你加了分号编译器将会报错。
此例包含了一个库,用于将数据存放在flash空间内而不是ram内。这为动态内存节约了空间,大型表格查表更容易实现。
#include &avr/pgmspace.h&
prog_uint16_t myConstants[] PROGMEM = {0, 2& , 9128,&
0,0,0,0,0,0,0,0,,,4500};&
四、算数运算符
4.1 =(赋值运算符)
= 赋值运算符(单等号) &注意:这个是赋值的=号并不是相比较的==号
赋值运算符(单等号)
将等号右边的数值赋值给等号左边的变量
在C语言中,单等号被称为赋值运算符,它与数学上的等号含义不同,赋值运算符告诉单片机,将等号的右边的数值或计算表达式的结果,存储在等号左边的变量中。
& int sensV& //声明一个名为sensVal的整型变量
& senVal = analogRead(0);& //将模拟引脚0的输入电压存储在SensVal变量中
要确保赋值运算符(=符号)左侧的变量能够储存右边的数值。如果没有大到足以容纳右边的值,存储在变量中的值将会发生错误。
比如你要把一个浮点型小数赋值给一个整数就不对
不要混淆赋值运算符[=](单等号)与比较运算符[==](双等号),认为这两个表达式是相等的。
4.2 +(加)
加,减,乘,除
这些运算符返回两个操作数的和,差,乘积,商。这些运算是根据操作数的数据类型来计算的,比如 9和4都是int类型,所以9 / 4 结果是 2.这也就代表如果运算结果比数据类型所能容纳的范围要大的话,就会出现溢出(例如. 1加上一个整数 int类型 32,767 结果变成-32,768)。如果操作数是不同类型的,结果是”更大”的那种数据类型。如果操作数中的其中一个是 float类型或者double类型, 就变成了浮点数运算。
y = y + 3; & //这里的Y得是整数型 int 类型才行,如果y是2输出结果为5
y=y+"你好啊"; & //这里的y得是字符串类型 &str 才行,如果y是“逗B”,输出结果就是“逗B你好啊”
//加可以用来做字符串相加,减的话必须是主内容包含被减掉的内容才可以。
x = x - 7;&
i = j * 6;
r = r / 5;&
result = value1 + value2;
result = value1 - value2;
result = value1 * value2;
result = value1 / value2;&
value1: 任何常量或者变量,value2: 任何常量或者变量
但是要注意,互相做运算的变量或是常得是同一类型,不是的话先转换成同一类型
编程小提示
整型常量的默认值是int类型,所以一些整型常量(定义中)的计算会导致溢出.(比如: 60 * 1000
会得到一个负数结果.那么if(60*1000 & 0) ,if得到的是一个false值。
在选择变量的数据类型时,一定要保证变量类型的范围要足够大,以至于能容纳下你的运算结果。
要知道你的变量在哪个点会”翻身”,两个方向上都得注意.如: (0 - 1) 或 (0 - - 32768)
一些数学上的分数处理,要用浮点数,但其缺点是:占用字节长度大,运算速度慢。
使用类型转换符,例如
(int)myFloat 将一个变量强制转换为int类型。&
4.3 -(减)
详见4.2 +(加)&
4.4 *(乘)
详见4.2 +(加)&
4.5 /(除)
详见4.2 +(加)
4.6 %(取模)
一个整数除以另一个数,其余数称为模。它有助于保持一个变量在一个特定的范围(例如数组的大小)。
结果=被除数%除数
被除数:一个被除的数字
除数:一个数字用于除以其他数
余数(模)
X = 7%5; // X为2,商为1余2
X = 9% 5;// X为4商为1余4
X = 5% 5;// X为0商为1余0
X = 4%5; // X为4除不动就为它本身4了
/*通过循环计算1到10的模*/
&int values[10];
int i = 0;&
void setup () {
void loop()
& values [i] = analogRead(0); & //所以读取的值就是10以内的除以10之后的余数
& i =(i + 1)%10; //取模运算
模运算符对浮点数不起作用。
五、比较运算符
5.1 ==(等于)比较是否等于
if(条件判断语句)和 ==、!=、&、&(比较运算符)
复习一下if语句
if 语句与比较运算符一起用于检测某个条件是否达成,如某输入值是否在特定值之上等。if 语句的语法是:
if (someVariable & 50)
& // 执行某些语句
本程序测试
someVariable 变量的值是否大于 50。当大于 50 时,执行一些语句。换句话说,只要 if 后面括号里的结果(称之为测试表达式)为真,则执行大括号中的语句(称之为执行语句块);若为假,则跳过大括号中的语句。 if 语句后的大括号可以省略。若省略大括号,则只有一条语句(以分号结尾)成为执行语句。&
if (x & 120) digitalWrite(LEDpin, HIGH);&
if (x & 120)
digitalWrite(LEDpin, HIGH);&
if (x & 120){ digitalWrite(LEDpin, HIGH); }&
if (x & 120){
& digitalWrite(LEDpin1, HIGH);
& digitalWrite(LEDpin2, HIGH);
} // 以上所有书写方式都正确
在小括号里求值的表达式,需要以下操作符:&
比较运算操作符:
&x == y(x 等于 y)
&x != y(x 不等于 y)
&x && y(x 小于 y)
&x && y(x 大于 y)
&x &= y(x 小于等于 y)
&x &= y(x 大于等于 y)
注意使用赋值运算符的情况(如 if (x = 10))。一个“=”表示的是赋值运算符,作用是将 x 的值设为 10(将值 10 放入 x 变量的内存中)。两个“=”表示的是比较运算符(如 if (x == 10)),用于测试 x 和 10 是否相等。后面这个语句只有 x 是 10 时才为真,而前面赋值的那个语句则永远为真。
这是因为 C 语言按以下规则进行运算
if (x=10):10 赋值给 x(只要非 0 的数赋值的语句,其赋值表达式的值永远为真),因此 x 现在值为 10。此时 if 的测试表达式值为 10,该值永远为真,因为非 0 值永远为真。所以,if (x = 10) 将永远为真,这就不是我们运行 if 所期待的结果。另外,x 被赋值为 10,这也不是我们所期待的结果。
if 的另外一种分支条件控制结构是 if...else 形式。&
5.2 !=(不等于)
详见5.1 ==(等于)&
5.3 &(小于)
详见5.1 ==(等于)&
5.4 &(大于)
详见5.1 ==(等于)&
5.5 &=(小于等于)
详见5.1 ==(等于)&
5.6 &=(大于等于)
详见5.1 ==(等于)
六、布尔运算符
6.1 &&(与)
布尔运算符
这些运算符可以用于if条件句中。不会打&没关系英文输入状态按SHIFT+7
&&(逻辑与)就是同时的意思,小明买了一支笔&&买了一本书
只有两个运算对象为“真”,才为“真”,如:
if (digitalRead(2) == HIGH&
&& digitalRead(3) == HIGH) { // 读取2号针脚和3号针脚的电平
如果当两个输入都为高电平,则为“真”。
||(逻辑或)
只要一个运算对象为“真”,就为“真”,如:
if (x & 0 || y & 0) {
& //其中x大于0或是y大于0都可执行程序
如果x或y是大于0,则为“真”。
!(逻辑非)
如果运算对象为“假”,则为“真”,例如
如果x为“假”,则为真(即如果x等于0)。
千万不要误以为,符号为&(单符号)的位运算符”与”就是布尔运算符的“与”符号为&&(双符号)。他们是完全不同的符号。
同样,不要混淆布尔运算符||(双竖)与位运算符“或”符号为| (单竖)。
位运算符?(波浪号)看起来与布尔运算符not有很大的差别!(正如程序员说:“惊叹号”或“bang”),但你还是要确定哪一个运算符是你想要的。
if (a &= 10 && a &= 20){}&& // 如果a的值在10至20之间,则为“真”&
6.2 ||(或)
详见6.1 &&(与)&
6.3 !(非)
详见6.1 &&(与)
&七、指针运算符
7.1 * 取消引用运算符
指针运算符
(取地址) 和 * (取地址所指的值)
指针对C语言初学者来说是一个比较复杂的内容,但是编写大部分arduino代码时可以不用涉及到指针。然而,操作某些数据结构时,使用指针能够简化代码,但是指针的操作知识很难在工具书中找到,可以参考C语言相关工具书。
7.2 & 引用运算符
详见7.1 *取消引用运算符&
八、位运算符
8.1 & (按位与)
按位与(&)
按位操作符对变量进行位级别的计算。它们能解决很多常见的编程问题。下面的材料大多来自这个非常棒的按位运算指导。
说明和语法
下面是所有的运算符的说明和语法。进一步的详细资料,可参考教程。
位操作符与在C + +中是一个&符,用在两个整型变量之间。按位与运算符对两侧的变量的每一位都进行运算,规则是:如果两个运算元都是1,则结果为1,否则输出0.另一种表达方式:&
0 0 1 1 运算元1
0 1 0 1 运算元2
----------
0 0 0 1(运算元1&运算元2)-返回结果
在Arduino中,int类型为16位,所以在两个int表达式之间使用&会进行16个并行按位与计算。代码片段就像这样:
&&& int a =& 92;&&&
//二进制: 1100
&&& int b = 101;&&& // 二进制: 0101
&&& int c = a && // 结果:&&& 0100, 或10进制的68
a和b的16位每位都进行按位与计算,计算结果存在c中,二进制结果是,十进制结果是68.
按位与最常见的作用是从整型变量中选取特定的位,也就是屏蔽。见下方的例子。
按位或(|)
按位或操作符在C++中是|。和&操作符类似,|操作符对两个变量的为一位都进行运算,只是运算规则不同。按位或规则:只要两个位有一个为1则结果为1,否则为0。换句话说:
0 0 1 1 运算元1
0 1 0 1 运算元2
----------
0 1 1 1(运算元1 | 运算元2) - 返回的结果
这里是一个按位或运算在C
+ +代码片段:
int a =& 92;&&& // 二进制: 1100
int b = 101;&&& //二进制:
int c = a |& // 结果:&&& 1101, 或十进制的125
按位与和按位或运算常用于端口的读取-修改-写入。在微控制器中,一个端口是一个8位数字,它用于表示引脚状态。对端口进行写入能同时操作所有引脚。
PORTD是一个内置的常数,是指0,1,2,3,4,5,6,7数字引脚的输出状态。如果某一位为1,着对应管脚为HIGH。(此引脚需要先用pinMode()命令设置为输出)因此如果我们这样写,PORTD=B;则引脚2、3、7状态为HIGH。这里有个小陷阱,我们可能同时更改了引脚0、1的状态,引脚0、1是Arduino串行通信端口,因此我们可能会干扰通信。
我们的算法的程序是:
读取PORT并用按位与清除我们想要控制的引脚
用按位或对PORTD和新的值进行运算
&&&& // 计数器
void setup()
DDRD = DDRD | B; //设置引脚2~7的方向,0、1脚不变(xx|00==xx)
//效果和pinMode(pin,OUTPUT)设置2~7脚为输出一样
serial.begin(9600);
void loop ()&& {
for (i=0; i&64; i++){&
PORTD = PORTD & B;&
// 清除2~7位,0、1保持不变(xx & 11 == xx)
j = (i && 2);&&&&&&&&&&&&&&
//将变量左移为·2~7脚,避免0、1脚
PORTD = PORTD |&&&&&&&&& //将新状态和原端口状态结合以控制LED脚
Serial.println(PORTD, BIN); // 输出掩盖以便调试
delay(100);
按位异或(^)
C++中有一个不常见的操作符叫按位异或,也叫做XOR(通常读作”eks-or“)。按位异或操作符用‘^'表示。此操作符和按位或(|)很相似,区别是如果两个位都为1则结果为0:
0 0 1 1 运算元1
0 1 0 1 运算元2
----------
0 1 1 0(运算元1 ^运算元2) - 返回的结果
按位异或的另一种解释是如果两个位值相同则结果为0,否则为1。
下面是一个简单的代码示例:
int x = 12;&&&& // 二进制: 1100
int y = 10;&&&& // 二进制: 1010
int z = x ^& // 二进制: 0110, 或十进制 6
// Blink_Pin_5
//演示“异或”
void setup(){
DDRD = DDRD | B; / /设置数字脚5设置为输出
serial.begin(9600);
void loop ()&& {
PORTD = PORTD ^ B;& //
反转第5位(数字脚5),其他保持不变
delay(100);
8.2 | (按位或)
详见8.1& &(按位与)&
8.3 ^ (按位异或)
详见8.1& &(按位与)&
8.4 ~ (按位非)
按位取反 (~)
按位取反在C+ +语言中是波浪号~。与&(按位与)和|(按位或)不同,按位取反使用在一个操作数的右侧。按位取反将操作数改变为它的“反面”:0变为1,1变成0。例如:
0& 1&&& operand1
----------
1& 0&& ~ operand1
int a = 103;&&& // 二进制:& 0111
int b = ~a;&&&& // 二进制:& 1000 = -104
你可能会惊讶地看到结果为像-104这样的数字。这是因为整数型变量的最高位,即所谓的符号位。如果最高位是1,这个数字将变为负数。这个正数和负数的编码被称为补。想了解更多信息,请参考Wikipedia文章two's complement.
顺便说一句,有趣的是,要注意对于任何整数型操作数X,?X和-X-1是相同的。
有时,对带有符号的整数型操作数进行位操作可以造成一些不必要的意外。&
8.5 &&(左移位运算符)
left (&&), bitshift right (&&)
出自Playground的 The Bitmath
Tutorial 在C++语言中有两个移位运算符:左移位运算符(<>)。这些操作符可使左运算元中的某些位移动右运算元中指定的位数。
variable <> number_of_bits
variable - (byte, int, long) number_of_bits integer <= 32
int a = 5;&&&&&&& // 二进制数:
int b = a && 3;&& // 二进制数:
1000, 或十进制数:40
int c = b && 3;&& // 二进制数:
0101, 或者说回到开始时的5
//当你将x左移y位时(x<<y),x中最左边的y位会逐个逐个的丢失:
int a = 5;&&&&&&& // 二进制:
int b = a && 14;& // 二进制:
0000 - 101中最左边的1被丢弃
如果你确定位移不会引起数据溢出,你可以简单的把左移运算当做对左运算元进行2的右运算元次方的操作。例如,要产生2的次方,可使用下面的方式:
1 && 0 == 1
1 && 1 == 2
1 && 2 == 4
1 && 3 == 8
1 && 8 == 256
1 && 9 == 512
10 && 1 == 1024
当你将x右移y位(x>>y),如果x最高位是1,位移结果将取决于x的数据类型。如果x是int类型,最高位为符号位,确定是否x是负数或不是,正如我们上面的讨论。如果x类型为int,则最高位是符号位,正如我们以前讨论过,符号位表示x是正还是负。在这种情况下,由于深奥的历史原因,符号位被复制到较低位:
X = -16; //二进制:0000
Y = X && 3 //二进制:1110
这种结果,被称为符号扩展,往往不是你想要的行为。你可能希望左边被移入的数是0。右移操作对无符号整型来说会有不同结果,你可以通过数据强制转换改变从左边移入的数据:
X = -16; //二进制:0000
int y = (unsigned int)x && 3;&
// 二进制: 1110
如果你能小心的避免符号扩展问题,你可以将右移操作当做对数据除2运算。例如:
INT = 1000;
Y = X && 3; 8 1000&
//1000整除8,使y=125&
8.6 && (右移位运算符)
&&(左移位运算符)&
九、复合运算符
9.1 ++ (递增)
++ (递增) / -- (递减)
递增或递减一个变量
x++;& //x自增1返回x的旧值
++x;& // x自增1返回x的新值
x--;& // x自减1返回x的旧值
--x;& //x自减1返回x的新值
x: int或long(可能是unsigned)
变量进行自增/自减操作后的原值或新值。
y = ++x;&&&&& // 现在x=3,y=3
y = x--;&&&&& // 现在x=2,y还是3&
9.2 -- (递减)
详见 9.1 ++ (递增)
9.3 += (复合加)
-= , *= , /=
执行常量或变量与另一个变量的数学运算。+= 等运算符是以下扩展语法的速记。
X += Y;& //相当于表达式X = X +
X -= Y;& //相当于表达式X = X -
X *= Y;& //相当于表达式X = X *
X /= Y;& //相当于表达式X = X /
X:任何变量类型
Y:任何变量类型或常数
x += 4;&&&&& // x 现在等于6
x -= 3;&&&&& // x 现在等于3
x *= 10;&&&& // x 现在等于30
x /= 2;&&&&& // x 现在等于15
9.4 -= (复合减)
详见 9.3 += (复合加)
9.5 *= (复合乘)
详见 9.3 += (复合加)
9.6 /= (复合除)
详见 9.3 += (复合加)
9.6 &= (复合运算按位与)
复合运算按位与运算符(&=)经常被用来将一个变量和常量进行运算使变量某些位变为0。这通常被称为“清算”或“复位”位编程指南。
x &=&& // 等价于 x = x
x:char,int或long类型变量
Y:char,int或long类型常量
首先,回顾一下按位与(&)运算符
0 0 1 1 运算元1
0 1 0 1 运算元2
----------
0 0 0 1(运算元1&运算元2) - 返回的结果
任何位与0进行按位与操作后被清零,如果myBite是变量
myByte&B = 0;
因此,任何位与1进行“按位与运算”后保持不变
myByte B = myB
注意:因为我们用位操作符来操作位,所以使用二进制的变量会很方便。如果这些数值是其他值将会得到同样结果,只是不容易理解。同样,B是为了标示清楚,0在任何进制中都是0(恩。。有些哲学的味道)
因此 - 清除(置零)变量的任意位0和1,而保持其余的位不变,可与常量B进行复合运算按位与(&=)
1 0 1 0 1 0 1 0变量
1 1 1 1 1 1 0 0 mask
----------------------
1 0 1 0 1 0 0 0
变量不变 位清零
将变量替换为x可得到同样结果
X X X X X X X X变量
1 1 1 1 1 1 0 0 mask
----------------------
X X X X X X 0 0
变量不变 位清零
myByte = ;
myByte&= B1111100 == B;
9.8 |= (复合运算按位或)
复合按位或操作符(| =)经常用于变量和常量“设置”(设置为1),尤其是变量中的某一位。
x |=&& //等价于 x = x |
x: char,int或long类型
y:整数,int或long类型
首先,回顾一下OR(|)运算符
1& 1&&& 运算元1
0& 1&&& 运算元2
&& ----------
&& 0 1 1 1(运算元1 | 运算元2) - 返回的结果
如果变量myByte中某一位与0经过按位或运算后不变。
myByte | B = myB
与1经过或运算的位将变为1.
myByte | B111111;
因此 - 设置变量的某些位为0和1,而变量的其他位不变,可与常量B进行按位与运算(| =)
1 0 1 0 1 0 1 0变量
0 0 0 0 0 0 1 1
----------------------
1 0 1 0 1 0 1 1
变量保持不变 位设置
接下来的操作相同,只是将变量用x代替
X X X X X X X X变量
0 0 0 0 0 0 1 1 mask
----------------------
X X X X X X 1 1
变量保持不变 位设置
myByte = B;
myByte | = B == B;&
10.1 HIGH|LOW(引脚电压定义)
引脚电压定义,HIGH和LOW
当读取(read)或写入(write)数字引脚时只有两个可能的值: HIGH 和 LOW 。
HIGH(参考引脚)的含义取决于引脚(pin)的设置,引脚定义为INPUT或OUTPUT时含义有所不同。当一个引脚通过pinMode被设置为INPUT,并通过digitalRead读取(read)时。如果当前引脚的电压大于等于3V,微控制器将会返回为HIGH。
引脚也可以通过pinMode被设置为INPUT,并通过digitalWrite设置为HIGH。输入引脚的值将被一个内在的20K上拉电阻
控制 在HIGH上,除非一个外部电路将其拉低到LOW。
当一个引脚通过pinMode被设置为OUTPUT,并digitalWrite设置为HIGH时,引脚的电压应在5V。在这种状态下,它可以
输出电流 。例如,点亮一个通过一串电阻接地或设置为LOW的OUTPUT属性引脚的LED。
LOW的含义同样取决于引脚设置,引脚定义为INPUT或OUTPUT时含义有所不同。当一个引脚通过pinMode配置为INPUT,通过digitalRead设置为读取(read)时,如果当前引脚的电压小于等于2V,微控制器将返回为LOW。
当一个引脚通过pinMode配置为OUTPUT,并通过digitalWrite设置为LOW时,引脚为0V。在这种状态下,它可以
倒灌 电流。例如,点亮一个通过串联电阻连接到+5V,或到另一个引脚配置为OUTPUT、HIGH的的LED。&
10.2 INPUT|OUTPUT(数字引脚(Digital
pins)定义)
数字引脚(Digital
pins)定义,INPUT和OUTPUT
数字引脚当作 INPUT 或 OUTPUT都可以 。用pinMode()方法使一个数字引脚从INPUT到OUTPUT变化。
引脚(Pins)配置为输入(Inputs)
Arduino(Atmega)引脚通过pinMode()配置为
输入(INPUT)
即是将其配置在一个高阻抗的状态。配置为INPUT的引脚可以理解为引脚取样时对电路有极小的需求,即等效于在引脚前串联一个100兆欧姆(Megohms)的电阻。这使得它们非常利于读取传感器,而不是为LED供电。
引脚(Pins)配置为输出(Outputs)
引脚通过pinMode()配置为 输出(OUTPUT) 即是将其配置在一个低阻抗的状态。
这意味着它们可以为电路提供充足的电流。Atmega引脚可以向其他设备/电路提供(提供正电流positive current)或倒灌(提供负电流negative current)达40毫安(mA)的电流。这使得它们利于给LED供电,而不是读取传感器。输出(OUTPUT)引脚被短路的接地或5V电路上会受到损坏甚至烧毁。Atmega引脚在为继电器或电机供电时,由于电流不足,将需要一些外接电路来实现供电。
10.3 true | false(逻辑层定义)
逻辑层定义,true与false(布尔Boolean常量)
在Arduino内有两个常量用来表示真和假:true和 false。
在这两个常量中false更容易被定义。false被定义为0(零)。
true通常被定义为1,这是正确的,但true具有更广泛的定义。在布尔含义(Boolean sense)里任何
非零 整数 为true。所以在布尔含义内-1,2和-200都定义为ture。 需要注意的是true和false常量,不同于HIGH,LOW,INPUT和OUTPUT,需要全部小写。&
10.4 integer constants(整数常量)
整数常量是直接在程序中使用的数字,如123。默认情况下,这些数字被视为int,但你可以通过U和L修饰符进行更多的限制(见下文)。
通常情况下,整数常量默认为十进制,但可以加上特殊前缀表示为其他进制。
10(十进制)
2(二进制)
只适用于8位的值(0到255)字符0-1有效
8(八进制)
字符0-7有效
16(十六进制)
前缀”0x”
字符0-9,A-F,A-F有效
小数是十进制数。这是数学常识。如果一个数没有特定的前缀,则默认为十进制。
二进制以2为基底,只有数字0和1是有效的。
101& //和十进制5等价 (1*2^2 + 0*2^1 +
二进制格式只能是8位的,即只能表示0-255之间的数。如果输入二进制数更方便的话,你可以用以下的方式:
myInt = (B * 256) + B;&&& // B 作为高位。
八进制是以8为基底,只有0-7是有效的字符。前缀“0”(数字0)表示该值为八进制。
0101&&& // 等同于十进制数65&& ((1 * 8^2) + (0 * 8^1) + 1)
警告:八进制数0前缀很可能无意产生很难发现的错误,因为你可能不小心在常量前加了个“0”,结果就悲剧了。
十六进制以16为基底,有效的字符为0-9和A-F。十六进制数用前缀“0x”(数字0,字母爱克斯)表示。请注意,A-F不区分大小写,就是说你也可以用a-f。
0x101&& // 等同于十进制257&& ((1 * 16^2) + (0 * 16^1) + 1)
默认情况下,整型常量被视作int型。要将整型常量转换为其他类型时,请遵循以下规则:
'u' or 'U' 指定一个常量为无符号型。(只能表示正数和0)
'l' or 'L' 指定一个常量为长整型。(表示数的范围更广)
例如: 100000L
'ul' or 'UL' 这个你懂的,就是上面两种类型,称作无符号长整型。
例如:32767ul&
10.5 floating point constants(浮点常量)
和整型常量类似,浮点常量可以使得代码更具可读性。浮点常量在编译时被转换为其表达式所取的值。
n = .005; 浮点数可以用科学记数法表示。'E'和'e'都可以作为有效的指数标志。
2.34 * 10^5
67.0 * 10^-12
十一、数据类型
void只用在函数声明中。它表示该函数将不会被返回任何数据到它被调用的函数中。
//功能在“setup”和“loop”被执行
//但没有数据被返回到高一级的程序中
void setup()
void loop()
11.2 boolean (布尔)
一个布尔变量拥有两个值,true或false。(每个布尔变量占用一个字节的内存。)
int LEDpin = 5;&&&&&& // LED与引脚5相连
int switchPin = 13;&& // 开关的一个引脚连接引脚13,另一个引脚接地。
boolean running =
void setup()
& pinMode(LEDpin, OUTPUT);
& pinMode(switchPin, INPUT);
& digitalWrite(switchPin,
HIGH);&&&&& // 打开上拉电阻
void loop()
& if (digitalRead(switchPin)
& {& // 按下开关 - 使引脚拉向高电势
&&& delay(100);&&&&&&&&&&&&&&&&&&&&&&& // 通过延迟,以滤去开关抖动产生的杂波
&&& running = !&&&&&&&&&&&&&&& // 触发running变量
&&& digitalWrite(LEDpin,
running)&&&&& //点亮LED
11.3 char(字符或字符串)
一个数据类型,占用1个字节的内存存储一个字符值。字符都写在单引号,如'A';(多个字符(字符串)使用双引号,如“ABC”)。
字符以编号的形式存储。你可以在ASCII表中看到对应的编码。这意味着字符的ASCII值可以用来作数学计算。(例如'A'+ 1,因为大写A的ASCII值是65,所以结果为66)。如何将字符转换成数字参考serial.println命令。
char数据类型是有符号的类型,这意味着它的编码为-128到127。对于一个无符号一个字节(8位)的数据类型,使用byte数据类型。
& char myChar = 'A';
& char myChar = 65;&&&&& // both are equivalent
11.4 unsigned char(无符号数据类型)
一个无符号数据类型占用1个字节的内存。与byte的数据类型相同。
无符号的char数据类型能编码0到255的数字。
为了保持Arduino的编程风格的一致性,byte数据类型是首选。
unsigned char myChar = 240;
11.5 byte(无符号数)
一个字节存储8位无符号数,从0到255。
byte b = B10010;& //
"B" 是二进制格式(B10010等于十进制18)
11.6 int(整型)
整数是基本数据类型,占用2字节。整数的范围为-32,768到32,767( -2^15 ~(2^15)-1)。
整数类型使用2的补码方式存储负数。最高位通常为符号位,表示数的正负。其余位被“取反加1”(此处请参考补码相关资料,不再赘述)。
Arduino为您处理负数计算问题,所以数学计算对您是透明的(术语:实际存在,但不可操作。相当于“黑盒”)。但是,当处理右移位运算符(>>)时,可能有未预期的编译过程。
int ledPin = 13;
var - 变量名
val - 赋给变量的值
当变量数值过大而超过整数类型所能表示的范围时(-32,768到32,767),变量值会“回滚”(详情见示例)。
x = -32,768;
x = x - 1;&&&&&& // x 现在是 32,767。
x = 32,767;
x = x + 1;&&&&&& // x 现在是 -32,768。
11.7 unsigned int(无符号整型)
无符号整型变量扩充了变量容量以存储更大的数据,它能存储32位(4字节)数据。与标准长整型不同无符号长整型无法存储负数,其范围从0到4,294,967,295(2 ^ 32 - 1)。
void setup()
&&&& Serial.begin(9600);
void loop()
& Serial.print("Time:
& time = millis();
//程序开始后一直打印时间
& Serial.println(time);
//等待一秒钟,以免发送大量的数据
&&&& delay(1000);
unsigned long var =
var - 你所定义的变量名
val - 给变量所赋的值
一个存储一个16字节无符号数的字符,取值范围从0到65535,与unsigned int相同。
word w = 10000;
11.9 long(长整数型)
长整数型变量是扩展的数字存储变量,它可以存储32位(4字节)大小的变量,从-2,147,483,648到2,147,483,647。
long speedOfLight = 186000L; //参见整数常量‘L’的说明
long var =
var - 长整型变量名
var - 赋给变量的值
11.10 unsigned long(无符号长整数型)
无符号长整型变量扩充了变量容量以存储更大的数据,它能存储32位(4字节)数据。与标准长整型不同无符号长整型无法存储负数,其范围从0到4,294,967,295(2 ^ 32 - 1)。
void setup()
&&&& Serial.begin(9600);
void loop()
& Serial.print("Time:
& time = millis();
//程序开始后一直打印时间
& Serial.println(time);
//等待一秒钟,以免发送大量的数据
&&&& delay(1000);
unsigned long var =
var - 你所定义的变量名
val - 给变量所赋的值
11.11 float(浮点型数)
float,浮点型数据,就是有一个小数点的数字。浮点数经常被用来近似的模拟连续值,因为他们比整数更大的精确度。浮点数的取值范围在3.4028235 E+38 ~ -3.4028235E +38。它被存储为32位(4字节)的信息。
float只有6-7位有效数字。这指的是总位数,而不是小数点右边的数字。与其他平台不同的是,在那里你可以使用double型得到更精确的结果(如15位),在Arduino上,double型与float型的大小相同。
浮点数字在有些情况下是不准确的,在数据大小比较时,可能会产生奇怪的结果。例如 6.0 / 3.0 可能不等于 2.0。你应该使两个数字之间的差额的绝对值小于一些小的数字,这样就可以近似的得到这两个数字相等这样的结果。
浮点运算速度远远慢于执行整数运算,例如,如果这个循环有一个关键的计时功能,并需要以最快的速度运行,就应该避免浮点运算。程序员经常使用较长的程式把浮点运算转换成整数运算来提高速度。
float sensorCalbrate = 1.117;
float var =
var——您的float型变量名称
val——分配给该变量的值
y = x / 2;&&&&&&&& // Y为0,因为整数不能容纳分数
z = (float)x / 2.0;&& // Z为0.5(你必须使用2.0做除数,而不是2)
11.12 double(双精度浮点数)
双精度浮点数。占用4个字节。
目前的arduino上的double实现和float相同,精度并未提高。
如果你从其他地方得到的代码中包含了double类变量,最好检查一遍代码以确认其中的变量的精确度能否在arduino上达到。
11.13 string(char array/字符串)
string(字符串)
文本字符串可以有两种表现形式。你可以使用字符串数据类型(这是0019版本的核心部分),或者你可以做一个字符串,由char类型的数组和空终止字符('\0')构成。(求助,待润色-Leo)本节描述了后一种方法。而字符串对象(String object)将让你拥有更多的功能,同时也消耗更多的内存资源,关于它的详细信息,请参阅页面(String object)[超链接]
以下所有字符串都是有效的声明。
char Str1[15];
char Str2[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o'};
char Str3[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o', '\0'};
char Str4[ ] = "arduino";
char Str5[8] = "arduino";
char Str6[15] = "arduino";
声明字符串的解释
在Str1中 声明一个没有初始化的字符数组
在Str2中 声明一个字符数组(包括一个附加字符),编译器会自动添加所需的空字符
在Str3中 明确加入空字符
在Str4中 用引号分隔初始化的字符串常数,编译器将调整数组的大小,以适应字符串常量和终止空字符
在Str5中 初始化一个包括明确的尺寸和字符串常量的数组
在Str6中 初始化数组,预留额外的空间用于一个较大的字符串
空终止字符
一般来说,字符串的结尾有一个空终止字符(ASCII代码0)。以此让功能函数(例如Serial.pring())知道一个字符串的结束。否则,他们将从内存继续读取后续字节,而这些并不属于所需字符串的一部分。
这意味着,你的字符串比你想要的文字包含更多的个字符空间。这就是为什么Str2和Str5需要八个字符,即使“Arduino”只有七个字符 - 最后一个位置会自动填充空字符。str4将自动调整为八个字符,包括一个额外的空。在Str3的,我们自己已经明确地包含了空字符(写入'\ 0')。
需要注意的是,字符串可能没有一个最后的空字符(例如在Str2中您已定义字符长度为7,而不是8)。这会破坏大部分使用字符串的功能,所以不要故意而为之。如果你注意到一些奇怪的现象(在字符串中操作字符),基本就是这个原因导致的了。
单引号?还是双引号?
定义字符串时使用双引号(例如“ABC”),而定义一个单独的字符时使用单引号(例如'A')
包装长字符串
你可以像这样打包长字符串:
char myString[] = “This is the first line”
” this is the second line” ” etcetera”;
字符串数组
当你的应用包含大量的文字,如带有液晶显示屏的一个项目,建立一个字符串数组是非常便利的。因为字符串本身就是数组,它实际上是一个两维数组的典型。
在下面的代码,”char*”在字符数据类型char后跟了一个星号'*'表示这是一个“指针”数组。所有的数组名实际上是指针,所以这需要一个数组的数组。指针对于C语言初学者而言是非常深奥的部分之一,但我们没有必要了解详细指针,就可以有效地应用它。
char* myStrings[]={
& "This is string
1", "This is string 2", "This is string 3",
& "This is string
4", "This is string 5","This is string 6"};
void setup(){
& Serial.begin(9600);
void loop(){
& for (int i = 0; i & 6;
Serial.println(myStrings[i]);
&&& delay(500);
11.14 String& object(String类)
String类,是0019版的核心的一部分,允许你实现比运用字符数组更复杂的文字操作。你可以连接字符串,增加字符串,寻找和替换子字符串以及其他操作。它比使用一个简单的字符数组需要更多的内存,但它更方便。
仅供参考,字符串数组都用小写的string表示而String类的实例通常用大写的String表示。注意,在“双引号”内指定的字符常量通常被作为字符数组,并非String类实例。
compareTo()
endsWith()
equalsIgnoreCase()
GetBytes()
lastIndexOf
setCharAt()
startsWith()
substring()
toCharArray()
toLowerCase()
toUpperCase()
[](元素访问)
==(比较)
StringConstructors
StringAdditionOperator
StringIndexOf
StringAppendOperator
StringLengthTrim
StringCaseChanges
StringReplace
StringCharacters
StringStartsWithEndsWith
StringComparisonOperators
StringSubstring
11.15 array (数组)
数组是一种可访问的变量的集合。Arduino的数组是基于C语言的,因此这会变得很复杂,但使用简单的数组是比较简单的。
创建(声明)一个数组
下面的方法都可以用来创建(声明)数组。
& myInts [6];
& myPins [] = {2,4,8,3,6};
& mySensVals [6] = {2,4,-8,3,2};
& char message[6] =
你声明一个未初始化数组,例如myPins。
在myPins中,我们声明了一个没有明确大小的数组。编译器将会计算元素的大小,并创建一个适当大小的数组。
当然,你也可以初始化数组的大小,例如在mySensVals中。请注意,当声明一个char类型的数组时,你初始化的大小必须大于元素的个数,以容纳所需的空字符。
数组是从零开始索引的,也就说,上面所提到的数组初始化,数组第一个元素是为索引0,因此:
mySensVals [0] == 2,mySensVals [1] == 4,
依此类推 。
这也意味着,在包含十个元素的数组中,索引九是最后一个元素。因此,
& int myArray[10] =
{9,3,2,4,3,2,7,8,9,11};
& // myArray[9]的数值为11
& // myArray[10],该索引是无效的,它将会是任意的随机信息(内存地址)
出于这个原因,你在访问数组应该小心。若访问的数据超出数组的末尾(即索引数大于你声明的数组的大小- 1),则将从其他内存中读取数据。从这些地方读取的数据,除了产生无效的数据外,没有任何作用。向随机存储器中写入数据绝对是一个坏主意,通常会导致不愉快的结果,如导致系统崩溃或程序故障。要排查这样的错误是也是一件难事。
不同于Basic或JAVA,C语言编译器不会检查你访问的数组是否大于你声明的数组。
指定一个数组的值
mySensVals [0] = 10;
从数组中访问一个值:
X = mySensVals [4];
数组和循环
数组往往在for循环中进行操作,循环计数器可用于访问每个数组元素。例如,将数组中的元素通过串口打印,你可以这样做:
& for (i = 0; i & 5; i = i
& Serial.println(myPins[i]);
如果你需要一个演示数组的完整程序,请参考Knight Rider exampel。&
十二、数据类型转换
12.1 char()
将一个变量的类型变为char。
x:任何类型的值
12.2 byte()
将一个值转换为字节型数值。
X:任何类型的值
12.3 int()
将一个值转换为int类型。
x:一个任何类型的值
int类型的值
12.4 word()
把一个值转换为word数据类型的值,或由两个字节创建一个字符。
word(h, l)
X:任何类型的值
H:高阶(最左边)字节
L:低序(最右边)字节
12.5 long()
将一个值转换为长整型数据类型。
x:任意类型的数值
12.6 float()
将一个值转换为float型数值。
X:任何类型的值
见float中关于Arduino浮点数的精度和限制的详细信息。&
十三、变量作用域
13.1 variable scope(变量的作用域)
变量的作用域
在Arduino使用的C编程语言的变量,有一个名为 作用域(scope) 的属性 。这一点与类似BASIC的语言形成了对比,在BASIC语言中所有变量都是 全局(global) 变量。
在一个程序内的全局变量是可以被所有函数所调用的。局部变量只在声明它们的函数内可见。在Arduino的环境中,任何在函数(例如,setup(),loop()等)外声明的变量,都是全局变量。
当程序变得更大更复杂时,局部变量是一个有效确定每个函数只能访问其自己变量的途径。这可以防止,当一个函数无意中修改另一个函数使用的变量的程序错误。
有时在一个for循环内声明并初始化一个变量也是很方便的选择。这将创建一个只能从for循环的括号内访问的变量。
int gPWM& // 任何函数都可以调用此变量
void setup()
void loop()
&&&& // "i" 只在
"loop" 函数内可用
&& // "f" 只在
"loop" 函数内可用
& for (int j = 0; j &100;
&&& //变量j只能在循环括号内访问
13.2 static(静态变量)
static关键字用于创建只对某一函数可见的变量。然而,和局部变量不同的是,局部变量在每次调用函数时都会被创建和销毁,静态变量在函数调用后仍然保持着原来的数据。
静态变量只会在函数第一次调用的时候被创建和初始化。
/* RandomWalk
* Paul Badger 2007
* RandomWalk函数在两个终点间随机的上下移动
* 在一个循环中最大的移动由参数“stepsize”决定
*一个静态变量向上和向下移动一个随机量
*这种技术也被叫做“粉红噪声”或“醉步”
#define randomWalkLowRange -20
#define randomWalkHighRange 20
void setup()
&&&& Serial.begin(9600);
void loop()
{&&&&&&& //& 测试randomWalk 函数
& stepsize = 5;
& thisTime = randomWalk(stepsize);
serial.println(thisTime);
&& delay(10);
int randomWalk(int moveSize){
& static int&&&&&
// 在randomwalk中存储变量
&&&&&&&&&&&&&&&&&&&&&&&& // 声明为静态因此它在函数调用之间能保持数据,但其他函数无法改变它的值
&& place = place +
(random(-moveSize, moveSize + 1));
&& if (place & randomWalkLowRange){&&&&&&&&&&&&&&&&&&& //检查上下限
&&& place = place +
(randomWalkLowRange - place);&&&& // 将数字变为正方向
& else if(place &
randomWalkHighRange){
&&& place = place - (place -
randomWalkHighRange);&&&& // 将数字变为负方向
13.3 volatile
volatile这个关键字是变量修饰符,常用在变量类型的前面,以告诉编译器和接下来的程序怎么对待这个变量。
声明一个volatile变量是编译器的一个指令。编译器是一个将你的C/C++代码转换成机器码的软件,机器码是arduino上的Atmega芯片能识别的真正指令。
具体来说,它指示编译器编译器从RAM而非存储寄存器中读取变量,存储寄存器是程序存储和操作变量的一个临时地方。在某些情况下,存储在寄存器中的变量值可能是不准确的。
如果一个变量所在的代码段可能会意外地导致变量值改变那此变量应声明为volatile,比如并行多线程等。在arduino中,唯一可能发生这种现象的地方就是和中断有关的代码段,成为中断服务程序。
//当中断引脚改变状态时,开闭LED
int pin = 13;
volatile int state = LOW;
void setup()
& pinMode(pin, OUTPUT);
& attachInterrupt(0, blink,
void loop()
& digitalWrite(pin, state);
void blink()
& state = !
13.4 const
const关键字代表常量。它是一个变量限定符,用于修改变量的性质,使其变为只读状态。这意味着该变量,就像任何相同类型的其他变量一样使用,但不能改变其值。如果尝试为一个const变量赋值,编译时将会报错。
const关键字定义的常量,遵守 variable scoping 管辖的其他变量的规则。这一点加上使用 #define的缺陷
,使 const 关键字成为定义常量的一个的首选方法。
const float pi = 3.14;
x = pi * 2;&&& // 在数学表达式中使用常量不会报错
pi = 7;&&&&&&& // 错误的用法 - 你不能修改常量值,或给常量赋值。
您可以使用 const 或 #define 创建数字或字符串常量。但
arrays, 你只能使用 const。
一般 const 相对
的#define是首选
的定义常量语法。&
十四、辅助工具
14.1 sizeof()
sizeof操作符返回一个变量类型的字节数,或者该数在数组中占有的字节数。
sizeof(variable)
variable: 任何变量类型或数组(如int,float,byte)
sizeof操作符用来处理数组非常有效,它能很方便的改变数组的大小而不用破坏程序的其他部分。
这个程序一次打印出一个字符串文本的字符。尝试改变一下字符串。
char myStr[] = "this is a test";
void setup(){
& Serial.begin(9600);
{0}void{/0}{1} {/1}{2}loop{/2}{1}() {{/1}
& for (i = 0; i &
sizeof(myStr) - 1; i++){
&&& Serial.print(i, DEC);
&&& Serial.print(" =
&&& Serial.println(myStr[i],
请注意sizeof返回字节数总数。因此,较大的变量类型,如整数,for循环看起来应该像这样。
for (i = 0; i & (sizeof(myInts)/sizeof(int)) - 1; i++) {
& //用myInts[i]来做些事
十五、数字
15.1 pinMode()
将指定的引脚配置成输出或输入。详情请见digital pins。
pinMode(pin, mode)
pin:要设置模式的引脚
mode:INPUT或OUTPUT
ledPin = 13 // LED连接到数字脚13
void setup()
pinMode(ledPin,OUTPUT); //设置数字脚为输出
void loop()
digitalWrite(ledPin,HIGH); //点亮LED
& delay(1000);&&&&&&&&&&&&&&&&& // 等待一秒
& digitalWrite(ledPin,
LOW);&&& // 灭掉LED
延迟(1000); //等待第二个
模拟输入脚也能当做数字脚使用,参见A0,A1等
15.2 digitalWrite()
给一个数字引脚写入HIGH或者LOW。
如果一个引脚已经使用pinMode()配置为OUTPUT模式,其电压将被设置为相应的值,HIGH为5V(3.3V控制板上为3.3V),LOW为0V。
如果引脚配置为INPUT模式,使用digitalWrite()写入HIGH值,将使内部20K上拉电阻(详见数字引脚教程)。写入LOW将会禁用上拉。上拉电阻可以点亮一个LED让其微微亮,如果LED工作,但是亮度很低,可能是因为这个原因引起的。补救的办法是
使用pinMode()函数设置为输出引脚。
注意:数字13号引脚难以作为数字输入使用,因为大部分的控制板上使用了一颗LED与一个电阻连接到他。如果启动了内部的20K上拉电阻,他的电压将在1.7V左右,而不是正常的5V,因为板载LED串联的电阻把他使他降了下来,这意味着他返回的值总是LOW。如果必须使用数字13号引脚的输入模式,需要使用外部上拉下拉电阻。
digitalWrite(pin, value)
pin: 引脚编号(如1,5,10,A0,A3)
value: HIGH or LOW
int ledPin = 13;&&&&&&&&&&&&&&&&
// LED连接到数字13号端口
void setup()
& pinMode(ledPin,
OUTPUT);&&&&& // 设置数字端口为输入模式
void loop()
& digitalWrite(ledPin,
HIGH);&& // 使LED亮
& delay(1000);&&&&&&&&&&&&&&&&& // 延迟一秒
& digitalWrite(ledPin,
LOW);&&& // 使LED灭
& delay(1000);&&&&&&&&&&&&&&&&& // 延迟一秒
13号端口设置为高电平,延迟一秒,然后设置为低电平。
模拟引脚也可以当做数字引脚使用,使用方法是输入端口A0,A1,A2等。
15.3 digitalRead()
读取指定引脚的值,HIGH或LOW。
digitalRead(PIN)
pin:你想读取的引脚号(int)
HIGH 或 LOW
ledPin = 13 // LED连接到13脚
int inPin = 7;&& // 按钮连接到数字引脚7
int val = 0;& //定义变量存以储读值
void setup()
& pinMode(ledPin,
OUTPUT);&&&&& // 将13脚设置为输出
& pinMode(inPin, INPUT);&&&&& // 将7脚设置为输入
void loop()
digitalRead(inPin);&& // 读取输入脚
& digitalWrite(ledPin,
val);&&& //将LED值设置为按钮的值
将13脚设置为输入脚7脚的值。
如果引脚悬空,digitalRead()会返回HIGH或LOW(随机变化)。
模拟输入脚能当做数字脚使用,参见A0,A1等。&
十六、模拟
16.1 analogReference()
配置用于模拟输入的基准电压(即输入范围的最大值)。选项有:
DEFAULT:默认5V(Arduino板为5V)或3.3伏特(Arduino板为3.3V)为基准电压。
INTERNAL:在ATmega168和ATmega328上以1.1V为基准电压,以及在ATmega8上以2.56V为基准电压(Arduino Mega无此选项)
INTERNAL1V1:以1.1V为基准电压(此选项仅针对Arduino Mega)
INTERNAL2V56:以2.56V为基准电压(此选项仅针对Arduino Mega)
EXTERNAL:以AREF引脚(0至5V)的电压作为基准电压。
type:使用哪种参考类型(DEFAULT, INTERNAL, INTERNAL1V1, INTERNAL2V56, 或者 EXTERNAL)。
改变基准电压后,之前从analogRead()读取的数据可能不准确。
不要在AREF引脚上使用使用任何小于0V或超过5V的外部电压。如果你使用AREF引脚上的电压作为基准电压,你在调用analogRead()前必须设置参考类型为EXTERNAL。否则,你将会削短有效的基准电压(内部产生)和AREF引脚,这可能会损坏您Arduino板上的单片机。
另外,您可以在外部基准电压和AREF引脚之间连接一个5K电阻,使你可以在外部和内部基准电压之间切换。请注意,总阻值将会发生改变,因为AREF引脚内部有一个32K电阻。这两个电阻都有分压作用。所以,例如,如果输入2.5V的电压,最终在在AREF引脚上的电压将为2.5 * 32 /(32 + 5)= 2.2V。
16.2 analogRead()
从指定的模拟引脚读取数据值。 Arduino板包含一个6通道(Mini和Nano有8个通道,Mega有16个通道),10位模拟数字转换器。这意味着它将0至5伏特}

我要回帖

更多关于 arduino pinmode 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信