找回密码
 立即注册
首页 业界区 安全 嵌入式 Arduino 期末复习

嵌入式 Arduino 期末复习

扈季雅 昨天 09:36
1 基础知识

1.1 概述

对嵌入式的定义


  • 国内定义:以应用为中心,以计算机技术为基础,软件硬件可裁剪,且适应系统对功能,可靠性,成本,体积,功耗严格要求的专用计算机系统。
  • IEEE定义:用于控制,监视或者辅助操作机器和设备的装置。
分类

以下按照形态差异分类:
类名板型号芯片级MCU,SoC板级单片机,模块设备级工控机其中,单片机又分为:

  • 不含操作系统(我们学习的arduino不包含操作系统)
  • 含操作系统
组成

嵌入式系统四大组成部分

  • 微处理器
    核心部件,微处理器强弱直接影响嵌入式设备的复杂度和范围。
  • 存储器
    对速度和功耗要求高
  • 输入/输出设备(I/O)
    ①人机交互②传感器设备③输入设备
  • 通信和扩展接口
    嵌入式系统与其他系统进行数据交换和扩展。
1.2 常用元件

名称相关单位作用分类电阻器(Resistor)欧姆 Ω(R) /误差/额定功率等 欧姆定律:I=U/R限流,分压电路可调电阻器,热敏电阻器,光敏电阻器,压敏电阻器电容器(Capacitor)法拉 F(C) (电荷量和电压比值)储能元件,充放电特性和阻止直流电流,允许交流电滤波电容器,积分电容器,微分电容器电感器(Inductor)亨利 H(L)\(X_L(感抗)=2\pi f(交流电频率)L\)对突变电流有阻碍作用 。滤波,震荡,延迟,筛选信号,过滤噪声,稳定电流,抑制电磁波干扰二极管(Diode)1V 10mA 标记为D①正向导通,逆向截止 ②整流,稳压,恒流,开关,发光,光电转换等电路中发光二极管(LED):长脚阴极短脚阳极。一般工作电压在1V,导电电流在10mA,所以需要一个电阻分压限流\(R=(E-U_E)/I_F\)(半导体)晶体管标记为Q把微弱的电信号放大成幅度值较大的电信号(用作无触点开关)①NPN型:基极B和发射极E之间施加正向电压,发射极和集电极导通②PNP型:基级和发射极施加反向电压,晶体管导通万用表V,A,Ω,β(半导体参数),F测量直流电流,电压,交流电流,电压,电阻,还可以测量电容量,电感量,半导体参数数字万用表分为四个测量插孔和红黑表笔各一个杜邦线null扩展实验板引脚,增加实验项目,无焊接进行电路实验杜邦线有两头,有插针插孔两类,可以两头都是,也可一个一半面包板null电路的组装,调试和训练一般五个一组,分配在同一金属片中Arduino扩展板null简化电路搭建过程,快速搭建项目多种,不列举模块null无需了解模块原理,只需按照要求连接,即可快速制作硬件对于一些简单的模块只有三个信号线:①V/VCC电源②G/GND地线③S信号引脚。例如UART蓝牙模块等2  Arduino软硬件开发基础

2.1 开发板

2.1.1 Arduino UNO简介

如图所示为一个Arduino UNO板
1.jpeg

拥有:

  • 14个输入输出引脚(0~13),其中(3,5,6,9,10,11)可以作为PWM输出
  • 6个模拟输入(A0~A5)
  • 1个UART硬件串口
  • 1个电源插孔,1个ICSP插座和1个复位按钮
  • 1个USB接口,与计算机连接,可以供电和通信
引脚名称和功能

电源引脚

2.jpeg

名称作用VIN①外部电流供电时的输入电压引脚 ②电源插座供电时提供5V电压5V输出5V电压 使用该引脚和3.3V引脚可能损坏旁路线性稳压器3V输出3.3V电压GND接地AREF模拟输入的参考电压RESET扩展一个按钮实现复位功能。引脚为低电平输入输出

3.jpeg

名称引脚位作用串口0(RX),1(TX)接收(RX)和发送(TX)TTL串行数据。外部中断2,3触发中断的引脚。触发条件分为:①低电平触发 ②上升沿触发 ③下降沿触发 ④发生变化触发PWM3,5,6,9,10,11(~线)6路八位PWMSPI10(SS),11(MOSI),12(MISO),13(SCK)支持SPI通信LED13高电平LED亮,低电平LED灭TWIA4/SDA,A5/SCLTWI通信3 Arduino编程

3.1 函数

时间函数

函数参数用法备注delay(ms)ms为unsigned long延长ms毫秒delay更多用于较短延时,但是有以下缺点:①延时中无法读取传感器的值等,阻止了大部分操作delayMicroseconds(μs)μs为 unsigned int延长微秒更长时间用delaymicros()time=micros()返回以微秒为单位的运行时间(unsigned long)计时周期为70min,对于UNO(晶体振荡器为16MHz),返回值为4μs的倍数millis()time=millis()返回毫秒运行时间(unsigned long)计时周期为50天数学函数

函数参数用法abs(x)x为int家族绝对值constrain(x,a,b)x归一化数据,a下限,b上限 任意数据类型对于x,小于a返回a,小于b返回b ,中间返回xmap(x,fromLow,fromHigh,toLow,toHigh)只能用于整数 (映射数,现在下限,现在上限,映射后下限,映射后上限)将整数从一个范围映射到另外一个范围,与上着规则基本一致max(x,y)任意类型返回两个数较大者(可用作限制下限)min(x,y)同上返回最小(控制上限)pow(base,exponent)float幂的运算sqrt(X)任意求平方根sq()任意实数求平方cos/sin/tan()弧度角角余弦值/正弦值/正切字符函数

十三个,较简单,看懂英语也能知其用法:

  • isAlpha 是否为字母
  • isAlphaNumeric 是否为字母或数字
  • isAscii 是否为ASCII码
  • isControl 是否为控制符
  • isDigit 是否为数字
  • isGraph 一个非空字符是否可输出/可打印
  • isHexadecimalDigit 是否为16进制数
  • isLowerCase 是否为小写字母
  • isPrintable 任意字符是否可输出打印
  • isPunct 是否为标点符号
  • isSpace 是否为空格符
  • isUpperCase 是否大写
  • isWhitespace 是否为" ","\f","\n","\r","\t","\v"的任意一种
以上都是若条件成立返回真否则为假
随机函数

random(min,max)


  • min 下限
  • max 可选 上限
返回[min,max-1]之间的随机数(long)
每次执行程序结果相同,如需不同需要以下方法
randomSeed(seed)


  • seed 种子值
这两者都是伪随机,可以逆向分析
位和字节函数

函数参数作用bit(n)n为指定位返回位的权值(bit 0是1,1是2,2是4)bitClear(x,n)x 数字变量,n 要读取的位返回指定位的值bitSet(x,n)x 数字变量 n 指定置1的位某一位置0bitRead(x,n)x 变量 n 指定读取位读取指定位的值bitWrite(x,n,b)x 变量 ,n 要赋值的位,b要赋的值给变量指定位赋值highByte/lowByte(x)x变量提取一个字高字节/低字节3.2 常量表示

进制前缀


  • 十进制:无
  • 二进制 前缀B
  • 八进制 前缀 0
  • 十六进制 前缀0x
3.3 程序结构

一个Arduino程序分为两个函数

  • setup()
    程序开始运行时调用该函数,可用于变量初始化等等,只会运行一次
  • loop()
    执行完setup会执行看、loop,loop语句始终按照顺序循环执行。
3.4 位运算


  • &按位与
  1. 0 0 1 1
  2. 0 1 0 1
  3. --------&
  4. 0 0 0 1
复制代码

  • |按位或
  1. 0 0 1 1
  2. 0 1 0 1
  3. ---------|
  4. 0 1 1 1
复制代码

  • ~ 按位取反
  • ^按位异或
  1. 0 0 1 1
  2. 0 1 0 1
  3. ---------^
  4. 0 1 1 0
复制代码

  • >右移
4 第四章

4.1 数字接口


  • 数字引脚
  • 模拟引脚
  • 通信引脚
  • 外部中断引脚
  • 电源引脚
  • 。。。
I/O接口封装函数

基本封装函数有三个
函数参数作用digitalRead(pin)读取的引脚编号pin读取引脚状态digitalWrite(pin,value)pin同上,value:HIGH/LOW(高引脚低引脚)HIGH为5Vor3.3V,LOW为0V 设置引脚的高低电平pinMode(pin,mode)mode有INPUT,OUTPUT,INPUT_PULLUP指定引脚输出模式

  • 设置引脚 为输出(OUTPUT)模式,此时引脚为低阻抗状态,可以向其他电路原件提供电流(通常为40mA以内)
  • 设置引脚为输入(INPUT)模式,,此时引脚为高阻抗状态,此时该引脚可用于读取信号。
  • 设置引脚为输入上拉(INPUT_PULLUP)模式.首先Arduino内部自带上拉电阻。当我们需要使用该内部上拉电阻,可以通过pinMode()将引脚设置为输入上拉(INPUT_PULLUP)模式。当你将一个引脚设置为INPUT_PULLUP模式时,如果没有输入信号,这个引脚的状态将会是HIGH(高电平)。只有当这个引脚被接地(即连接到GND)时,它的状态才会变为LOW(低电平)。这种模式通常用于接按钮或开关。例如,你可以将一个按钮的一端接到interruptPin,另一端接到GND。当按钮没有被按下时,interruptPin的状态是HIGH。当按钮被按下时,interruptPin会被接地,因此它的状态变为LOW。使用内部上拉电阻的好处是,你不需要在你的电路中添加额外的上拉电阻。这可以简化你的电路设计,并减少硬件成本。
4.2 模拟接口的应用

在Arduino中有A0~A5,6个模拟接口,可以通过A/D转换器(10个),将0V~5V的电压转换为0~1023的值。
在板子上有~的接口,可以实现D/A转换。
模拟接口三个封装函数

函数参数作用analogRead(pin)0~5的接口模拟读,返回一个转换值(0~1023)analogReference(type)选项:①DEFAULT:默认5V/3.3V电压 ②INTERNAL:片内参考电压,1.1V/2.56V ③INTERNAL1V1:片内1.1V参考电压 ④INTERNAL2V56 ⑤EXTERNAL:通过AREF引脚获取电压配置模拟引脚的参考电压analogWrite(pin,value)value:0~255之间int型。设置引脚输出模拟量,用于改变灯亮度或者电机转速等。注意:

  • 针脚悬空时,analogRead()返回值受到环境的多重影响。
  • AREF引脚若电压在0~5V范围外,在调用analogRead()前必须设置EXTERNAL
  • 调用analogWrite()之前,不需要调用pinMode()函数设置该引脚为输出,analogWrite()和read()没有关系
4.3 串行接口的应用

在Arduino上至少有一个串口(UART/USART),通过RX(0)和TX(1)和计算机USB进行串口通信。
串口通信指:将接收的来自CPU的并行数据转换为连续的串行数据流发送出去,或将接收的串行数据转换为并行数据转发给CPU。
串口的库函数

列举几个在实验中比较常见的函数

  • if(Serial) 串口是否准备好
  • available() 读取串口收到的字节数
    Serial.available()
  • begin() 设置串行通信波特率
    begin(speed,config)
    speed 设置波特率
    config 设置数据位数.默认是,8数据位,无奇偶位,1个停止位。
    Serial.begin(19200)
  • end(结束通信) RX,TX可以作为普通引脚使用
  • find()/findUntil() 从串口缓冲区读取已知长度的目标数据/读取到结束串停止
  • print() 将数据发送到串口显示,一个数字按照一个ASCII字符显示。
    print(val,format) format指定数据显示几位
    相似函数还有println,加一个换行符
  • read() 读字符
    还有readBytes/readBytesUntil/readString/热爱的StringUntil
  • setTimeout() 设置串口超时时间,默认1000ms
  • write()写二进制数据到串口
  • serialEvent()串口数据准备好时触发的事件函数
4.4 I2C总线接口(半双工)(考的简单)

内部集成电路(Inter-Integrated Circuit ,I2C),是具有多主机系统所需的包括总线仲裁和高低速器件同步功能的高性能总线。
两根信号线:数据线SDA,和时钟线SCL。
I2C类库函数


  • begin(address)
    初始化wire库,将I2C设备作为主设备或从设备加入I2C总线,只调用一次。默认为主设备
  • beginTransmission(address)
    启动一个已知地址的I2C从设备的通信
  • write()
    写数据到设备
  • endTransmission()
    结束一个begintransmission()。所以一次数据的传输,需要三个函数连续使用。
  • requestFrom()
    设置从设备向主设备发送的字节数。
    Wire.requestFrom(设备地址,请求字节数,stop[请求后发送停止信息,可选])、
  • available()
    调用requestFrom()返回接收的字节数,
  • read()
    接收任意方向的一个字节数据
  • setClock()
    修改底层时钟频率,底线是100KHZ
  • onReceive()
    onReceive(hander)
    当从设备接收主设备的数据时,调用hander函数
  • onRequest()
    当从主设备接收设备的数据时,调用一个hander函数
4.5 SPI接口(全双工)

串行外设接口(Serial Peripheral Interface,SPI),物理上时通过微处理单元(MCU)的同步串行端口(Synchronous Serial Port,SSP)模拟实现数据通信,允许MCU以全双工的同步串行模式进行通信
在芯片只占用四个引脚
引脚名作用SCLK串行时钟,用来同步数据传输,由主机输出MOSI主机输出从机输入数据线MISO主机输入从机输出数据线SS片选线,低电平有效,由主机输出SS可以实现一条总线多个SPI,所以SPI总线可以出现多个从机,但是只能出现一个主机4.6 外部中断接口(重要)(模块)

这里中断同操作系统的中断。外部内部发生事件,CPU暂停当前工作,去完成当前发生的事件,之后CPU继续刚刚被终止地方,继续当前工作,这样的过程称为中断。

  • 中断源:产生中断请求的源
  • 中断服务程序(ISRs),处理中断的程序
    有一定限制,不能有参数和返回值等,运行时间尽量短,同一时刻只有一个ISRs运行,delay不能用但是delayMicroseconds可以使用。
  • 中断优先级
  • 中断嵌套
在UNO中,用于中断引脚为 ,2,3
外部中断函数 四个

①attachInterrupt()

推荐语法:
attachInterrupt(digitalPinToInterrupt(pin),ISR,mode)
参数说明:

  • pin:引脚号
  • ISR:调用的ISRs函数(中断服务程序函数名)不能有参数和返回值
  • mode:触发中断方式
mode 定义含义LOW引脚低电平HIGH引脚高电平 (不适用UNO)CHANGE引脚变化RISING引脚从低到高跳变FALLING引脚从高到底跳变我们在使用时建议使用digitalPinToInterrupt(pin)函数进行转换,因为不同开发版的映射不同
在UNO中,中断号和引脚关系为:
INT.0=2
INT.1=3
② detachInterrupt()

关闭某个已启用的中断
detachInterrupt(interrupt)
参数:
interrupt,关闭中断号
③ interrupts()

开启中断
无参数
④ noInterrupts()

停止已经设置好的中断,使程序不受中断影响
无参数
tips:多说一嘴,可以使用开关中断实现原子级的函数,例如对时间敏感的函数(参考操作系统)
外部中断例子

例一:实现开关中断
  1. void setup() {}
  2. void loop()
  3. {
  4.         noInterrupts();
  5.        
  6.         ///原子/时间敏感函数
  7.         interrupts();
  8. }
复制代码
例二:实现LED不断闪烁
  1. const byte ledPin=13;
  2. const byte interruptPin=2;
  3. volatile byte state=LOW; //volatile是每次读都会从内存读新值而不是寄存器
  4. void setup()
  5. {
  6.         pinMode(ledPin,OUTPUT);
  7.         pinMode(interruptPin,INPUT_PULLUP);//外置一个按钮
  8.         attachInterrupt(digitalPinToInterrupt(interruptPin),blink,CHANGE);
  9.        
  10. }
  11. void loop()
  12. {
  13.         digitalWrite(ledPin,state);
  14. }
  15. void blink()
  16. {
  17.         state=!state;
  18. }
复制代码
4.7 软件串口(重要)

作用:硬件串口为0,1。但是为了解决日常大量使用0,1接口,增加的软件串口。若使用软件串口,只有一个可以同时接收数据。
函数

定义一个数字引脚
SoftwareSerial mySerial(RX,TX)

  • begin()
  • avaliable()
  • read()
  • write()
同硬件串口

  • isListening() 是否为检测状态
  • listen() 使串口处于检测状态,同时只有一个串口处于检测状态
  • overflow()测试软件串口是否溢出,并清除溢出标志
  • peek() 返回软件串口RX接收字符,再次调用返回相同字符
  • print和println
4.8 EEPROM

断电不丢失数据
特点:以字节为单位进行数据读写
考点:
多字节进行数据读写,使用①数组 ②共用体
EEPROM类库函数


  • read(address) 读一个字节
  • write(address,val) 写一个字节
  • update(address.val) 更新一个字节
  • put(address,data) 更新任意数据或者对象
    此函数替代write可以减少擦写次数,减少寿命
  • get(address,data) 读取任意类型的数据或者对象
实现多字节读取函数
  1. #include <EEPROM.h>
  2. // 定义一个共用体,用于存储不同类型的数据
  3. union DataUnion {
  4.   int intValue;
  5.   float floatValue;
  6.   char charArray[10]; // 假设我们需要的最大字符串为9个字符加上终止符'\0'
  7. };
  8. // 函数:从EEPROM中读取多个字节到共用体
  9. void readFromEEPROM(int startAddress, DataUnion *data, size_t dataSize) {
  10.   for (size_t i = 0; i < dataSize; i++) {
  11.     // 逐字节读取数据
  12.     ((char*)data)[i] = EEPROM.read(startAddress + i);
  13.   }
  14. }
  15. void setup() {
  16.   Serial.begin(9600);
  17.   DataUnion data;
  18.   // 假设我们要读取的数据是一个整数,存储在地址0开始的位置
  19.   readFromEEPROM(0, &data, sizeof(data.intValue));
  20.   Serial.println(data.intValue);
  21.   // 假设我们要读取的数据是一个浮点数,存储在地址4开始的位置
  22.   readFromEEPROM(4, &data, sizeof(data.floatValue));
  23.   Serial.println(data.floatValue);
  24.   // 假设我们要读取的数据是一个字符数组,存储在地址8开始的位置
  25.   readFromEEPROM(8, &data, sizeof(data.charArray));
  26.   Serial.println(data.charArray);
  27. }
  28. void loop() {
  29.   // 不需要循环操作
  30. }
复制代码
应用

实例1:从A0读取模拟量的值,存入到EEPROM。
  1. #include <EEPROM.h>
  2. int addr = 0;                          //地址初始化
  3. void setup() {
  4.   }
  5. void loop() {
  6.   int val = analogRead(0) / 4;   //模拟量除以4,10位换算为8位
  7.   EEPROM.write(addr, val);               //按地址写入变量值
  8.   addr = addr + 1;
  9.   if (addr == EEPROM.length())
  10.         addr = 0;
  11.   delay(100);
  12. }
复制代码
实例2:读EEPROM的内容并送串口监视器显示。
  1. #include <EEPROM.h>
  2. int address = 0;                //从地址0开始读
  3. byte value;
  4. void setup() {
  5.   Serial.begin(9600);         //初始化串口,等待串口连接
  6.   while (!Serial) {;}                //等待串口连接
  7. }
  8. void loop() {
  9.   value = EEPROM.read(address); //读一个字节到value
  10.   Serial.print(address);
  11.   Serial.print("\t");
  12.   Serial.println(value, DEC);
  13.   address = address + 1;
  14.   if (address == EEPROM.length())
  15.          address = 0;
  16.   delay(500);  }                          //程序运行结果
复制代码
第五章 人机界面和接口

5.1 Arduino与按键的接口技术

按键分为:编码按键和非编码两种
编码按键特点:

  • 使用方便
  • 接口简单
  • 响应速度快
  • 需要专用电脑
非编码按键特点:

  • 没有编码速度快
  • 不需要专用硬件
独立按键接口

4.jpeg

常用方法是,每个按键接一个I/O口。斜接线,一端接地,另一端通过电阻接到上拉电阻器接口上。没有键按下保持高电平,有键按下就是低电平
按键接口控制方式


  • 随机方式:Arduino空闲执行按键扫描
  • 中断方式:按键按下产生中断请求,中断响应后执行按键请求
  • 定时方式:每隔一定时间执行扫描程序,由Arduino定时器完成
按键在机械按下会产生抖动,必须进行消抖:软件消抖和硬件消抖,硬件使用不多。
5.png

软件消抖的原理是先延迟20ms再进行按键检测。
  1. 实例功能:独立按键软件消抖。
  2. int k1 = 5, k2 = 6, k3 = 7, k4 = 8;
  3. int key = 0;                     //键值
  4. int key1 = 0;                    //判断按键是否释放标志
  5. void setup(){
  6. Serial.begin(9600);
  7. pinMode(k1, INPUT);                        
  8. pinMode(k2, INPUT);
  9. pinMode(k3, INPUT);
  10. pinMode(k4, INPUT);  }
  11. void loop(){                //查询有无键按下,有键按下在屏幕显示结果
  12.     read_key();                 //读取按键
  13. if (key != 0 ) {                //显示是哪个键按下
  14. Serial.print("K");
  15. Serial.print(key);0
  16. Serial.println(" is pressed");
  17. key = 0; }
  18. }
  19. void read_key() {                 //读取按键值并消抖函数
  20.   if (!digitalRead(k1) || !digitalRead(k2) || !digitalRead(k3) || !digitalRead(k4))
  21.   {
  22.     delay (20);                         //消抖动延时
  23.   if (!digitalRead(k1) || !digitalRead(k2) || !digitalRead(k3) || !digitalRead(k4))
  24.   {
  25.   if (!digitalRead(k1)) key = 1;        //键值输出
  26.   if (!digitalRead(k2)) key = 2;
  27.   if (!digitalRead(k3)) key = 3;
  28.   if (!digitalRead(k4)) key = 4;  }
  29. else key = 0;
  30.   }
  31. if (key1 != key)                             //判断按键是否释放
  32.     key1 = key;
  33. else
  34. key = 0;                                         //没有键按下,返回0
  35. }
复制代码
矩阵按键接口

6.png

当按钮过多,一个按钮占用一个I/O接口显然不合理,所以在接口多采用矩阵列式,节省资源。矩阵按键同样要考虑按键触点闭合和断开时存在的抖动期。常用有扫描法和反转法。
扫描法

设行线(或列线)为输出,列线(或行线)为输入,依次将行线设置为低电平,同时读入列线的状态,如果列线的状态出现非全1状态,这时0状态的行、列交点的键就是所按下的键。扫描法的特点是逐行(或逐列)扫描查询。
  1. int ko[4] = {5, 6, 7, 8};                  //定义行
  2. int ki[4] = {9, 10, 11, 12};                 //定义列
  3. int key = 0;                          //键值
  4. int key1 = 0;                        //判断按键是否释放
  5. void setup() {
  6.   Serial.begin(9600);
  7.   for (int i = 0; i < 4; i++) {
  8.     pinMode(ko[i], OUTPUT);          //行输出
  9.     pinMode(ki[i], INPUT_PULLUP); //列输入,带内部上拉电阻
  10.   }
  11. }
  12. void loop(){
  13.   read_key();                          //调用读键值函数
  14.   if (key != 0 )  {
  15.     Serial.print("K");
  16.     Serial.print(key);
  17.     Serial.println(" is pressed");
  18.     key = 0;
  19.   }
  20. }
  21. void read_key() {
  22.   for ( int l = 0; l < 4; l++)          // 首先把行线全部输出高电平
  23.     digitalWrite(ko[l], HIGH);
  24.   for ( int i = 0; i < 4; i++) {
  25.     digitalWrite(ko[i], LOW);            //逐行输出低电平
  26.     delay(5);                        //等待稳定
  27.     for (int k = 0; k < 4; k++) {         //逐列读入
  28.       if (!digitalRead(ki[k])) {           //低电平表示有键按下
  29.         delay(20);                          //延时消抖动
  30.         if (!digitalRead(ki[k])) {         //再次读入,低电平确认有键按下
  31.           key =  i * 4 + k + 1;         //计算键值,行×4+列,键值1~16
  32.         }
  33.         else   key = 0;
  34.       }
  35.     }
  36.   }
  37.   if (key1 != key)                  //判断按键是否释放
  38.     key1 = key;
  39.   else
  40.     key = 0;
  41. }
复制代码
对于read_key的解释:

  • 初始化所有行为高电平:这一步是准备步骤,确保在开始扫描之前,所有行都不会触发任何列。如果某些行被设为低电平,那么在扫描过程中可能会错误地检测到未被按下的键。
  • 逐行输出低电平:接下来,程序逐行将每一行设为低电平,并检查所有列的状态。这样做的目的是为了逐个检查每一行,看看是否有按键被按下。
    当某一行被设为低电平时,如果这一行的任何键被按下,相应的列会被拉到低电平(因为按键连接了行和列,形成了电路闭合)。①此时,通过检测到的低电平列,我们可以确定是哪个键被按下了。②如果这一行没有键被按下,那么所有列都会保持高电平状态,因为内部上拉电阻会将它们拉高
反转法

反转法通过两个步骤获得键值。
① 将行线设置为低电平,从列线对应引脚读取数据,发现有列线变成低电平,说明该列有按键按下。
②反之,将该列线输出全部设置为低电平,从行对应的引脚读取数据,,发现行有低电平,说明行线有键按下。
  1. //反转法矩阵按键例程
  2. int kl[4] = { 5, 6, 7, 8};                                  //行线引脚定义
  3. int kc[4] = { 9, 10, 11, 12};                       //列线引脚定义
  4. int key = 0;                                          //键值
  5. int key1 = 0;                                       //按键释放检测
  6. int key_l;                                                  //行
  7. int key_c;                                                  //列
  8. int flag = 0;                                         //有键按下标志
  9. void setup(){
  10.      Serial.begin(9600);
  11.   }
  12. void loop()
  13. {
  14.   read_key();
  15.   if (key != 0 )
  16.   {
  17.     Serial.print("K");
  18.     Serial.print(key);
  19.     Serial.println(" is pressed");
  20.     key = 0;
  21.   }
  22. }
  23. void read_key() {
  24.   for (int i = 0; i < 4; i++)                         //行输出,列输入
  25.   {
  26.     pinMode(kl[i], OUTPUT);
  27.     digitalWrite(kl[i], LOW);
  28.     pinMode(kc[i], INPUT_PULLUP);         //带内部上拉电阻
  29.   }
  30.   delay(5);
  31.   for (int k = 0; k < 4; k++) {
  32.     if (!digitalRead(kc[k])) {
  33.       delay(20);
  34.       if (!digitalRead(kc[k])) {
  35.         key_c = k;
  36.         flag = 1;                                //有键按下标志
  37.       }
  38.       else flag = 0;
  39.     }
  40.   }
  41. if (flag == 1)  {
  42.     for (int n = 0; n < 4; n++)  {              //列输出,行输入
  43.        pinMode(kc[n], OUTPUT);
  44.       digitalWrite(kc[n], LOW);
  45.       pinMode(kl[n], INPUT_PULLUP);
  46.     }
  47.     delay(5);
  48.     for (int j = 0; j < 4; j++)   {
  49.       if (!digitalRead(kl[j]))  {
  50.         key_l = j;
  51.         key = key_l * 4 + key_c + 1;        //计算键值,行×4+列,键值1~16
  52.         flag = 0;
  53.       }  }  }
  54.   if (key1 != key)                                 //判断按键是否释放
  55.     key1 = key;
  56.   else
  57.     key = 0;
  58. }
复制代码
区别

代码上看,扫描法是两个循环嵌套,反转法是四个循环。
模拟量按键接口

仅需一个模拟信号接口,通过输入的电压值不同处理不同的结果
两种:
并联式
7.png

串联式
8.png

5.2 红外技术

红外遥控机工作原理

红外遥控器是一种无线发射装置,在波长为0.76~1.5um的近红外线来传输控制信号的遥控设备。
9.png

红外线二极管发射光波->红外线接收器把红外信号转换为电信号->处理器处理->解调指令
红外发光二极管:特殊的二极管,发出不可见光
红外接收头:VDD,GND,VOUT三个头
特点:
不可穿墙,电路调试简单,编码解码容易
编码

组成:

  • 起始码
  • 用户码
  • 数据码
  • 数据码反码(纠错)
软件编码:八位二段用户码,8位数据码和8位数据反码
5.3 数码管

数码管是8个发光二极管组成的元件,七个段用a~g表示,小数点用dp表示
10.png

分为共阳极(阴极连接成公共端,接GND),和共阴极(阳极链接成公共端,接5V),区别就是前者阳极高电平发光,后者阴极接地发光。
LCD接口技术

LCD是平面显示器一种。耗电量低,体积小,辐射低。
LCD分为四类:

  • 点阵式液晶屏
  • 段码式液晶屏
  • 字符式液晶屏
  • TFT彩屏
LCD1602

引脚说明
名称作用VSS电源地线VDD电源正极VO液晶显示偏压RS数据/命令选择R/W读/写选择E使能信号D0~D7数据位BLA背光板正极BLK背光板负极显示字符有以下几种:
①使用自行库CGROM,包含96个标准ASCII字符,96个日文字符和希腊文字符
②自定义的点阵字符,5*7的矩阵,CGROM存储的也是这种字符,每行用01代表是否显示该点。
LCD类库函数

LiquidCrystal.h

  • LiquidCrystal
    构造函数,可以采用4线(d0~d3悬空),或者8线方式
  1. LiquidCrystal(rs,enable,d4,d5,d6,d7)
  2. LiquidCrystal(rs,rw,enable,d,d,d,d)
复制代码

  • begin(cols,rows)
    初始化,设定显示列数和行数
  • clear()
    清空
  • write(data)/print(data)
    向LCD写一个字符/字符串,一般来说print用途更广
以下是几个有关光标的函数

  • home()
    光标定位在屏幕左上角
  • setCursor(col,row)
    定位在指定行列
  • cursor()
    显示光标
  • noCursor()
    关闭
  • blink()/noBlink
    闪烁的光标
以下是跟液晶视觉有关的

  • display()/noDisplay()
    开启/关闭液晶显示
  • scrollDisplayLeft()/scrollDisplayRight()
    屏幕上内容向左滚动一个字符
  • autoscroll()/noAutoscroll()
    自动滚动
  • leftToRight()/rightToLeft()
    文本从左到右写入屏幕(默认)/从右向左
  • createChar()
    创建用户自定义字符,可创建8个(0~7),需使用write(num),num为自定义编号。
6 常用模块的应用

6.1 超声波测距

11.png

超声波测距传感器,采用超声波回波测距原理。
12.png

下图为SR04原理
13.png

HR-SR04类库函数

构造函数SR04(int echonPin,int tiggerPin)

  • Distance()
    返回测量距离,long类型,单位cm
下例为超声波测量的例子
  1. #include "SR04.h"                //添加库函数
  2. #define TRIG_PIN 6                //定义引脚
  3. #define ECHO_PIN 7                //定义引脚
  4. SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);        //构造函数
  5. long a;
  6. void setup() {
  7.    Serial.begin(9600);                //定义串口波特率
  8.    Serial.println("Example written by Coloz From Arduin.CN");
  9.    delay(1000);
  10. }
  11. void loop() {
  12.    a=sr04.Distance();                 //读取障碍物和SR04的距离
  13.    Serial.print(a);                      //送串口监视器显示
  14.    Serial.println("cm");
  15.    delay(1000);
  16. }
复制代码
蜂鸣器(模块)

14.png

是一种一体化结构的电子讯响器,直流电压供电,用作发声器件
有源蜂鸣器(内含驱动电路),可以将直流电转化为一定的脉冲信号,引起磁场变化,带动震动膜片发出震动声音。
和无源蜂鸣器(外部驱动)
有源蜂鸣器

蜂鸣器发声时间不同,频率就不同,声音就不同。
[code]int buzzer = 8;                        //设置控制蜂鸣器的数字引脚 正极连接void setup() {       pinMode(buzzer,OUTPUT);         //设置数字引脚为输出模式    } void loop() {    unsigned char i, j;                    //定义变量     for(i=0; i
您需要登录后才可以回帖 登录 | 立即注册