版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第三章Arduino基本示例传感器感知世界,Arduino让创意动起来《Arduino应用技术(第二版)》·温湿度·红外·液晶·超声波·声音·电机·数码管·键盘·多任务高职电子信息类专业教学用本章学习目标学完本章,你将能利用Arduino驱动传感器与执行器,完成一个个可运行的电子小实验。1掌握温湿度传感器及其使用2掌握人体运动红外传感器及其使用3掌握液晶显示器及其使用4掌握超声波传感器及其使用5掌握声音播放6了解电机驱动与控制7了解数码管驱动与显示8了解矩阵键盘的使用9了解多任务处理方法本章共10节:从温湿度检测、红外感应到液晶显示、超声波测距、声音控制、电机驱动、数码管、矩阵键盘,最后掌握多任务处理技巧。3本章地图:从"感知"到"行动"的十个实验每一节都按"认识模块→连接电路→编写程序→观察现象"四步完成一个小实验3.1温湿度检测DHT11数字
LM35模拟3.2人体红外PIR传感器
继电器输出3.3液晶显示LCD1602
I2C接口3.4超声波测距HC-SR04
声速测距3.5
声音电子琴
音乐播放3.6舵机驱动SG90伺服
角度控制3.7步进电机28BYJ-48
步进控制3.8数码管显示七段码
动态扫描3.9矩阵键盘键值读取
密码锁3.10
多任务millis
中断前五节以"传感器"为主,后五节以"执行器与系统"为主,最终回归多任务处理这一进阶主题。3.1.1DHT11温湿度传感器DHT11是一款具备已校准数字信号输出的温湿度传感器:内部集成电阻式感湿元件+NTC测温元件+高性能8位单片机。校准系数以程序形式存放在OTP内存中,检测信号时自动调用,因此可靠性高、长期稳定。单总线(单线制)串行接口,系统集成简单快捷4针单排引脚封装,体积超小、功耗低性价比极高,是入门温湿度检测的首选注意:避免安装在强风、强光直射或化学气体浓度过高的环境中主要性能指标湿度量程20%~90%RH湿度精度±5%RH温度量程0~50℃温度精度±2℃工作电压3.3V~5.5V工作电流平均约1mA响应时间湿度约25s,温度1~2s3.1.1DHT11电路连接DHT11为4针单排封装:第1脚VCC、第2脚DATA、第3脚悬空、第4脚GND图3-2DHT11与Arduino的连接第1脚接电源,第4脚接地VCC与数据脚间接4.7kΩ~10kΩ上拉电阻,保证空闲时数据线为高电平第2脚(数据)接Arduino的D3可加100nF去耦电容滤除电源噪声小提示:也可直接选购已封装好外围电路(含上拉电阻)的DHT11模块,接线更简单。3.1.1DHT11程序编写DHT11通信协议较复杂,可直接使用网络上成熟的dht库:把库文件放入IDE的libraries目录,再通过#include调用。dht11.ino·温湿度检测#include<dht.h>#defineDHT11_PIN3dhtDHT;voidsetup(){Serial.begin(9600);Serial.println("TherealtimeTemperature");Serial.println("andHumidityis:");}voidloop(){intchk=DHT.read11(DHT11_PIN);//读入数据Serial.print("Humidity:");Serial.print(DHT.humidity,1);Serial.println('%');Serial.print("Temparature");Serial.print(DHT.temperature,1);Serial.println('C');delay(2000);}运行结果(串口监视器)图3-3温湿度程序运行结果上传完成后打开串口监视器,选择正确端口与波特率9600,即可看到每秒刷新的温度与湿度。3.1.2LM35温度传感器图3-4LM35温度传感器(TO-92封装)线性输出:每升高1℃输出电压增加10mV25℃时约250mV,100℃时约1000mV工作电压4~30V;典型精度±0.25℃常用型号与测温范围LM35DH0℃~70℃LM35DZ0℃~100℃LM35CZ-40℃~110℃LM35AH-55℃~150℃一般精度越高,价格也稍高免校准:负载1mA时输出阻抗低至0.1Ω低功耗、自热效应极低(静止时约0.08℃),适合电池供电正负双电源供电可测量负温度3.1.2LM35电路连接与程序图3-5LM35电路连接接线建议:电源两端加0.1μF瓷片电容退耦;信号线尽量短,采用模拟接地,避免与数字地共用。
lm35.ino·串口每1秒刷新一次温度voidsetup(){Serial.begin(9600);}voidloop(){Serial.print((0.488*analogRead(A0)));Serial.println("C");delay(1000);}软件上可用多次取平均等算法,减少数据大幅波动。3.1温湿度传感器实物与原理补充DHT11传感器实物与LM35原理图,完善“认识模块”环节图3-1DHT11温湿度传感器图3-6LM35原理图小结:DHT11输出数字信号(单总线),LM35输出模拟电压(10mV/℃),是数字与模拟温度传感器的典型代表。3.2人体运动红外检测·PIR传感器运动传感器把"人或物体的运动"转化为电信号。按工作方式分为两类:主动式(AIR):主动发射辐射,检测其反射变化。被动式(PIR):不发射辐射,只接收人体体温发出的红外线(约10μm),应用最广泛。图3-7PIR模块工作电压4.5~20V;输出电压高3.3V/低0V;探测角度约120°,探测范围最大7m。工作原理(被动热释电)人体约10μm红外线→菲涅耳透镜增强→聚焦到热释电元件→温度变化使元件电荷失衡→电路检测处理后输出信号。图3-9PIR检测原理图3.2PIR传感器内部结构认识PIR的热电传感器与菲涅耳透镜,了解电路板各功能区图3-8PIR内部结构图3-10PIR电路板结构组成:热电传感器接收人体红外,菲涅耳透镜负责聚焦;电路板带3V稳压器、单次/重复触发选择及两个可调电位器。3.2PIR敏感度与延时调节电路板上的两个电位器分别调节感应距离与高电平保持时间图3-11敏感度调节图3-12延时时间调节调节:敏感度旋钮逆时针/往左增加感应距离(最左可达7m),顺时针/往右减小;延时旋钮决定高电平保持5s~5min。3.2PIR电路连接与继电器图3-14PIR与Arduino硬件电路连接图PIR信号输出端→ArduinoD2继电器信号端→ArduinoD3分别接通电源(VCC)与地线(GND)继电器常开/常闭输出端可连接大电流负载继电器引脚说明地连接0V信号低电平有效,输入低于约2V时继电器开启电源连接5VPIR电路板功能调节(表3-1)延时时间高电平停留5s~5min可调敏感度检测范围3~7m可调数字输出检测到运动输出高电平(3.3V)电源4~20V直流供电3.2继电器结构与连接实物了解继电器引脚(常开/常闭/公共),并查看PIR与Arduino的实物连接图3-13继电器结构示意图图3-15运动传感器与Arduino连接实物图接线:继电器三针接口分别接地、电源与信号(低电平有效),常开/常闭输出端可连接大电流负载。3.2PIR运动检测程序检测到人体运动→LED点亮、继电器动作→延时10s后自动关闭;无人时LED熄灭pir.ino·变量定义与setup()intledPin=13;//LED输出13脚intrelayInput=3;//继电器输出3脚intinputPin=2;//PIR输入2脚intpirState=LOW;//初始未侦测到动作intval=0;//读入引脚状态voidsetup(){pinMode(ledPin,OUTPUT);pinMode(inputPin,INPUT);pinMode(relayInput,OUTPUT);digitalWrite(relayInput,HIGH);Serial.begin(9600);}pir.ino·loop()主循环voidloop(){val=digitalRead(inputPin);if(val==HIGH){//检测到高电平digitalWrite(ledPin,HIGH);if(pirState==LOW){Serial.println("Motiondetected!");pirState=HIGH;digitalWrite(relayInput,LOW);Serial.println("TurnontheLamp!");delay(10000);//等待10sdigitalWrite(relayInput,HIGH);Serial.println("TurnofftheLamp!");}}else{digitalWrite(ledPin,LOW);if(pirState==HIGH){Serial.println("Motionended!");pirState=LOW;}}}要点:pirState用于记录状态变化,只在状态跳变时打印与动作,避免重复触发继电器。3.3液晶显示器(LCD1602)认识LCD1602液晶显示器的外观,2行×16字符点阵图3-16液晶显示器要点:本教材采用带PCF8574TI2C模块的LCD1602,仅用SDA、SCL两条数据线即可驱动,对比度由背面蓝色电位器调节。3.3液晶显示·LCD1602(I2C接口)传统LCD会占满几乎所有I/O口;本教材采用带PCF8574T/PCA8574I2C模块的LCD1602,仅用两条数据线即可驱动。I2C串行总线:SDA数据线+SCL时钟线,需上拉电阻,支持5V/3.3V。对比度由背面蓝色电位器调节;移除背光跳线帽即关背光。ArduinoLCD1602GNDGND5VVCCA4SDAA5SCL表3-2Arduino与LCD的接线注意:LCD1602默认I2C地址通常是0x27,也可能是0x37/0x3E/0x24,使用前需确认。图3-17Arduino与LCD电路连接图只用4根线(GND、VCC、SDA、SCL)即可点亮LCD,为其他外设省下大量I/O口。3.3安装液晶I2C库文件在ArduinoIDE库管理器中搜索并安装LiquidCrystal_I2C库图3-19安装液晶I2C库文件(一)图3-19安装液晶I2C库文件(二)安装:库管理器搜索LiquidCrystal_I2C→选择版本点击“安装”;也可用ZIP方式手动导入库文件夹。3.3寻找I2C地址与安装库i2c_scanner.ino·扫描总线上的设备地址#include<Wire.h>voidsetup(){Wire.begin();Serial.begin(9600);}voidloop(){byteerror,address;Serial.println("Scanning...");for(address=1;address<127;address++){Wire.beginTransmission(address);error=Wire.endTransmission();if(error==0){Serial.print("Foundat0x");if(address<16)Serial.print("0");Serial.println(address,HEX);}}delay(5000);}图3-18寻找I2C液晶地址(串口显示0x27)安装LiquidCrystal_I2C库(三选一)下载ZIP解压到libraries目录项目→加载库→添加.ZIP库…库管理器搜索安装3.3LCD显示程序lcd_display.ino·显示"Hello!world"#include<Wire.h>#include<LiquidCrystal_I2C.h>LiquidCrystal_I2Clcd(0x27,16,2);voidsetup(){lcd.init();//初始化LCD}voidloop(){lcd.setCursor(0,0);//光标第一行lcd.backlight();//打开背光lcd.print("Hello!");lcd.setCursor(0,1);//光标第二行lcd.print("world");}lcd(0x27,16,2)表示地址0x27、16列、2行;setCursor(列,行)定位光标。图3-20LCD实物显示效果拓展:两行文字向左滚动显示chara1[]="Helloall!";chara2[]="WelcometoNJCIT";voidloop(){lcd.setCursor(15,0);for(intp=0;p<26;p++){lcd.scrollDisplayLeft();lcd.print(a1[p]);delay(500);}lcd.clear();lcd.setCursor(15,1);}3.4超声波测距·HC-SR04图3-21超声波传感器HC-SR044引脚:VCC(5V)、GND、Trig(触发)、Echo(回响)工作过程1.Trig引脚触发测距:发送至少10μs高电平2.模块自动发射8个40kHz方波,并检测回波3.检测到回波后,Echo引脚输出高电平,其持续时间即超声波往返时间
图3-22超声波工作原理图3.4HC-SR04电路连接图3-23HC-SR04与Arduino连接图Echo→D2(回响信号输入)Trig→D3(触发信号输出)VCC→5V
GND→GND图3-25串口实时显示测量距离实验过程中通过串口实时查看距离;超出2~400cm量程时显示"Outofrange"。3.4HC-SR04连接实物图超声波模块与Arduino的实际接线效果,以及串口实时显示距离图3-24HC-SR04与Arduino连接实物图图3-27HC-SR04与Arduino显示连接实物图接线:Echo→D2、Trig→D3、VCC→5V、GND→GND;串口每1秒刷新一次距离值。3.4连接Arduino板到电脑用USB数据线将Arduino板连接到电脑,选择端口并下载程序图3-26连接Arduino板到电脑步骤:连接USB→IDE选择开发板Arduino/GenuinoUno→选择对应COM端口→点击上传。3.4超声波测距程序Trig发10μs高电平触发→pulseIn()测得Echo高电平宽度(往返时间)→换算成距离ultrasonic.ino·引脚与setup()#defineechoPin2//回声引脚#definetrigPin3//触发引脚voidsetup(){Serial.begin(9600);pinMode(trigPin,OUTPUT);pinMode(echoPin,INPUT);}ultrasonic.ino·loop()测距与输出voidloop(){floatduration,distance;digitalWrite(trigPin,LOW);delayMicroseconds(2);digitalWrite(trigPin,HIGH);delayMicroseconds(10);digitalWrite(trigPin,LOW);duration=pulseIn(echoPin,HIGH);distance=(duration/2)*0.0344;if(distance>=400||distance<=2){Serial.println("Outofrange");}else{Serial.print("Distance=");Serial.print(distance);Serial.println("cm");}delay(500);}pulseIn(pin,HIGH)返回引脚高电平持续的时间(μs),是测距程序的核心。3.5声音控制·蜂鸣器与简易电子琴有源蜂鸣器内部集成振荡电路,施加直流电压即自动发出固定频率声音,无需外部音频信号。无源蜂鸣器无内置振荡电路,由压电陶瓷片+共鸣腔组成,需外部音频信号驱动,频率决定音高。tone(pin,频率)输出指定频率方波驱动无源蜂鸣器;noTone(pin)停止发声。图3-31蜂鸣器电路(模块,NPN三极管放大)电子琴原理:按下按钮,演奏对应频率的曲调。从中音C、D、E、F开始:C=262HzD=294HzE=330HzF=349Hz用数组存储频率,配合tone()演奏。3.5简易电子琴电路电子琴通过不同按键电阻分压产生不同模拟值,对应不同音阶频率图3-28简易电子琴电路连接实物图图3-29简易电子琴电路原理图原理:按键串联不同电阻分压到A0,程序读取模拟值判断按键,再通过tone()驱动无源蜂鸣器发声。3.5蜂鸣器频率与音阶不同音阶对应不同频率,用tone()输出指定频率方波驱动蜂鸣器图3-30Arduino蜂鸣器频率常用音阶频率对照(单位:Hz)C4=262D4=294E4=330F4=349G4=392A4=440B4=494C5=523D5=587E5=659G5=784C6=1047函数:tone(pin,频率)/noTone(pin)音频=每秒振动次数(Hz)。频率越高音调越高;无源蜂鸣器需外部方波驱动,频率决定音高。3.5.1简易电子琴程序不同按键通过电阻分压产生不同的A0模拟值,程序据此判断按键并演奏对应音阶piano.ino·按A0模拟值演奏C/D/E/Fintnotes[]={262,294,330,349};//演奏的频率voidsetup(){Serial.begin(9600);}voidloop(){intkeyVal=analogRead(A0);//存放A0输入Serial.println(keyVal);if(keyVal==1023){tone(8,notes[0]);//演奏C}elseif(keyVal>=990&&keyVal<=1010){tone(8,notes[1]);//演奏D}elseif(keyVal>=505&&keyVal<=515){tone(8,notes[2]);//演奏E}elseif(keyVal>=5&&keyVal<=10){tone(8,notes[3]);//演奏F}else{noTone(8);//不演奏}}要点:通过analogRead读按键分压值,用if-else判断并调用tone()播放不同频率。3.5.2音乐播放·音律与简谱节拍节拍是音乐中规律性的时间单位,犹如音乐的"心跳"。拍号如2/4拍,表示每小节2个四分音符节拍。音调音调由声音频率决定,全球统一用A~G表示。"1=C"即C调歌曲;标准音A每秒振动441个周期。图3-32《小星星》简谱简谱约定:数字无下划线=四分音符(1拍,500ms);带短横线=二分音符(2拍)。每个音符结束后加20ms无音停顿,增强音乐效果。3.5.2《小星星》播放程序twinkle.ino·三个全局数组inttonelist[]={0,262,294,330,350,393,441,495};intmusiclist[]={0,1,1,5,5,6,6,5,4,4,3,3,2,2,1,5,5,4,4,3,3,2,5,5,4,4,3,3,2,1,1,5,5,6,6,5,4,4,3,3,2,2,1};intrhythmlist[]={0,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2};tonelist音调频率;musiclist简谱音符;rhythmlist音符时长(1=1拍,2=2拍)。twinkle.ino·play()与主程序voidplay(){inti;for(i=0;i<=42;i=i++){tone(8,tonelist[musiclist[i]]);delay(480*rhythmlist[i]);noTone(8);delay(20);}}voidsetup(){pinMode(8,OUTPUT);}voidloop(){play();delay(1000);//播完停1秒}3.6.1舵机的直接控制图3-33伺服电机(SG90)舵机(伺服电机Servo)能精准转动到指定角度,由直流电机、减速机构、传感器与反馈控制电路构成,常用于机器人关节、舵面控制。舵机仅用一个输入引脚接收类似PWM的脉冲信号,脉冲持续时间决定转动角度。基准信号周期20ms(低电平为主)1ms高电平→0°2ms高电平→180°两者之间对应0°~180°的角度图3-34舵机工作原理图舵机保持角度需持续接收脉冲,稳定性受最大扭力限制。3.6.1舵机电路连接与程序图3-35舵机电路连接图红色→5V;黑/棕→GND;橙/黄(控制)→PWM引脚9。抖动时可GND与5V间加470μF以上大电容;大扭矩舵机应外接电源。servo.ino·舵机逐步旋转0°~180°#include<Servo.h>Servomyservo;//舵机对象intpos=0;//位置变量voidsetup(){myservo.attach(9);//接9脚}voidloop(){for(pos=0;pos<=180;pos+=1){myservo.write(pos);delay(15);//等待到位}for(pos=180;pos>=0;pos-=1){myservo.write(pos);delay(15);}}3.6.2舵机的自动控制(电位器)自动控制思路在电路中增加一个10kΩ电位器,转动电位器即可实时改变舵机角度,实现传感器与执行器的结合(自动控制)。map()映射函数map(值,原下限,原上限,新下限,新上限)把模拟量0~1023等比映射为角度0°~180°:val=map(val,0,1023,0,180);servo_pot.ino·电位器控制舵机#include<Servo.h>Servomyservo;//舵机对象intpotpin=0;//电位器接A0intval;voidsetup(){myservo.attach(9);}voidloop(){val=analogRead(potpin);//0~1023val=map(val,0,1023,0,180);myservo.write(val);delay(15);}本质:电位器模拟信号→舵机执行动作,是闭环自动控制的入门。3.7.1步进电机简介(28BYJ-48)图3-38步进电机及其驱动器步进电机依据电磁铁原理,将电脉冲信号转换为角位移:每接收一个脉冲,输出轴转动一个"步距角"。它以分步方式旋转,适合低速高精度定位(如3D打印机、电动移门)。28BYJ-48为4相5线永磁式单极减速步进电机,常配ULN2003驱动器。工作电压5~12V;电流约200mA;减速比1:64步距角5.625°/64;四相绕组A、B、C、DULN2003:达林顿管阵列,耐压50V,单通道输出500mA内轴转一圈需64×64=4096个脉冲(步距角5.625°÷64,减速比1:64),即输出轴每圈4096步。3.7.1通电方式与电路连接图3-39电机与ULN2003连接图28BYJ-48与ULN2003模块防反插直连;IN1~IN4接数字脚8、9、10、11;改变脉冲顺序即可改变转动方向。三种通电方式单四拍:A→B→C→D→A双四拍:AB→BC→CD→DA八拍:A→AB→B→BC→C→CD→D→DA图3-41单极四相步进电机通电方式“单/双”指同时通电绕组数;“拍”指完成一次通电循环的步数。八拍同一步数下仅转半圈。3.7.1步进电机直接驱动(单四拍)用switch-case按单四拍顺序给四相绕组通电,配合micros()定时每1ms走一步stepper_direct.ino·主循环#defineIN18#defineIN29#defineIN310#defineIN411intSteps=0;//当前步boolDirection=true;//方向unsignedlonglast_time=0;intsteps_left=4095;//总步数voidsetup(){pinMode(IN1,OUTPUT);pinMode(IN2,OUTPUT);pinMode(IN3,OUTPUT);pinMode(IN4,OUTPUT);}voidloop(){while(steps_left>0){if(micros()-last_time>=1000){stepper(1);//每1ms走一步last_time=micros();steps_left--;}}Direction=!Direction;//换向steps_left=4095;}stepper_direct.ino·通电与方向voidstepper(intxw){//单四拍for(intx=0;x<xw;x++){switch(Steps){case0://A相通电digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW);digitalWrite(IN3,LOW);digitalWrite(IN4,LOW);break;case1://B相通电digitalWrite(IN1,LOW);digitalWrite(IN2,HIGH);digitalWrite(IN3,LOW);digitalWrite(IN4,LOW);break;case2://C相通电digitalWrite(IN1,LOW);digitalWrite(IN2,LOW);digitalWrite(IN3,HIGH);digitalWrite(IN4,LOW);break;case3://D相通电digitalWrite(IN1,LOW);digitalWrite(IN2,LOW);digitalWrite(IN3,LOW);digitalWrite(IN4,HIGH);break;}SetDirection();}}voidSetDirection(){if(Direction)Steps++;elseSteps--;if(Steps>3)Steps=0;if(Steps<0)Steps=3;}3.7.2步进电机库函数驱动(Stepper)ArduinoIDE内置Stepper库(项目→导入库→Stepper),仅需3个函数Stepper(steps,pin1,pin2,pin3,pin4):创建电机对象,steps为每圈步数。例:Stepperstepper(4096,8,9,10,11);setSpeed(rpm):设置转速(转/分钟),仅设速不控步数。例:stepper.setSpeed(60);step(steps):按指定步数旋转,正数正向、负数反向。例:stepper.step(100);stepper_lib.ino·正反各一圈#include<Stepper.h>constintstepsPerRevolution=4096;SteppermyStepper(stepsPerRevolution,8,9,10,11);voidsetup(){myStepper.setSpeed(60);//60rpmSerial.begin(9600);}voidloop(){Serial.println("正向旋转");myStepper.step(stepsPerRevolution);delay(1000);Serial.println("反向旋转");myStepper.step(-stepsPerRevolution);delay(1000);}3.8.1单位数码管的驱动共阴极(CC)COM接负极,点亮段时对应引脚施加高电平,熄灭施加低电平。共阳极(CA)COM接正极,点亮段时对应引脚施加低电平,熄灭施加高电平。两种类型不可直接互换。段码duanma[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f},对应0~9(共阴,顺序dpgfedcba)。表3-3数码管接线表数码管ArduinoA4B5C6D7E8F9G10DP11ComGNDA~G各接220Ω限流电阻;COM接GND(共阴)。3.8.1单位数码管驱动程序用duanma段码数组配合bitRead()逐位驱动8个引脚,循环显示0~97seg.ino·段码与初始化constunsignedcharduanma[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0~9段码intLEDPins[]={4,5,6,7,8,9,10,11};intLEDCount=8;voidsetup(){for(intthisLED=0;thisLED<LEDCount;thisLED++)pinMode(LEDPins[thisLED],OUTPUT);}7seg.ino·驱动与主循环voiddeal(unsignedcharvalue){for(inti=0;i<8;i++)digitalWrite(LEDPins[i],bitRead(value,i));}voidloop(){for(inti=0;i<10;i++){deal(duanma[i]);delay(1000);}}bitRead(x,n):读取数字x的第n位(位序从右至左计,0起始)。deal()把段码逐位写到8个引脚上。3.8.24位七段数码管与动态扫描多路复用结构4位数码管共享段码A~G,每位有独立公共阳极(位码)。仅需12个引脚(8段+4位),替代独立显示所需的32个引脚。动态扫描与视觉暂留依次显示每一位并快速切换(约1ms)。因视觉暂留,人眼看到4位同时显示。例:显示"1234"时分时逐位点亮1、2、3、4。表3-44位数码管与Arduino连接段引脚位引脚A2D113B3D212C4D311D5D410E6——F7——G8——DP9——用四位数码管制作秒表,段码引脚2~9,位码引脚10~13(共阳)。核心思想:位选+段选分时切换,利用视觉暂留实现多位数显示。3.8.24位数码管秒表程序位选+段选动态扫描,millis()定时每秒计数一次并刷新显示stopwatch.ino·变量与缓冲intledCount=8;//段数intsegCount=4;//位数constunsignedcharduanma[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};intledPins[]={2,3,4,5,6,7,8,9};intsegPins[]={13,12,11,10};unsignedchardisplayTemp[4];//缓冲voidsetup(){for(inti=0;i<ledCount;i++)pinMode(ledPins[i],OUTPUT);for(inti=0;i<segCount;i++)pinMode(segPins[i],OUTPUT);}voiddeal(unsignedcharvalue){for(inti=0;i<8;i++)digitalWrite(ledPins[i],bitRead(value,i));}voidupdateDisplayBuffer(unsignedintnum){displayTemp[0]=duanma[num/1000];displayTemp[1]=duanma[(num%1000)/100];displayTemp[2]=duanma[(num%100)/10];displayTemp[3]=duanma[num%10];}stopwatch.ino·扫描与主循环voiddisplayDigits(){//动态扫描staticinti=0;deal(0);//清屏防鬼影for(inta=0;a<segCount;a++)digitalWrite(segPins[a],1);//关位digitalWrite(segPins[i],0);//选位deal(displayTemp[i]);//送段i++;if(i==segCount)i=0;}voidloop(){staticunsignedintnum=3467;staticunsignedlonglastTime=0;if(millis()-lastTime>=1000){lastTime=millis();num++;//每秒加1}updateDisplayBuffer(num);displayDigits();//持续刷新}3.9.1矩阵键盘简介与接线4×4矩阵键盘共16个按键,由4行×4列组合构成。每个按键一端接某行、另一端接某列,常用于输入密码、导航菜单、控制机器人。扫描原理单片机采用行扫描法或列扫描法检测按键:逐行输出低电平、读列电平,即可定位被按下的键位。相比直连,用8个引脚即可读16个键。表3-5电路连接表键盘引脚Arduino方向1/2/3/4D9/D8/D7/D6行5/6/7/8D5/D4/D3/D2列按下按键后,其值立即显示在串行监视器上。键面布局:123A/456B/789C/*0#D3.9.1键值读取程序(Keypad库)使用Keypad库:定义键位映射、行列引脚,getKey()读取按键并在串口显示keypad.ino·键位与引脚#include<Keypad.h>constbyteROWS=4;constbyteCOLS=4;charhexaKeys[ROWS][COLS]={{'1','2','3','A'},{'4','5','6','B'},{'7','8','9','C'},{'*','0','#','D'}};byterowPins[ROWS]={9,8,7,6};bytecolPins[COLS]={5,4,3,2};keypad.ino·读取与显示KeypadcustomKeypad=Keypad(makeKeymap(hexaKeys),rowPins,colPins,ROWS,COLS);voidsetup(){Serial.begin(9600);}voidloop(){charcustomKey=customKeypad.getKey();if(customKey){Serial.println(customKey);}}Keypad库通过"项目→导入库→管理库"安装加载。getKey()返回空表示无按键。3.9.2密码锁系统构成输入部件=矩阵键盘;输出部件=继电器控制的锁体。密码正确时改变继电器状态。工作流程①键盘输入密码存入Data[]②输入满7位后strcmp比较③正确→继电器开5s,LCD显示Correct④错误→显示Incorrect,清除重输password_lock.ino·核心逻辑charMaster[]="123A456";//密码intsignalPin=12;//继电器LiquidCrystal_I2Clcd(0x27,16,2);voidsetup(){lcd.init();lcd.backlight();pinMode(signalPin,OUTPUT);}voidloop(){lcd.print("EnterPassword:");customKey=customKeypad.getKey();if(customKey){Data[data_count]=customKey;lcd.setCursor(data_count,1);lcd.print(Data[data_count]);data_count++;}if(data_count==Password_Length-1){if(!strcmp(Data,Master)){lcd.print("Correct");digitalWrite(signalPin,HIGH);delay(5000);digitalWrite(signalPin,LOW);}else{lcd.print("Incorrect");delay(1000);}lcd.clear();clearData();}}strcmp(Data,Master)相等返回0,即密码匹配。3.10.1多任务处理简介单核与顺序执行ArduinoUNO采用ATmega328P,仅一个CPU核心,同一时刻只能执行一个任务;通常无操作系统,按预设流程顺序执行。问题根源:delay()阻塞延时期间CPU空转等待,任务响应不及时。流水灯+火焰报警并行时,可能错过持续时间很短的火焰信号。时间片轮转(OS)操作系统把CPU时间划分成时间片,按FIFO依次分配给任务,每个任务运行一个时间片后暂停换下一个。时间片极短,宏观上看似并行。本书的三种处理方法①millis()非阻塞延时②外部中断(硬件触发)③定时器中断(MsTimer2)多任务的核心矛盾:如何在不阻塞主循环的前提下,让多个任务都能及时得到执行。3.10.2millis()非阻塞延时millis()返回自系统上电以来的毫秒数(无符号长整型)。与delay()不同,它不暂停程序,可在"延时"期间继续执行其他任务。实现思路设定时间间隔interval,记录上次执行时间;循环判断当前时间−上次时间是否达到间隔,达到则执行该任务,否则继续做其他事。注意:millis()精度不足以做时钟;信号持续时间过短(低于毫秒级)时,应采用中断方式。millis_blink.ino·非阻塞LED闪烁unsignedlongpreviousMillis=0;constlonginterval=1000;voidsetup(){pinMode(LED_BUILTIN,OUTPUT);}voidloop(){unsignedlongcurrentMillis=millis();if(currentMillis-previousMillis>=interval){previousMillis=currentMillis;digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));}//在这里执行其他任务,不被阻塞}3.10.3外部中断的应用硬件中断机制:当中断条件满足(引脚电平变化)时,硬件暂停当前程序,转去执行中断服务函数,完成后返回主程序。即便loop()中没有火焰检测代码,系统也能及时检测并报警。ext_interrupt.ino·关键代码voidexInterrupt(){//ISRSerial.println("FireAlarm!");}voidsetup(){...attachInterrupt(digitalPinToInterrupt(2),exInterrupt,RISING);}使用中断的五个要点①ISR是无返回值、无参数的函数②避免在ISR中用delay(),执行时间尽量短③中断期间millis()不再增长,影响高精度计时④不要在中断时用串口接收数据,可能丢失⑤中断与主循环共享变量需加volatile关键字3.10.4定时器中断(MsTimer2)MsTimer2库配置UNO硬件定时器Timer2(8位),生成周期性中断。通过"项目→加载库→管理库"搜索MsTimer2安装。set(ms,ISR):设置中断间隔与中断服务函数start():启动定时器中断stop():终止定时器中断注意:MsTimer2占用D3、D11引脚,使用后这两个引脚不能再用于PWM输出,但仍可作数字引脚。ms_timer.ino·LED每500ms翻转#include<MsTimer2.h>voidflash(){//中断服务程序staticboolstate=0;state=!state;digitalWrite(13,state);}voidsetup(){pinMode(13,OUTPUT);MsTimer2::set(500,flash);MsTimer2::start();}voidloop(){//主程序继续执行其他任务}定时器中断每隔500ms调用flash(),流水灯任务无需写在loop中。第三章本章小结3.1温湿度:DHT11数字单总线;LM35模拟量T=0.488×val3.2PIR红外:菲涅耳透镜探测人体,pirState状态机,继电器输出3.3LCD1602I2C:A4→SDA、A5→SCL,扫描地址0x27,LiquidCrystal_I2C库3.4超声波:Trig/Echo,distance=(duration/2)×0.0344,pulseIn测量3.5声音:tone()/noTone(),数组存音符,电子琴与音乐播放3.6舵机:Servo库,脉冲1ms→0°、2ms→180°,逐步旋转3.7步进电机:28BYJ-48+ULN2003,4096步/圈,Stepper库3.8数码管:段码+位码,bitRead驱动,动态扫描利用视觉暂留3.9矩阵键盘:Keypad库读键,密码锁用继电器+LCD验证3.10多任务:millis()非阻塞、外部中断、定时器中断MsTimer2第四章Arduino通信让Arduino与外界对话:串口·SPI·IIC·以太网·蓝牙《Arduino应用技术(第二版)》·串口通信·SD卡读写·实时时钟·以太网·蓝牙高职电子信息类专业教学用本章学习目标学完本章,你将掌握Arduino与外界的多种通信方式,为物联网应用打下基础。1掌握串口通信与远程控制2了解SPI通信与SD卡读写3了解IIC通信与实时时钟4了解以太网通信5了解蓝牙通信通信是物联网应用的核心基础。本章以"串口通信"为重点展开,串口、SPI、IIC、以太网、蓝牙五种方式将在后续项目实战章节中被综合运用。说明:4.4以太网与4.5蓝牙正文在提供的教材文本中未完整收录,本PPT以现有内容为主,并补充了要点页。4本章地图:五种通信方式每种通信方式都按"认识接口→连接电路→编写程序→观察现象"四步完成4.1串口通信Serial.available
Serial.read
远程灯控
双板通信4.2SPI/SD卡MOSI/MISO
SCK/SS
SD卡读写4.3IIC时钟DS1302
DS1307
实时时钟LCD4.4以太网W5100扩展板
Ethernet库
TCP/IP协议4.5蓝牙HC-05模块
手机APP控制串口是"点对点"的调试与控制的起点;SPI快而简单、IIC省引脚,两者适合连接外设;以太网与蓝牙则让Arduino走向真正的物联网。4.1串口通信与远程控制Arduino与计算机之间通信时,最常用的方式就是串口通信。在2.2.5节中已经介绍过串口监视器以及常用串口函数(方法),如Serial.begin()、Serial.print()和Serial.println()等。本节进一步探讨读取串口缓冲区中已接收数据的操作方法,实现Arduino与计算机之间的双向通信。缓冲区:Arduino会在SRAM中分配一段大小为64B的接收存储空间,串口接收到的数据会暂时存放在这里。串口通信的典型流程①Serial.begin(9600)初始化并设定波特率②Serial.available()查询缓冲区是否有数据③Serial.read()读取缓冲区中的字节④Serial.print()将结果回传给计算机波特率:串口每秒传输的比特数,常用9600、115200。4.1.1串口读取函数Serial.available()检测串口接收缓冲区的状态,返回已接收并存储(容量64B)中的可读字节数。通常与判断结合使用:Serial.available()>0表示已有数据可读。Serial.read()返回串口缓存中的第一个可读字节(整型),无数据则返回-1。读取后自动清除缓冲区中已读数据;若只想"看一眼"而不删除,可用Serial.peek()。协同运作:两个函数通常成对出现——先判断available()是否有数据,再用read()逐字读取,直到返回0。典型应用while(Serial.available()>0){data=Serial.read();Serial.print(data);delay(5);}功能:循环读取串口数据并赋值给data,直至缓冲区清空。4.1.2串口接收回显程序当串口收到数据时,逐字节读取并回显到串口监视器Serial回显·串口接收示例intincomingByte=0;//传入的串行数据voidsetup(){Serial.begin(9600);//打开串口,波特率9600}voidloop(){//只有接收到数据时才发送if(Serial.available()>0){incomingByte=Serial.read();//读取字节Serial.print("Ireceived:");//显示得到的数据Serial.println(incomingByte,DEC);}}运行结果(图4-1)Serial.println(incomingByte,DEC):以十进制输出读到的字节数值(50对应字符'2')。4.1.2串口通信实现灯控电脑端在串口监视器发送字符'a'点亮LED并输出"turnon";发送'b'熄灭LED并输出"turnoff";其他字符LED状态不变。串口灯控·Serial控制LEDvoidsetup(){Serial.begin(9600);pinMode(13,OUTPUT);}voidloop(){if(Serial.available()>0){charch=Serial.read();Serial.print(ch);if(ch=='a'){//开灯digitalWrite(13,HIGH);Serial.println("turnon");}elseif(ch=='b'){//关灯digitalWrite(13,LOW);Serial.println("turnoff");}}}Serial.read()读到的字符与'a'/'b'比较digitalWrite(13,HIGH/LOW)控制板载LED串口输出同步提示灯的状态这就是"远程控制"的雏形:数据从电脑经串口到达Arduino,程序根据指令作出响应。再结合继电器即可控制大功率负载。4.1.2双Arduino串口通信用另一块Arduino代替电脑发送字符'a'/'b'。发送端引脚2、3各接一个按钮;发送端TX(引脚1)→接收端RX(引脚0),发送端RX(引脚0)→接收端TX(引脚1);两块板GND必须相连。发送端·按钮触发Serial.writeconstintbuttonPin1=2;constintbuttonPin2=3;voidsetup(){Serial.begin(9600);pinMode(buttonPin1,INPUT_PULLUP);pinMode(buttonPin2,INPUT_PULLUP);}voidloop(){if(digitalRead(buttonPin1)==LOW){delay(20);//去抖动if(digitalRead(buttonPin1)==LOW){Serial.write('a');//发送字符awhile(digitalRead(buttonPin1)==LOW);}}//buttonPin2同理,发送字符'b'}要点:按钮按下为低电平触发;delay(20)消抖;Serial.write('a')发送单个字符;while等待按钮释放,防止重复发送。注意:TX与RX交叉连接一方的TX(发送)必须接到另一方的RX(接收),两者交叉;GND必须共地。接收端配合灯控程序即可远程开灯。4.1拓展:软件串口SoftwareSerial有时需要用到多个串口通信,这时可以使用软件串口SoftwareSerial库:把Arduino的任意数字引脚模拟为串口。SoftwareSerial基本用法#include<SoftwareSerial.h>SoftwareSerialmySerial(10,11);//RX接10,TX接11voidsetup(){Serial.begin(9600);//硬件串口mySerial.begin(4800);//软件串口}voidloop(){if(mySerial.available()){Serial.write(mySerial.read());}}使用说明通过SoftwareSerial(rxPin,txPin)创建软串口对象可同时挂接多个软串口,突破硬件串口数量限制软串口波特率不宜过高,且与中断存在相互影响典型应用:连接蓝牙模块、GPS模块等串口外设4.2.1SPI通信SPI(SerialPeripheralInterface,串行外设接口)是一种同步串行通信协议,常用于微控制器与传感器、存储器、显示屏等外设之间的数据传输。MOSI主出从入,主设备向从设备发送数据。MISO主入从出,从设备向主设备发送数据。SCK串行时钟,由主设备提供,同步数据传输。SS/CS从设备选择,低电平选中。SPI系统中可以有多个从机,但仅允许一个主机。主机通过从机选择线(SS)识别并确定当前通信的从机。SS引脚也称CS(ChipSelect,芯片选择引脚),两者是同一概念。ArduinoUNO的SPI引脚SS→引脚10MOSI→引脚11MISO→引脚12SCK→引脚134.2.1SD卡与SD扩展板若需处理或存储大量数据,Arduino内置的EEPROM和Flash存储空间不足时,可外接SD卡扩充存储容量。SD卡基于半导体快闪记忆技术,广泛应用于数码相机、手机、平板等设备。除SD卡外,还需准备SD扩展板与电脑端的SD读卡器;部分设备用全尺寸SD卡,部分用MicroSD卡(TF卡)。图4-3SD卡(microSD+适配器)图4-4SD扩展板MicroSD卡小巧,可装入转SD适配器后使用;扩展板提供卡座与电平转换,直接插到Arduino上。4.2.2SD类库函数SD类库成员函数提供访问SD卡、操作文件与文件夹、进行文件读写的功能函数功能说明SD.begin([cspin])初始化SD卡库与SD卡,成功返回true;无参时默认使用SS引脚。SD.open(fn,[mode])打开文件,可创建新文件;FILE_READ只读、FILE_WRITE写入。file.available()检查文件中可读数据的字节数,返回可用字节数。file.close()关闭文件,并确保数据已被完整写入SD卡。file.print(d,[BASE])将数据写入文件;BASE可为BIN/OCT/DEC/HEX。file.println(d,[BASE])写入数据并自动添加回车换行。file.read()读取文件中一个字节(1B),无数据返回-1。file.write(d)/(buf,len)将数据写入文件,返回已发送的字节数。4.2.3SD卡的电路连接表4-1SD卡扩展板与ArduinoUNO的连接SD扩展板ArduinoUNOGNDGNDVCC3.3VCS数字10号引脚MOSI(DI)数字11号引脚MISO(DO)数字12号引脚SCK(clk)数字13号引脚SD卡扩展板直接叠插在Arduino上,六个信号与电源引脚一一对应,无需额外接线。注意:SD卡的供电电压是3.3V,ArduinoUNO板上已配备相应电压的引脚(3.3V)。切勿将VCC接到5V,以免损坏SD卡。4.2.3SD读写程序(一):初始化与写入SD写入·test.txt(FILE_WRITE)#include<SPI.h>#include<SD.h>FilemyFile;constintss_pin=10;//CS接引脚10voidsetup(){Serial.begin(9600);Serial.print("InitializingSDcard...");if(!SD.begin(ss_pin)){//初始化失败则停止Serial.println("initializationfailed!");return;}Serial.println("initializationdone.");//打开文件(不存在则创建),写入一行数据myFile=SD.open("test.txt",FILE_WRITE);if(myFile){Serial.print("Writingtotest.txt...");myFile.println("testing1,2,3.");myFile.close();//关闭文件,确保写入Serial.println("done.");}else{Serial.println("erroropeningtest.txt");}}voidloop(){}关键点SD.begin(10)初始化,失败则returnSD.open以FILE_WRITE方式打开(可自动建文件)myFile.println写入一行,close确保数据落卡SPI的SS引脚须设为输出模式,否则SD卡库无法正常工作;SD.open的路径用"/"分隔。4.2.3SD读写程序(二):读取与回显写入完成后,再以只读方式打开test.txt,逐字节读取并输出到串口监视器SD读取·test.txt(只读)myFile=SD.open("test.txt");//只读方式打开if(myFile){Serial.println("test.txt:");while(myFile.available()){//有数据则读Serial.write(myFile.read());//逐字节读取并回显}myFile.close();}else{Serial.println("erroropeningtest.txt");}//以上代码位于setup()中,位于写入之后读取逻辑:available()返回可读字节数,配合read()在while循环中逐个读出,再用Serial.write直接输出到串口。拓展思考:结合3.1节的DHT11,把温湿度数据按固定周期写入SD卡形成数据日志,实现"记录仪"功能。4.3IIC通信与实时时钟实时时钟,亦称RTC时钟。目前流行的时钟电路模块有DS1302、DS1307等,接口简洁、价格经济、操作便捷,应用广泛。DS1302三线串行通信
涓流充电·可编程充电DS1307IIC总线接口
56B非易失RAMIIC总线(I2C):仅需SDA(数据)和SCL(时钟)两根线即可挂接多个设备,通过不同的设备地址区分。ArduinoUNO的IIC引脚:A4=SDA,A5=SCL。与带IIC接口的LCD1602液晶接线方式相同。本节目标:用DS1302/DS1307搭建实时时钟显示电路,在LCD1602上显示当前日期与时间。4.3.1DS1302实时时钟模块DS1302由美国DALLAS公司设计,是一款具备涓细电流充电能力的低功耗、高性能实时时钟(RTC)芯片,广泛用于需精确时间记录的电子设备。主要特点三线串行数据传输方式为掉电保护电源提供可编程充电,可关闭充电功能普通32.768kHz晶振,精确计时年、月、日、周、时、分、秒支持12/24小时制,闰年自动调整图4-5DS1302模块(含晶振与纽扣电池)模块引脚:除电源(VCC、GND)外,还有RST(复位)、I/O(数据)、CLK(时钟)。4.3.1DS1302库函数在编写程序之前,先认识DS1302所用到的主要库函数库函数功能说明DS1302rtc(RST,SDA,SCL)创建DS1302对象,指定RST/I/O/CLK连接引脚。rtc.init()初始化模块,配置引脚并检查DS1302是否响应。rtc.halt(value)false
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高性能运动织物及服饰项目可行性研究报告模板-立项备案
- 2026年人教版小学英语三年级上册第11单元同步练习题
- 2025-2026年心理测评与评估实践测试题
- 2026年重庆市苏教版高中数学必修第五册第7章同步练习题
- 2025-2026年四川省人教版高中语文必修第三册同步练习题
- 2025-2026年部编版高中英语完形填空专项训练习题
- 2026年海南省北师大版八年级物理下册力学专项测试卷
- 2025-2026年高中语文古诗词阅读理解能力测试卷
- 2025-2026年部编版六年级数学下册第11单元数的认识测试卷
- 2025-2026年浙江省人教版八年级化学下册第2单元测试卷
- GB/T 31880-2026检验检测机构诚信基本要求
- 2026秋新教材人教版五年级上册数学《观察简单组合体》教学设计(3课时)
- 1.4 人口普查 课件(共25张) 北师大版数学四年级上册
- 妊娠期妇女心肺复苏急救指南(2025版)中文版+围产期急救操作规范
- 精益基础考试题及答案
- 2026年四川省成都市中考语文真题(试题+答案)
- 2025中国联通广东省分公司校园招聘(174个岗位)笔试历年参考题库附带答案详解
- 2026年国家电网职称考试(工业工程技术-营销工程)(副高)经典试题及答案
- 2026科特迪瓦能源行业的现状贸易分析及投资策略配置布局研究方案
- 2026年幼儿园教职工安全
- 2026年秋初中开学典礼教务主任发言稿
评论
0/150
提交评论