文章目录

  • 前言
  • 一. 原型技术中的编程基础(Arduino C)
    • a. 变量和数据类型
      • 浮点型变量
      • 数组
      • String
      • C字符串
      • 比较和位运算
      • *复合运算和赋值
      • *字符串和数字的互相转化
    • b. 程序结构控制
      • 顺序
      • 选择
      • 循环
    • c. 函数
    • d. 库的使用
      • 内置库
      • 创建自己的库
  • 二. 物理原型开发基础(Arduino)
    • a. 交互式硬件原型的开发基础:电流、常⽤电⼦元件、示意图与电路图,万⽤表、焊接、 ⾯包板的使⽤。
    • b. 串⼝通信
      • 串口(UART)
      • 硬件串口
      • 串口通讯的函数
      • 软件串口
      • 多个串口
    • c. 简单数字和模拟输⼊
      • 开关
      • 按键消抖
      • 数字键盘
      • 模拟输入
        • *多路复用模拟输入
      • 测量电压
    • d. 获取传感器输⼊
      • 动作(数字量高低电平,类似开关)
      • 动作检测(集成被动红外探测器PIR,只需判断模拟量高电平)
      • 光(光敏电阻模拟量)
      • 距离(超声波,输出模式纯净高电平+输入模式计算脉冲时间)
      • 精确测距(*红外IR传感器比超声波精度高但量程小,输出非线性需要查表)
      • 振动(压电传感器/爆震传感器,应力越大电压越高。模拟量)
      • 声音
      • 温度
      • *RFID标签
      • *旋转动作(旋转编码器)
      • *鼠标
      • *GPS
      • *加速度(陀螺仪测量角加速度,加速度计测量移动加速度如重力加速度)
    • e. 可视输出、物理输出、声⾳输出
      • 显示
      • 电机
      • 音频
    • f. ⽆线通信和⽹络
      • * I2C和SPI
      • 无线XBEE
      • 蓝牙
      • *互联网
  • 三. 上述技术在设计原型制作和开发中的应⽤。
    • 1.接收到____信号时,_____动作
    • 2.智能水杯(传感器、显示器、LED、蜂鸣器、蓝牙等等综合运用)

前言

含星号*的不太常用。阅读前最好有一点基础知识,可以看个视频入门一下。本文参考书为Arduino Cookbook(Michael Margolis 等著)中译本《Arduino权威指南》。

Arduino是开放的电子开发平台,包含硬件和软件。
常用的一种硬件Arduino UNO如下图:


记:
左边5V输出、GND引脚, 0-5模拟引脚
右边USB接口 GND 13-0数字引脚(3 5 6 9 10 11支持PWM)

模拟引脚带ADC功能,10位精度,analogRead(pin),可将0~5V的电压转换为0 ~1023

PWM:脉冲宽度调制。analogWrite(pin,value); value值改变的是PWM的脉冲宽度,范围为0~255

一. 原型技术中的编程基础(Arduino C)

Arduino中的程序长这样:

const int ledPin=13;//LED连接到数字引脚13
void setup()
{pinMode(ledPin,OUTPUT);//以输出方式初始化一个引脚
}
void loop()
{digitalWrite(ledPin,HIGH);//点亮LEDdelay(1000);//等待1000ms即1sdigitalWrite(ledPin,LOW);//熄灭LEDdelay(1000);
}

a. 变量和数据类型

数据类型 字节 范围 使用
int 2 -32768~36767 整数值
unsigned int 2 0~65535 正整数值
long 4 -2^16~ 2 ^16-1 大范围整数
unsigned long 4 0~2^32-1 大范围正整数
float 4 3.4028235E+38~-3.4028235E+38 带小数部分的数字,7位有效十进制数字(32位存储巨大范围内的所有值,8位用于小数位置(指数),剩下24位留给符号和数值)
double 4 同float 在arduino里只是float的另一个名称
boolean 1 false(0)或true(1) 代表true或false值
char 1 -128~127 代表单个字符,也可以代表范围内的有符号值
Byte 1 0~255 类似char,但无符号值

其他:
string:char阵列(字符),通常用来包含文本
void:仅用在无返回值的函数声明

浮点型变量

/*
浮点例子
初始化浮点值至1.1,每次减少0.1至0
*/
boolean almostEqual(float a, float b);//定义了一个布尔型返回值的函数“视作几乎相等”,
float value=1.1;
void setup()
{Serial.begin(9600);
}
void loop()
{value=value-0.1;if(value==0)Serial.println("the value is exactly zero");else if(almostEqual(value,0))//比较此时value值和0的差距是否近似相等{Serial.print("The value");Serial.print(value,7);//打印到7位小数Serial.println("is almost equal to zero");}elseSerial.println(value);delay(100);
}/*定义了一个布尔型返回值的函数“视作几乎相等”,输入形式参数为a和b,如果a和b之前差很小,则返回true把DELTA的值设成能视作相等的最大差值*/boolean almostEqual(float a, float b){const float DELTA=.00001;//视作几乎相等的最大差值if (a==0) return fabs(b) <=DELTA;//fabs() 浮点绝对值if (b==0) return fabs(a) <=DELTA;//上面的if代码是为了防止分母为0报错return fabs((a-b)/max(fabs(a),fabs(b))) <= DELTA;//其实我感觉用这一句就够了return fabs(a-b)<=DELTA;}

数组

/*
数组程序
由开关阵列控制LED阵列
*/int inputPins[]={2,3,4,5}; //为开关输入创建引脚阵列
int ledPinds[]={10,11,12,13};//为LED输出创建引脚阵列void setup()
{for(int index=0;index<4;index++){pinMode(ledPins[index],OUTPUT);//声明LED对应引脚为输出模式pinMode(inputPins[index],);//声明按键对应引脚为输入模式digitalWrite(inputPins[index],HIGH);//按键引脚,允许上拉电阻}
}void loop()
{for(int index=x;index<4;index++){int val=digitaleRead(inputPins[index]);//读取输入值if(val=LOW)//检查开关是否按下{digitalWrite(ledPins[index],HIGH);//如果按下就点对应灯}else{digitalWrite(ledPins[index],LOW);//熄灭LED}}
}


要点:使用数字引脚,开关接GND,LED需要接电阻和GND

String

/*arduino字符串和c字符数组相比使用简单,但存在内存泄露、占用问题。
*/String text1="2只老虎";
String text2="爱跳舞";
String text3;//在程序内被赋值void setup()
{Serial.begin(9600);Serial.print(text1);Serial.print("is");Serial.print(text1.length());//length()返回字符数Serial.println("characters long.");Serial.print("text2 is");Serial.print(text2.length());Serial.println("characters long.");text1.concat(text2);Serial.println("用了text1.concat(text2);后text1变为");Serial.println(text1);
//加法运算符可以结合字符串text3=text1+text2;Serial.println("用了text3=text1+text2;后text3=");Serial.println(text3);}void loop(){}


C字符串

//strcpy(destination,source);//复制字符串从source到de
//strncpy(destination,source,6);//复制6个字符从source到de
//strcat(destination,source);//复制字符串从source到de的结尾
String text1=“Arduino”;
char stringA[8];//声明长达7个字符加上终止空字符的字符串
char stringB[8]=“Arduino”;//同上,并初始化
char stringC[16]=“Arduino”;//同上,但字符串有加长的空间
char stringD[]=“Arduino”;//由编译器初始化串并计算大小

* text1.concat(stringC);可以兼容,但+不能兼容char和string

比较和位运算

1.字符和数量值
比较相等关系

== != < > >= <=

if (strcmp(string1,string2)==0) //判断相等则返回0值,第一个大返回值大于零,否则小于0
//*可以在string2后加“,4”指定判断4个字符Serial.print("相等");

2.逻辑比较

&&与 ||或 !非

3.位运算

&按位与,二进制数,如果两个位都是1,才设置运算后的那个位为1,如3&1等于1(11&01=01)
|按位或,对应的两个位有1得1,3|1=11(11|01=11)
^按位异或,对应的两个位是一个1才设置1,如5 ^ 4 =2(110 ^ 100=010)
~取反,反转每个位(比特bit)的值,如 ~ 1 =254(~00000001=11111110)

4.余数
%

5.其他常用计算函数

abs(x)计算x的绝对值 constrain(x,min,max)返回一个在min和max范围内的值 min(x,y) max(x,y)
返回最值 pow(x,y) 计算x的y次方 sqrt(x) x的平方根 floor(x) 向下取整,不大于x的最大整数值
ceil(x)向上取整,不小于x的最小整数值 sin(x) cos(x) tan(x)

*设置和读取位

最右边是最低位 bitSet(x,bitPosition) 设置 写入1 bitClear(x,bitPosition)清除 写入0
bitRead(,)返回指定位的值 bitWrite(x,bitPosition,value)
设置x的第bitPosition位为value值(0或1) bit(bitPosition)返回给定的比特位置的值 bit(0)=1
bit (1)=2 bit(2)=4

所以8个开关的状态可以包装成一个单一的8位值,而不需要8个字节或整数 int整数值刚好由2个字节,16个位组成。
取高低字节就是取高8位低8位:

A=258;//16进制数为0x102=(B)0000 0001 0000 0010
lowByte(A);//取最低8位=(B)0000 0010=(10进制数)2
highByte(A);//取最高8位=(B)0000 0001=(10进制数)1

本质上是位运算,所以可以自己定义这样的函数如下

//w为32位数,取高16位就是把整体右移16位。宏表达式为
#define highWord(w) ((w)>>16)
//取低16位就是把高16位变成0,可以用高16位为0的数去 与运算
#define lowWord(w) ((w) & 0xffff )

*从高字节和低字节组合成一个int或long值
word(high,low)把高低字节组装成一个16位值(2字节)

*复合运算和赋值

运算符 例子
+= 或-=和*=或/= value+=5;//本身加5,用于递增或递减
>>=或<<= value>>=2;//向右移动2位
&=或 |= value&=2;//用2对value做二进制 与屏蔽

*字符串和数字的互相转化

/*
*1.从给定数字创建一个字符串
itoa 从整数到ASCII码,Itoa长整数到ASCII码
*/void setup()
{Serial.begin(9600);}char buffer1[12];//long数据类型有11个字符  包括减号和末尾空字符void loop(){long value=15;itoa(value,buffer1,2);//要转的值value,将要存放输出字符串的缓冲区为buffer1,2进制// Serial.print(value);Serial.print(buffer1);Serial.print("为转换的二进制值,有");Serial.print(strlen(buffer1));Serial.print("位数,");value=23333;itoa(value,buffer1,16);Serial.print(value);Serial.print("转为16进制数");Serial.print(buffer1);Serial.print("有");Serial.print(strlen(buffer1));Serial.println("位数");delay(1000);}//结果:1111为转换的二进制值,有4位数,23333转为16进制数5b25有4位数
/*
*2.从给定字符串创建一个数字
*/
const int ledPin=LED_BUILTIN;//LED连接的管脚、
int blinkDelay;//闪烁周期
char strValue[6];
int index=0;//存储所接收的数字的数字索引
void setup()
{Serial.begin(9600);pinMode(ledPin,OUTPUT);//LED引脚为输出}void loop(){if(Serial.available()){char ch=Serial.read();//读取电脑串口发来的文字为ASCII字符Serial.print(ch);if(index<4 && isDigit(ch)){//缓冲区未满而且ch是数字字符strValue[index++]=ch;//在字符串里加上ASCII字符}else{//这里是当缓冲区满或者遇到第一个非数字strValue[index]=0;blinkDelay=atoi(strValue);//使用atoi将字符串转换为int,赋值给闪烁周期值index=0;}}blink();}void blink()
{digitalWrite(ledPin,HIGH);delay(blinkDelay/2);//等待闪烁周期的一半digitalWrite(ledPin,LOW);delay(blinkDelay/2);//等待闪烁周期的一半}//这个程序存在的缺陷是一旦开始闪烁了,delay期间就不会执行任何串口的监测

b. 程序结构控制

顺序

选择

1.if
if()
{
语句;
}

const int ledPin=13;
const int inputPin=2;
void setup(){pinMode(ledPin,OUTPUT);
pinMode(inoutPin,INPUT);
}
void loop(){int val = digitalRead(inputPin);//读取输入值
if(val==HIGH)//检查是否为高{digitalWrite(ledPin,HIGH);//如果开关被按下就点亮LED}//else if(...){...}
else
{digitalWrite(ledPin,LOW);//否则关闭LED
}
}

2.switch

只能整型或者字符型

switch(字符变量)
{case '1':函数1;break;case '+':函数2;default:函数3break;
}

循环

1.while

while(条件){}
do
{}
while(条件);

2.for

for(int i=0;i<4;i++){...}

3.跳出循环
break;
continue;

while(analogRead(sensorPin)>100)
{if(digitalRead(switchPin)==HIGH)//开关引脚接GND{break;//如果开关没按下就退出循环}flashLED();//只有传感器值大于100且开关按下才会闪LED
}

c. 函数

int blink3(int period)
{…}
返回类型 函数名 (参数类型 参数名字)

需要函数返回多个值可以在最开始定义全局变量,然后在函数中改变全局变量。也可以使用引用,符号&表示该参数是引用,函数内值的变化也将改变调用该函数时被赋值的变量的值。如下:
void swap(int &value1,int &value2)
返回类型 函数名 (参数类型 &参数名字)

函数声明:告知编译器你要引用函数,出现在顶部,结束加分号如下:
void swap(int &value1,int &value2);

常用函数先略,后面出现再介绍。

d. 库的使用

内置库

#include <Servo.h>//头文件在库的文件夹
#include “Servo.h”//头文件在当前文件夹
一些常用的库:SoftwareSerial软串口
SPI以太网和SPI硬件
Wire I2C设备
Stepper 步进电机的工作

*其他:
EEPROM内存 Ethernet以太网通讯 FIrmata简化串行通讯和板卡控制的协议
LiquidCrystal 液晶显示器 SD支持使用外部硬件读取和写文文件到SD卡
Matrix 管理LED阵列
Sprite 激活与LED阵列…

创建自己的库

*可以先不看
#开头的语句被称为预处理命令
#define 标识符字符串 宏定义
#include 文件包含 条件编译 用来防止重复定义
#ifndef 标识符 程序段
#endif

#if 表达式 程序段1
#else 程序段2
#endif

/* 创建一个 blinkLED.cpp 一个以给定的毫秒数时间点亮LED的简单库
*/

#include “Arduino.h”//arduin函数和常数的库所需要的
#include “blinkLED.h”//包含了你库的函数定义

//在给定的引脚以给定的时间闪烁LED void blinkLED(int pin, int duration) {
digitalWrite(pin, HIGH); //打开LED delay(duration);
digitalWrite(pin, LOW); //关闭LED delay(duration); }

/* 再创建一个blinkLED.h要放在和cpp文件一起的文件夹*/

#include “Arduino.h” void blinkLED(int pin, int duration);//函数原型

//最后在blinkLibTest程序中#include “blinkLED.h”

关键字高亮显示需要再建立一个keywords.txt文件,键入:你的关键词 KEYWORD1

二. 物理原型开发基础(Arduino)

a. 交互式硬件原型的开发基础:电流、常⽤电⼦元件、示意图与电路图,万⽤表、焊接、 ⾯包板的使⽤。


面包板原理图

从原理图可以看到,面包板上下区是横向5位相通,一般用于接电源和接地,中间区域是纵向5位相通,通常用于放置电路元件和电路连接线。

电阻:对电流起阻碍作用的元件。
电容:装电的容器,旁路、去耦、滤波、储能作用。
二极管:单项传导电流,整流、稳压作用。
三级管:放大、振荡、开关作用。EBC三级,有两种是PNP和NPN。
继电器:可控电子开关,原理电磁效应控制线圈。

传感器
电阻类:光敏电阻(光亮电阻降)
人体热释电红外传感器:对人体辐射出的红外线敏感,无人在监测范围内输出低电平,有人输出高电平脉冲信号。
温度传感器
五相倾斜:内部由一个金属球和4个触点组成,检测4个倾斜方向和水平位置共5种状态。
触摸模块:电容触摸感应原理检测人体接触,有人高无人低。

模拟声音传感器:检测周围环境声音的大小
气体传感器:使用气敏材料是在清洁空气中电导率较低的二氧化锡,当传感器所处环境中存在可燃气体时,传感器的电导率随着空气中可燃气体浓度的增加而增大。使用简单的电路就可以将电导率的变化转换为与该气体浓度相对应的输出信号。



时钟模块:虽然arduino的millis()和micro()可以获取运行时间,但是到一定时间就会溢出,而且断电不保存,可以用时钟模块准确、长时间计时。


显示器

b. 串⼝通信

串口(UART)

一种信息交互方式,硬件提供Arduino和它正在与之通信的设备之间的电信号,软件使用硬件发送所连接的硬件可以理解的字节或位。
硬件位于0(RX) 1(TX)两个引脚。

Arduino的串口库隔离了大部分硬件的复杂性,比较容易使用。

硬件串口

原理:串口硬件的发送和接收表示序列位的电脉冲数据。Arduino使用TTL电平表示构成字节信息的0和1,用0V表示比特率0 , 5V(或3.3V)表示比特值1。
大多数arduino板子有一个芯片把硬件串口转换成通用串口总线USB,用于连接到其他硬件串口。有的设备使用RS-232标准进行串口连接,通常有9针连接器,是一种旧的通讯协议,采用的电压与arduino不兼容。

Arduino Mega有4个硬件串口,可以与4个串口设备进行通讯,其中一个有USB接口

串口通讯的函数

1.初始化
Serial.begin(9600);//发送和接受的波特率范围是300~115200。9600,即每秒钟传输9600个“位元”(比特bit)
2.输出
Serial.print() 打印完不换行
Serial.println(“char1”);
Serial.println(char1); 打印完换行
Serial.println(char1,HEX);//HEX是16进制形式输出 OCT是10进制 BIN是二进制

(*print和write的区别,print发送的不是数据本身而是转换为字符,然后将字符对应的ASCII码发出去,串口监视器收到ASCIII码就会显示对应的字符,而write发送的是数值本身,串口监视器收到后会把数值当做ASCII码而显示对应的字符)
3.输入
Serial.read()
调用该函数时,arduino会从64B的缓冲区中取出1B的数据
4.Serial.available();
返回值就是当前缓冲区中接收到的数据字节数

*串口事件 void serialEvent(){} 当串口缓冲区中有数据,就会触发该事件。

*可以利用C++的流插入语法和模板,如果声明了一个流模板就可以使用它。
可以简化为 Serial<< “At” << t <<“seconds,speed=”<< s <<", distance =" << d << endl;

举一个USB串口通讯的实例(实际上在前面已经涉及过了)

/*
打印数字到串口监视器
*/
void setup()
{Serial.begin(9600);//发送和接受的波特率范围是300~115200。9600,即每秒钟传输9600个“位元”(比特bit)
}
int number=0;
void loop()
{Serial.print("The number is ");Serial.println(number);//打印数字并换行delay(500);number++;
}

也可以再复习一下这个用Serial.read接收电脑从串口传来的数据,然后转为数字,改变LED闪烁周期的。
接受单个数字的

const int ledPin=13;
int blinkRate=0;
void setup()
{Serial.begin(9600);pinMode(ledPin,OUTPUT);
}
void loop()
{if(Serial.available())//检查串口是否至少有一个可用字符{char ch=Serial.read();if(isDigit(ch)){blinkRate=(ch-'0');//ASCII值转换为数字值!!!!!!!!!!!!!!!blinkRate=blinkRate*100;//实际速率为100ms乘以接收的数字}}
blink();
}void blink()
{digitalWrite(ledPin,HIGH);delay(blinkRate);//等待闪烁周期的一半digitalWrite(ledPin,LOW);delay(blinkRate);//等待闪烁周期的一半}

复杂一点的,要用C语言转换函数atoi或atol把文本转化为数字

/*
*从给定字符串创建一个数字
*/
const int ledPin=LED_BUILTIN;//LED连接的管脚、
int blinkDelay;//闪烁周期
char strValue[4];//最多包含4位数字
int index=0;//存储所接收的数字的数字索引
void setup()
{Serial.begin(9600);pinMode(ledPin,OUTPUT);//LED引脚为输出}void loop(){if(Serial.available()){char ch=Serial.read();//读取电脑串口发来的文字为ASCII字符Serial.print(ch);if(index<4 && isDigit(ch)){//缓冲区未满而且ch是数字字符strValue[index++]=ch;//在字符串里加上ASCII字符}else{//这里是当缓冲区满或者遇到第一个非数字strValue[index]=0;blinkDelay=atoi(strValue);//使用atoi将字符串转换为int,赋值给闪烁周期值index=0;}}blink();}//这个程序存在的缺陷是一旦开始闪烁了,delay期间就不会执行任何串口的监测
void blink()
{digitalWrite(ledPin,HIGH);delay(blinkDelay/2);//等待闪烁周期的一半digitalWrite(ledPin,LOW);delay(blinkDelay/2);//等待闪烁周期的一半}

可以学习一下处理思路,实战可以直接用Serial.parseInt()或Serial.parseFloat()读取串口字符,并返回表示的数值

/*
*parseInt方法从给定字符串创建一个数字
*/
const int NUMBER_OF_FIELDS =3;//预计有多少个逗号分割的字段
int fieldIndex=0;//接受的当前字段
int values[NUMBER_OF_FIELDS];//保存所有字段数值的数组void setup()
{Serial.begin(9600);}void loop(){if(Serial.available()){for(fieldIndex=0;fieldIndex<3;fieldIndex++){values[fieldIndex]=Serial.parseInt();//获取一个数值}Serial.print(fieldIndex);Serial.println("fields received:");for(int i=0;i<fieldIndex;i++){Serial.println(values[1]);}}}

发送多个文本最简单的方法就是字符分割

软件串口

一个标准的arduino有一个硬件串口,但你也可以用软件库来模拟附加的端口(通信通道),以连接一个以上的设备,即软件串口,它需要耗费内存资源,所以速度效率不如硬件串口。
程序示例:

#include <softwareSerial.h>
const int rxpin=2;//用于接收LCD的引脚 const int txpin=3;//用于传送到LCD显示屏的引脚 SoftwareSerial
serial_lcd(rxpin,txpin);//新的串口为引脚2个和3个
void setup(){serial_lcd.begin(9600);}

多个串口

1.只有RX接收脚的LCD

/*
在同一时间将数据发送到两个串口设备,硬件串口
*/

//void setup(){ // 初始化mega的两个串口
Serial.begin(9600);//主串口
Serial1.begin(9600);//mega也可以用serial1到serial3 }

/*
SoftwareSerialOutput
输出数据到软件串口
*/
#include <softwareSerial.h>
const int rxpin=2;//用于接收LCD的引脚
const int txpin=3;//用于传送到LCD显示屏的引脚
SoftwareSerial serial_lcd(rxpin,txpin);//新的串口为引脚2个和3个
void setup()
{
Serial.begin(9600);
serial_lcd.begin(9600);//初始化软件串口也为9600b/s
}
int number=0;

void loop(){
serial_lcd.print("The number is ");//文本发送到LCD
serial_lcd.print(number);
Serial.print("the number is ");//在PC控制台打印数字
Serial.print(number);
delay(1000);
number++;
}

GPS同理,
区别是软串口的波特率改为4800
loop中改为这一段

if(serial_gps.available()>0)//有任何字符达到吗{{char c=serial_gps.read();//如果是,从GPS读取它  Serial.Write(c);//在串口控制台回显它
}
/*
*接受来自两个软件串口的数据
*/
#include <SoftwareSerial.h>
const int rxpin1=2;
const int txpin1=3;
const int rxpin2=4;
const int txpin2=5;SoftwareSerial gps(rxpin1,txpin1);//GPS设备连接到引脚2和3
SoftwareSerial xbee(rxpin2,txpin2);//XBee设备连接到引脚4和5void setup(){xbee.begin(9600);gps.begin(4800);xbee.listen();//设置XBee为活性设备  }
void loop(){if(xbee.available()>0)//XBee被激活{if(xbee.read()=='y')//收到y字符{gps.listen();//现在开始监听GPS设备unsigned long start=millis();//开始监听GPS并计时while(start+100000>millis())//监听10s{if(gps.available()>0)//现在GPS设备被激活{char c=gps.read();//***在这里处理GPS数据}}xbee.listen();//10s后返回到监听XBee}}}

c. 简单数字和模拟输⼊

开关



if(digitalRead(inputPin)=HIGH)
{digitalWrite(ledPin,HIGH)}

arduino内部有上拉电阻,可以不用外部电阻,程序需要修改一下

/*
连接到引脚2 的开关电脑引脚13的LED
*/
const int ledPin=13;
const int inputPin=2;void setup()
{pinMode(ledPin,OUTPUT);pinMode(inputPin,INPUT);digitalWrite(inputPin,HIGH);//打开inputpin上的内置上拉电阻
}
void loop()
{int val=digitalRead(inputPin);if(val==HIGH){digitalWrite(ledPin,HIGH);//打开LED}else{digitalWrite(ledPin,LOW);//打开LED}}

按键消抖

本程序针对下拉电阻,按钮按下输入arduino高电平

const int inputPin=2;//输入引脚号
const int ledPin=13;//输出引脚号
const int debounceDelay=10;//稳定之前循环等待的次数//按键稳定闭合debounceDelay时间,则返回true
boolean debounce(int pin)
{boolean state;//用于记录本次状态boolean previousState;previousState=digitalRead(pin);for(int counter=0;counter<debounceDelay;counter++){delay(1);//每次延时1msstate=digitalRead(pin);if(state!=previousState)//按键状态发生变化{counter=0;//计数器重新计数previousState=state;}}//按键状态不变return state;}void setup(){pinMode(inputPin,INPUT);pinMode(ledPin,OUTPUT);  }void loop(){if(debounce(inputPin)){digitalWrite(ledPin,HIGH);}}

如果用前面提到的上拉电阻,就要改变一下boolean debounce的返回值如下:

boolean debounce(int pin){boolean state;boolean previousState;previousState=digitalRead(Pin);for(counter=0;counter<debounceDelay;counter++) {//增加debounceDelay值直到计数与按键动作同步delay(1);//等待1msstate=digitalRead(pin);//读取引脚if(state!=previousState){counter=0;state=previousState;}}if(state==LOW)//low表示按下return true;elsereturn false;
}//用count显示按压的次数
int count;
void setup()
{pinMode(inPin,INPUT)pinMode(outPin,OUTPUT)
}
void loop
{if (debounce(input)){digitalWrite(outPin,HIGH);count++;Serial.println(count);}
}

/*
*switchTime 函数将返回开关被按压的毫秒数
*使用上拉电阻
*静态变量,即使在函数返回后仍然保留,只能在该函数内访问,好处是不能被一些其他函数意外地修改
*/

const int switchAPin=2;//开关2 的引脚
const int switchBPin=3;//开关3 的引脚

//带引用的函数必须显式声明
unsigned long switchTime(int pin, boolean &state,unsigned long &startTime);
long switchATime();
long switchBTime();

void setup()
{
pinMode(switchAPin,INPUT);
digitalWrite(switchAPin,HIGH);//打开上拉电阻
pinMode(switchBPin,INPUT);
digitalWrite(switchBPin,HIGH);//打开上拉电阻
}

void loop(){
unsigned long time;
Serial.print(",按键A的时间为:");
time=switchATime();
Serial.print(time);

Serial.print(",按键B的时间为:");
time=switchBTime();
Serial.print(time);
delay(1000);
}

unsigned long switchTime(int pin,boolean &state, unsigned long &startTime)
{
if(digitalRead(pin)!=state)//检查开关量是否改变
{
state=!state;//是 则反转状态值
startTime=millis();//存储时间
}
if(state == LOW)
return millis()-startTime;//返回以毫秒为单位的时间
else{return 0;//开关没有按下 在HIGH状态
}
}

long switchATime()
{
//声明静态变量
//开关状态改变第一次检测被检测到的时间
static unsigned long startTime=0;
static boolean state;//开关的当前状态
return switchTime(switchAPin,state,startTime);
}

long switchBTime()
{
//声明静态变量
//开关状态改变第一次检测被检测到的时间
static unsigned long startTime=0;
static boolean state;//开关的当前状态
return switchTime(switchBPin,state,startTime);
}

数字键盘

按键相当于一个常开开关

//读取数字键盘
/*keypad:键盘上的键打印到电脑串口
*/const int numRows = 4; //在键盘的行数
const int numCols = 3; //列数
const int debounceTime = 20; //开关稳定需要的毫秒数
//keymap定义相应的键被按下返回的字符
const char keymap[numRows][numCols] = {{'1', '2', '3'},{'4', '5', '6'},{'7', '8', '9'},{'*', '0', '#'}
};//这个数组确定用于行和列的引脚
const int rowPins[numRows] = {7, 2, 3, 6}; //0-3行
const int colPins[numCols] = {5, 8, 4}; //0-2列void setup()
{Serial.begin(9600);for (int row = 0; row <= numRows; row++){pinMode(rowPins[row], INPUT); //设置引脚为输入digitalWrite(rowPins[row], HIGH); //打开上拉电阻}for (int column = 0; column < numCols; column++){pinMode(colPins[column], OUTPUT); //设置引脚为输出digitalWrite(colPins[column], HIGH); //使所有列不活跃}
}void loop()
{char key = getKey();if (key != 0) {Serial.print("有效按键");Serial.print(key);}//返回按下的键值
}char getKey()
{char key = 0;//表示没按for (int column=0;column<numCols;column++)//按顺序拉低列电平{digitalWrite(colPins[column],LOW);//激活当前列为低电平for(int row=0;row<numRows;row++){//开始扫描每一行查找被按下的键,它将是低电平if(digitalRead(rowPins[row]==LOW)){delay(debounceTime);//去抖while(digitalRead(rowPins[row])==LOW);//等待按键被释放key=keymap[row][column];//记住哪个按键被按下}}//行扫描完毕digitalWrite(colPins[column],HIGH);//拉高当前列,下次循环拉低下一列}return key;//返回按下的键,如果没有按下,返回0    }

模拟输入

**analogRead()**会自动设置输入,
0V对应0,5V对应1023

/* 按一个电位器的位置设置的速度闪烁LED 注意区分模拟输入0和数字输入0
*/

const int potPin = 0; //选择电位器的输入引脚
const int ledPin = 13;
int val = 0;

void setup()
{
pinMode(ledPin, OUTPUT); //
}

void loop() {
val = analogRead(potPin); //读取电位器上的电压
digitalWrite(ledPin, HIGH);
delay(val);
digitalWrite(ledPin, LOW);
delay(val);
}

/* 按一个电位器的位置设置的速度闪烁LED
*/

const int potPin = 0; //选择电位器的输入引脚
const int ledPin = 13;
int val = 0;

void setup()
{
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}

void loop() {
val = analogRead(potPin); //读取电位器上的电压
int percent;//映射的值
percent=map(val,0,1023,0,100);//map整数运算读取的电压值对应百分比 的映射
digitalWrite(ledPin, HIGH);
delay(percent);
digitalWrite(ledPin, LOW);
delay(100-percent);
Serial.println(percent);
}

*多路复用模拟输入

测量电压

应用:电量不足时LED闪烁,到临界电压级别时LED长亮
long warningThreshold = 1200; //毫伏在警告级别 - LED闪烁
long criticalThreshold = 1000; //临界电压级别 - LED长量

const int batteryPin = 0;
const int ledPin = 13;

void setup()
{
pinMode(ledPin, OUTPUT);
}

void loop()
{
int val = analogRead(batteryPin);
if (val < (warningThreshold * 1023L / 5000))
{ //在上面的行中 一个数后跟L得到一个32位的值
flash(val / 1023);
}
else if (val < (criticalThreshold * 1023L / 5000))
{
digitalWrite(ledPin, HIGH);
}
}

void flash(int percent)
{ digitalWrite(ledPin, HIGH);
delay(percent + 1);
digitalWrite(ledPin, LOW);
delay(100 - percent); //检查延时==0?
}

d. 获取传感器输⼊

传感器提供信息的方式:
数字开关:倾斜 动作传感器
模拟信号:光 振动 声音 加速度
脉冲宽度:距离传感器 pulseln命令测量脉冲持续时间
串口:RFID GPS
同步协议:I2C SPI
通用传感设备 鼠标和游戏控制器等

各传感器原理简介见二、a

动作(数字量高低电平,类似开关)

//倾斜传感器
const int tiltSensorPin = 2; //连接传感器 的引脚
const int firstLEDPin = 11;
const int secondLEDPin = 12;

void setup() {
pinMode(tiltSensorPin, INPUT); //设置 传感器引脚 为输入
digitalWrite(tiltSensorPin, HIGH); //上拉电阻

pinMode(firstLEDPin, OUTPUT);
pinMode(secondLEDPin, OUTPUT);

}

void loop() {
if (digitalRead(tiltSensorPin) )
{
digitalWrite(firstLEDPin, HIGH);
digitalWrite(secondLEDPin, LOW);
}
else {
digitalWrite(firstLEDPin, LOW);
digitalWrite(secondLEDPin, HIGH);
}
}
可以理由按键消抖的原理消抖,程序略

动作检测(集成被动红外探测器PIR,只需判断模拟量高电平)


这种传感器引脚标有OUT - +
长这个样子的传感器基本上都是这么控制的↓,但是要注意信号电平的高低。
//红外传感器控制LED
const int inputPin = 2; //连接传感器 的模拟输入引脚2
const int ledPin = 13;

void setup() {
pinMode(ledPin, OUTPUT); //声明LED作为输出
pinMode(inputPin , INPUT); //被动红外传感器为输入引脚
}

void loop() {
int val = digitalRead(inputPin);
if (val == HIGH)
{ digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
}
}

光(光敏电阻模拟量)

//光敏电阻控制LED
const int SensorPin = 0; //连接传感器 的模拟输入引脚0
const int ledPin = 13;

void setup() {
pinMode(ledPin,OUTPUT);//LED引脚设为输出
}

void loop() {
int rate=analogRead(sensorPin);//读取模拟输入
digitalWrite(ledPin,HIGH);//设置LED开
== delay(rate);//等待时间取决于光照水平==
digitalWrite(ledPin,LOW);//设置LED开
delay(rate);//等待时间取决于光照水平
}

距离(超声波,输出模式纯净高电平+输入模式计算脉冲时间)


//超声波距离传感器控制LED
const int pingPin = 5; //连接传感器 的模拟输入引脚5
const int ledPin = 13;

void setup() {
pinMode(ledPin, OUTPUT); //声明LED作为输出
Serial.begin(9600);
}

void loop() {
int cm = ping(pingPin); Serial.println(cm);
digitalWrite(ledPin, HIGH);
delay(cm * 10); //每厘米增加了10ms的延迟
digitalWrite(ledPin, LOW);
delay(cm * 10);
}

int ping(int pingPin)
{ long duration, cm;
pinMode(pingPin, OUTPUT); //首先要给一个简短的的低电平脉冲以确保高电位脉冲触发
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);

pinMode(pingPin, INPUT); //传感器引脚改为输入模式,接受信号
duration = pulseIn(pingPin, HIGH); //计算出传感器引脚输入从低到高的时间,单位为微秒
//时间转换成距离
cm = duration * 29/ 2;//来回距离 超声波速度29us/cm
}

有不需要ping的超声波传感器,也是用pulseIn(pingPin, HIGH),是计算脉冲宽度,直接读值就可以。测量距离=pulseIn(pingPin, HIGH)*脉冲宽度速率

精确测距(*红外IR传感器比超声波精度高但量程小,输出非线性需要查表)


//红外距离传感器 测距输出
const int sensorPin = 0; //连接传感器 的模拟输入引脚0
const int ledPin = 13;
const long referenceMv = 5000; //长整形以防止做乘法时溢出
void setup() {
pinMode(ledPin, OUTPUT); //声明LED作为输出
Serial.begin(9600);
}

void loop() {
int val = analogRead(sensorPin);
== int mv = (val * referenceMv) / 1023;==//mv为距离信号

Serial.print(mv);
Serial.print(",");
int cm = getDistance(mv);
Serial.println(cm);

digitalWrite(ledPin, HIGH);
delay(cm * 10); //每厘米增加了10ms的延迟
digitalWrite(ledPin, LOW);
delay(cm * 10);
}

const int TABLE_ENTRIES = 12;
const int firstElement = 250; //第一项是250mv
const int INTERVAL = 250; //每个项之间的毫伏数
static int distance[TABLE_ENTRIES] = {150, 140, 130, 100, 60, 50, 40, 35, 30, 25, 20,15};//器件手册提供 假设单位是cm

int getDistance(int mV)
{
if (mV < INTERVAL )//判断是否在范围内, 可能还要写个超出最大距离的判断
return distance[TABLE_ENTRIES - 1]; //当距离比最小距离要小,返回最小距离
else
{
int index = mV / INTERVAL; //计算近似的信号值
float frac = (mV % 250) / (float)INTERVAL;//取余数,然后除以每项之差,用来插值计算
return distance[index] - ((distance[index] - distance[index + 1])* frac);
//返回计算出的距离值
}
}

振动(压电传感器/爆震传感器,应力越大电压越高。模拟量)


val=analogRead(sensorPin);
if(val>=THRESHOLD){…}

声音


//驻极体话筒
const int sensorPin = 0; //连接传感器 的模拟输入引脚0(可以省略
const int ledPin = 13;
const int middleValue = 512; //模拟值范围的中间值
const int numberOfSamples = 128; //每次读取多少个数过小无法覆盖完整波形周期,过大可能错过短的声音

int sample;//每次读取的值
long signal;//你已经去除直流偏移之后的读数
long averageReading;//循环读数的平均值

long runningAverage = 0; //计算值的运行平均数
const int averagedOver = 16; //新值以何种程度影响运行平均值,数字越大速度越慢

const int threshold = 400; //在什么水平LED亮

void setup() {
pinMode(ledPin, OUTPUT); //声明LED作为输出
Serial.begin(9600);
}

void loop() {
long sumOfSquares = 0; //正负幅值的平方和
for (int i = 0; i < numberOfSamples; i++) {
sample = analogRead(0); //读取一个数
signal = sample - middleValue; //算模拟信号 距离 直流中心值 的 偏移
signal *= signal;
sumOfSquares += signal;
}
averageReading = sumOfSquares / numberOfSamples; //计算运行平均值
runningAverage = ((averagedOver - 1) * runningAverage + averageReading) / averagedOver;
//即新运行平均值=原运行平均值+(这次采样平均值-原运行平均值)/16,分母averagedOver越大,每次改变就越小
//新值影响平均值的速度就越慢
if (runningAverage > threshold) {
digitalWrite(ledPin, HIGH);
}
else {
digitalWrite(ledPin, LOW);
}
Serial.println(runningAverage);//打印检查
}

const int TABLE_ENTRIES = 12;
const int firstElement = 250; //第一项是250mv
const int INTERVAL = 250; //每个项之间的毫伏数
static int distance[TABLE_ENTRIES] = {150, 140, 130, 100, 60, 50, 40, 35, 30, 25, 20, 15}; //器件手册提供

int getDistance(int mV)
{
if (mV < INTERVAL * TABLE_ENTRIES - 1)
return distance[TABLE_ENTRIES - 1]; //当距离比最小距离要大,返回最小距离
else
{
int index = mV / INTERVAL; //插值计算,
float frac = (mV % 250) / (float)INTERVAL;
return distance[index] - ((distance[index] - distance[index + 1]) * frac);
}
}

温度


类似光敏传感器,该温度传感器模拟电压与温度成正比,需要写相应程序计算。

*RFID标签

RFID 射频识别,对无线电频率敏感,易被干扰。

硬件图注意读取器有使能和输出引脚,前一个是arduino用来发给它激活信号(低电平)的,后一个是它把接收到的RFID传输给Arduino的,占用了硬串口,理论上你应该不能用电脑看到传输了什么数据。程序实现RFID读取并对特定ID回应:
const int startByte = 10; //每个标签之前的ASCII换行符
const int endByte = 13; //ASCII回车结束每个标签
const int tagLength = 10; //标签数位
const int totalLength = tagLength + 2; //标签的长度 + 开始和结束字节
char tag[tagLength + 1]; //保存标签和一个终止空白符

int bytesread = 0;
void setup() {
Serial.begin(2400);//设置为RFID阅读器的波特率
pinMode(2, OUTPUT); //输出到RFID
digitalWrite(2, LOW); //使能RFID}
}
void loop() {
if (Serial.available() >= totalLength) //检测是否有足够数据
{
if (Serial.read() == startByte)
{ bytesread == 0; //标签的开始,重置计数为0
while (bytesread < tagLength) //读取10位编码
{ int val = Serial.read();
if ((val == startByte) || (val == endByte)) //检查编码结束
break;
tag[bytesread] = val;
bytesread = bytesread + 1; //准备读取下一个数字
} if (Serial.read() == endByte) //检查正确的结束字符
{ tag[bytesread] = 0; //终止字符串
Serial.print(“RFID 标签是:”);
Serial.println(tag);
}
}
}
}

*旋转动作(旋转编码器)

测量并显示某物的旋转,跟踪速度和方向

代码逻辑:
首先把AB对应的4、2引脚置为输入模式,然后写高激活,
当A脚的状态和上次测量不同时,(上升沿或者下降沿)
B是低的,编码器位置减1,
若B高电平,编码器位置加1。
最后计算角度=(编码器位置 %走一圈的步数)*360度/走一圈的步数

拓展知识:中断
利用中断可以实现只有在收到传感器信号“当A脚的状态和上次测量不同时,(上升沿或者下降沿)”的时候程序才会去检查传感器值,而不是始终检查传感器值。

*鼠标

*GPS

*加速度(陀螺仪测量角加速度,加速度计测量移动加速度如重力加速度)


e. 可视输出、物理输出、声⾳输出

显示

1.数字输出
pinMode(outputPin,OUTPUT)
digitalWrite(outputPin,value)
2.模拟输出(uno的3 5 6 9 10 11引脚可以用)
analogWrite()
使用了一种脉冲宽度调制PWM技术,用数字脉冲模拟一个模拟信号
3.灯光控制。LED灯、阵列和数码显示,LCD文本和图形显示。
4.LED规格
5.复用,多个LED复用引脚,利用视觉暂留,靠按位扫描驱动。

利用复用技术16个引脚即可控制64个LED,
依次点亮所有LED的程序逻辑如下:
首先在setup中循环调好所有的行列引脚为输出模式
然后在loop中,计数当前为第n个灯,/和%计算出行列值,
之后for循环扫描每一行列依次点灯,具体为:拉低当前列,要判断当前点的灯有没有达到n的位置,未达到或者刚好达到就输出行高电平,超过就输出低电平,最后延时为这个LED给出20ms的帧时间,然后给低电平,关灯。

6.最大引脚电流 <40mA <200mA。驱动高功率需要用晶体管和外接电源。

计算LED串联的电阻值

数码管


这个是共阳极,给低电平点亮 段

数码管相当于8位LED串联,分共阴极和共阳极
驱动单位共阳极数码管的程序逻辑:
首先定义数组存储字形码
const byte numeral[10]={
//ABCDEF/dp 共阴极的字形码
B11111 1100,//0
, , , , …};2 个字节的每一位可以代表一个引脚的输出状态
然后定义引脚,设置为输出模式
在循环中调用数码管显示函数显示值,延时
数码管显示的函数:void showDigit(int number),循环检查是否点亮 for(int segement=1;segment<8;sengment++) 用到bitRead(numeral[number],segment) 读给定数字的字形码,赋值给isBitSet,如果为1,则isBitSet != isBitSet ,如果是共阴极数码管就不用这个操作,最后对应引脚拉低。

驱动多位LED数码管显示器
在单位的基础上,增加一个位数循环,依次点亮指定位指定的led段

为解决引脚占用,可以接MAX7221等数码管驱动芯片,需要查芯片的命令手册,并用到SPI通信,
用自定义函数sendCommend(int command, int value)发送指令函数,利用digitalWrite(使能引脚,LOW) SPI.transfer(command);SPI.transfer(value); digitalWrite(使能引脚,HIGH)

电机

1.舵机 即直流伺服电机。分为带位置反馈的角度控制舵机和断开位置反馈的连续旋转舵机。

红正棕负橙信号

控制舵机角度:
第一步库和对象
#include <Servo.h>//引入舵机库
Servo myservo;//创建舵机对象来控制指定舵机
第二步 信号引脚连接对象
void setup()
{
myservo.attach(9);//把连接在引脚9上的舵机赋予舵机对象
}
第三步使用wite写角度
void loop()
{
myservo.write(angle);
}

正反转摇摆:

#include <Servo.h>//引入舵机库
Servo myservo;//创建舵机对象来控制舵机int angle = 0; //用来存储舵机位置的变量void setup()
{myservo.attach(9);//把连接在引脚9上的舵机赋予舵机对象
}void loop()
{for (angle = 0; angle < 180; angle++){ //步长为1度myservo.write(angle);delay(20);//舵机命令之间等待20ms}for (angle = 180; angle > 0; angle--){myservo.wirte(angle);//在相反方向上移动舵机delay(20);}}

如果是连续旋转舵机,控制同理,但是给90°停止转动,距离90°越远,向一个方向转速越快。

2.有刷电机和无刷电机

可用H桥电路控制有刷电机,直接用元件即可,需要接一个用来使能的模拟引脚用analogWrite()PWM控制速度,一对数字引脚控制不同方向旋转和停止。
具体略。

可利用业余调速器控制无刷电机 代码和舵机代码相等

3.步进 每步走1°、2°、30°或更多。也是H桥,但可以用Stepper的库

#include <Stepper.h>
#define STEPS 24//更改电机步数
//创建实例  指定步数和引脚
Stepper stepper(STEPS, 2, 3, 4, 5,);int steps = 30; //走一步步长void setup()
{stepper.setSpeed(30);//设置电机的速度到30RPM
}void loop() {stepper.step(steps);
}

4.振动马达 像点亮LED一样就行,代码见第"三"部分

音频

扬声器原理
压电装置:施加脉冲时会产生声音的陶瓷换能器
有源蜂鸣器自身包含震荡源,给高电平就能响,


所以介绍无源蜂鸣器,由arduino给音频信号

//音调播放
//tone函数,可以通过数字引脚9上的扬声器播放音调const int speakerPin = 0; //扬声器连接到支持PWM的引脚9,
const int pitchPin = 0; //决定音调频率的电位器输入
void setup()
{}void loop()
{int sensor0Reading = analogRead(pitchPin); //读电位器调整的音高信号int frequrency = map(sensor0Reading, 0, 1023, 100, 5000); //映射电位器信号到一个合适的范围//100Hz~5kHzint duration = 250; //音调持续的时间tone (speakerPin, frequency, duration); //向扬声器输出由电位器给的音调信号,持续0.25sdelay(1000);
}

如果要同时产生多个音调做出电子琴的效果,可以用Tone.h的库,用switch分支选择输出给扬声器的音调,演奏对象.play(音调)方法。

f. ⽆线通信和⽹络

* I2C和SPI

I2C内部集成电路和SPI串行外设接口标准的建立是为传感器和微控制器之间的数字信息传输提供简单的方法。
I2C只需要2路信号连接到arduino,同一时间只能在一个方向上传送。通常用于不需要大量数据的传感器。(加速度计、外部实时时钟RTC、外部存储器芯片EPROM、数字温度计、LED数码管、另一个arduino等)
SPI速度更快,有独立的输入输出连线,可以同时收发数据。

I2C总线的两路连线叫SCL和SDA,Arduino作为主设备。
用Wire.h库可以轻松初始化和通讯。

下面一个例子是和游戏手柄I2C通讯



时钟



无线XBEE

分为发送端和接收端,用到VirturalWire.h 库传输文本消息


蓝牙

//蓝牙模块
//电脑串口发送消息arduino收到后发到蓝牙端,蓝牙端发消息,arduino收到后发给电脑串口
//硬件串口的引脚0 1要和电脑发消息占用了,所以用软串口传输信息
#include<SoftwareSerial.h>const int rxpin = 2; //引脚用于接收
const int txpin = 3; //引脚用来发送SoftwareSerial buletooth(rxpin, txpin); //给出的端口上的新串口void setup()
{Serial.begin(9600);bluetooth.begin(9600);//初始化软件串口Serial.println("Serial ready");bluetooth.println("蓝牙准备就绪");
}void loop() {if (bluetooth.available()) {char c = (char)bluetooth.read();Serial.write(c);}if (Serial.available()) {char c = (char)Serial.read();bluetooth.write(c);}
}

*互联网

1.以太网:低级别的信号层,提供基本的物理信息传递能力。这些信息的源地址和目的地址由媒界访问控制MAC地址来确定。arduino程序定义的MAC地址需要在网络上唯一。
2.传输控制协议TCP和网际协议IP,
3.本地IP地址,路由器提供,在路由器上的动态主机配置协议DHCP服务创建。从web浏览器发出的web请求和所得到的的回应使用超文本传输协议HTTP信息。网页通常使用超文本标记语言HTML格式。网络交换格式已被开发用在应用计算机软件实现可靠的网络数据提取,XML和JSON是流行的格式。

三. 上述技术在设计原型制作和开发中的应⽤。

1.接收到____信号时,_____动作

最简单的可以看做按钮和LED灯
按钮可以换成各种传感器还有通讯传输接受的数据,LED可以换成电机、蜂鸣器、显示屏等。

原理图都和这个大差不差,图片顺时针转90度,
左边模拟量
连传感器、H桥驱动模块等元件的使能引脚给速度值

右边数字量
连开关、LED、有源蜂鸣器、马达、传感器的使能脚、H桥的方向引脚。
PWM(3/5/6/9/10/11):电机、无源蜂鸣器等。
数字引脚通过程序可以模拟成串口通信引脚。
*(0和1一般不用,占用硬件串口UART。
2和3可以接外部中断。10-13SPI通信)

如光敏传感器和振动马达
const int motorPin = 3; //振动马达的引脚
const int sensorPin = 0; //光敏探测器连接到模拟输入口0;
int sensorAmbient = 0; //环境光水平
const int thresholdMargin = 100; //高于环境多少就需要振动void setup()
{pinMode(motorPin, OUTPUT); //输出到马达pinMode(sensorPin, INPUT); //接收传感器信号
}void loop() {int sensorValue = analogRead(sensorPin) ;if (sensorValue > thresholdMargin + sensorAmbient){digitalWrite(motorPin, HIGH);//马达振动}else {digitalWrite(motorPin, LOW);//停止振动}
}

细化改一下可以做智能窗帘。

2.智能水杯(传感器、显示器、LED、蜂鸣器、蓝牙等等综合运用)

温度传感器(塑料水杯) 压力传感器(水量监控) LCD液晶显示器 LED灯x2 蜂鸣器

水量监控:压力传感器实时健康水量。

智能饮水累计:初始饮水量为0,如果压力传感器计数小于1,暂停一段时间再计数,并计算饮水数。如果一段时间后饮水量未变,蜂鸣器报警。

不同温度下指示灯不同,温度传感器监测到水温超过。

水温报警功能,如果水温过高拿起水杯,蜂鸣器响起,提示使用者。

蓝牙用于信息传输,可以控制硬件。

Arduino基础知识复习12.18相关推荐

  1. 2011计算机等级考试二级c语言公共基础教程.doc,2011年全国计算机等级考试二级c语言公共基础知识复习100题及答案.doc...

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp资格/认证考试&nbsp>&nbsp计算机等级考试 2011年全国计算机等级考试二级c语言公 ...

  2. Java基础知识复习(一)

    Java基础知识复习(一) 目录 Java简介 命名规则 八种基本的数据类型 字面量 类型转换 变量的形态 逻辑运算符 位运算 移位运算 习题知识点 目录 Java简介 Java是由Sun公司在199 ...

  3. java基础知识复习(上半)

    java基础知识复习 java为什么被发明? Green项目的确立,应用于像电视盒一样的消费类电子产品,语言本身本身中立. java的三大版本? javaSE的定位在于客户端,只要用于桌面应用软件的编 ...

  4. 考试备战系列--软考--02基础知识复习

    这部分主要是计算机基础知识的概念介绍,相关系列文章如下所示. 考试备战系列--软考--01基础架构概念 考试备战系列--软考--02基础知识复习 考试备战系列--软考--03综合知识复习 考试备战系列 ...

  5. linux基础知识复习

    @(tigerfive)[linux,基础知识,复习笔记] linux基础复习(一) 今天只整理框架,具体内容之后详细整理吧 文件管理 文件基本操作 创建文件和目录 拷贝文件和目录 剪切文件和目录 删 ...

  6. 2021 版 Spring Boot 基础知识复习手册(2w字,建议收藏)

    点击上方 好好学java ,选择 星标 公众号重磅资讯,干货,第一时间送达 今日推荐:分享一套基于SpringBoot和Vue的企业级中后台开源项目,这个项目有点哇塞!个人原创100W +访问量博客: ...

  7. JDBC基础知识复习

    JDBC基础知识复习 1.JDBC连接数据库 1.1.导入JDBC驱动 1.2.注册JDBC驱动程序 1.3.创建连接对象 1.4.关闭JDBC连接 1.5.每种数据库对应的驱动名和URL 2.JDB ...

  8. 计算机二级的公共基础课水平测试,计算机二级公共基础知识复习试题含答案

    计算机公共基础课程,是针对高校非计算机专业学生设立的一门必修计算机基础课程.以下是由学习啦小编整理关于计算机二级公共基础知识复习试题含答案的内容,希望大家喜欢! 计算机二级公共基础知识复习试题含答案( ...

  9. 基础知识复习,html、css、js

    基础知识复习 HTML 一些标签的复习 一些符号的复习 CSS JS 许久没有写代码了,今年的上半年大部分时间在与模拟电路.数字电路.单片机这些东西打交道,本以此发展为主业,后发现十分痛苦.前两天写了 ...

最新文章

  1. java script w3c study notes
  2. Python 操作 Excel,总有一个模块适合自己
  3. Executors.newFixedThreadPool和ArrayBlockingQueue一点使用心得
  4. 使用ViewPager实现左右循环滑动图片
  5. 大数据资产管理在腾讯游戏的实践
  6. unity 角色换装
  7. 风控做得好,离不开这一项核心能力
  8. python上传文件到windows_python使用win32gui上传文件
  9. swift项目调用OC库 和OC项目 在swift文件里面全局调用OC库
  10. HDU2010 水仙花数【进制+入门】
  11. scala 入门初探
  12. 修复Git打包的一个Bug
  13. 模拟退火算法及MATLAB代码
  14. 乐高叉车wedo教案_乐高 WEDO自带12个活动教学参考书.pdf
  15. Oracle 日历表详解(含节假日)
  16. IJCAI 2021 | 面向睡眠阶段分类的多模态显著性波形检测网络
  17. 5分钟,教你创建在线聊天营销机器人
  18. 2021年中国工业互联网安全大赛
  19. windows下qt程序报错“the inferior stopped because it triggered an exception”
  20. Unity学习之Human fall flat创意工坊地图制作

热门文章

  1. 用python画枫叶-Python中的用for,while循环遍历文件实例
  2. 吸引力法则和《秘密》的理论其实不存在
  3. Web应用多账号系统设计及微信扫码登录实现
  4. 反驳生命的起点是rna_生命起源之谜:RNA世界假说将迎来终结?
  5. python中的format什么意思
  6. 项目03--当当网源码解读
  7. 罗森伯格助力杭州G20峰会保电工程-清江智能化变电站
  8. U3D里Humanoid动画系统问题与解决
  9. MTK平台的LCM防静电(esd-check)机制
  10. 记STM32之PWM学习笔记 ---PWM原理