嵌入式 Arduino 期末复习
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板
拥有:
- 14个输入输出引脚(0~13),其中(3,5,6,9,10,11)可以作为PWM输出
- 6个模拟输入(A0~A5)
- 1个UART硬件串口
- 1个电源插孔,1个ICSP插座和1个复位按钮
- 1个USB接口,与计算机连接,可以供电和通信
引脚名称和功能
电源引脚
名称 | 作用 |
---|---|
VIN | ①外部电流供电时的输入电压引脚 ②电源插座供电时提供5V电压 |
5V | 输出5V电压 使用该引脚和3.3V引脚可能损坏旁路线性稳压器 |
3V | 输出3.3V电压 |
GND | 接地 |
AREF | 模拟输入的参考电压 |
RESET | 扩展一个按钮实现复位功能。引脚为低电平 |
输入输出
名称 | 引脚位 | 作用 |
---|---|---|
串口 | 0(RX),1(TX) | 接收(RX)和发送(TX)TTL串行数据。 |
外部中断 | 2,3 | 触发中断的引脚。触发条件分为:①低电平触发 ②上升沿触发 ③下降沿触发 ④发生变化触发 |
PWM | 3,5,6,9,10,11(~线) | 6路八位PWM |
SPI | 10(SS),11(MOSI),12(MISO),13(SCK) | 支持SPI通信 |
LED | 13 | 高电平LED亮,低电平LED灭 |
TWI | A4/SDA,A5/SCL | TWI通信 |
3 Arduino编程
3.1 函数
时间函数
函数 | 参数 | 用法 | 备注 |
---|---|---|---|
delay(ms) | ms为unsigned long | 延长ms毫秒 | delay更多用于较短延时,但是有以下缺点:①延时中无法读取传感器的值等,阻止了大部分操作 |
delayMicroseconds(μs) | μs为 unsigned int | 延长微秒 | 更长时间用delay |
micros() | 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 ,中间返回x |
map(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的位 | 某一位置0 |
bitRead(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 位运算
- &按位与
0 0 1 1
0 1 0 1
--------&
0 0 0 1
- |按位或
0 0 1 1
0 1 0 1
---------|
0 1 1 1
~ 按位取反
^按位异或
0 0 1 1
0 1 0 1
---------^
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/热爱的StringUntilsetTimeout() 设置串口超时时间,默认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()
修改底层时钟频率,底线是100KHZonReceive()
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:多说一嘴,可以使用开关中断实现原子级的函数,例如对时间敏感的函数(参考操作系统)
外部中断例子
例一:实现开关中断
void setup() {}
void loop()
{
noInterrupts();
///原子/时间敏感函数
interrupts();
}
例二:实现LED不断闪烁
const byte ledPin=13;
const byte interruptPin=2;
volatile byte state=LOW; //volatile是每次读都会从内存读新值而不是寄存器
void setup()
{
pinMode(ledPin,OUTPUT);
pinMode(interruptPin,INPUT_PULLUP);//外置一个按钮
attachInterrupt(digitalPinToInterrupt(interruptPin),blink,CHANGE);
}
void loop()
{
digitalWrite(ledPin,state);
}
void blink()
{
state=!state;
}
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) 读取任意类型的数据或者对象
实现多字节读取函数
#include <EEPROM.h>
// 定义一个共用体,用于存储不同类型的数据
union DataUnion {
int intValue;
float floatValue;
char charArray[10]; // 假设我们需要的最大字符串为9个字符加上终止符'\0'
};
// 函数:从EEPROM中读取多个字节到共用体
void readFromEEPROM(int startAddress, DataUnion *data, size_t dataSize) {
for (size_t i = 0; i < dataSize; i++) {
// 逐字节读取数据
((char*)data)[i] = EEPROM.read(startAddress + i);
}
}
void setup() {
Serial.begin(9600);
DataUnion data;
// 假设我们要读取的数据是一个整数,存储在地址0开始的位置
readFromEEPROM(0, &data, sizeof(data.intValue));
Serial.println(data.intValue);
// 假设我们要读取的数据是一个浮点数,存储在地址4开始的位置
readFromEEPROM(4, &data, sizeof(data.floatValue));
Serial.println(data.floatValue);
// 假设我们要读取的数据是一个字符数组,存储在地址8开始的位置
readFromEEPROM(8, &data, sizeof(data.charArray));
Serial.println(data.charArray);
}
void loop() {
// 不需要循环操作
}
应用
实例1:从A0读取模拟量的值,存入到EEPROM。
#include <EEPROM.h>
int addr = 0; //地址初始化
void setup() {
}
void loop() {
int val = analogRead(0) / 4; //模拟量除以4,10位换算为8位
EEPROM.write(addr, val); //按地址写入变量值
addr = addr + 1;
if (addr == EEPROM.length())
addr = 0;
delay(100);
}
实例2:读EEPROM的内容并送串口监视器显示。
#include <EEPROM.h>
int address = 0; //从地址0开始读
byte value;
void setup() {
Serial.begin(9600); //初始化串口,等待串口连接
while (!Serial) {;} //等待串口连接
}
void loop() {
value = EEPROM.read(address); //读一个字节到value
Serial.print(address);
Serial.print("\t");
Serial.println(value, DEC);
address = address + 1;
if (address == EEPROM.length())
address = 0;
delay(500); } //程序运行结果
第五章 人机界面和接口
5.1 Arduino与按键的接口技术
按键分为:编码按键和非编码两种
编码按键特点:
- 使用方便
- 接口简单
- 响应速度快
- 需要专用电脑
非编码按键特点:
- 没有编码速度快
- 不需要专用硬件
独立按键接口
常用方法是,每个按键接一个I/O口。斜接线,一端接地,另一端通过电阻接到上拉电阻器接口上。没有键按下保持高电平,有键按下就是低电平
按键接口控制方式
- 随机方式:Arduino空闲执行按键扫描
- 中断方式:按键按下产生中断请求,中断响应后执行按键请求
- 定时方式:每隔一定时间执行扫描程序,由Arduino定时器完成
按键在机械按下会产生抖动,必须进行消抖:软件消抖和硬件消抖,硬件使用不多。
软件消抖的原理是先延迟20ms再进行按键检测。
实例功能:独立按键软件消抖。
int k1 = 5, k2 = 6, k3 = 7, k4 = 8;
int key = 0; //键值
int key1 = 0; //判断按键是否释放标志
void setup(){
Serial.begin(9600);
pinMode(k1, INPUT);
pinMode(k2, INPUT);
pinMode(k3, INPUT);
pinMode(k4, INPUT); }
void loop(){ //查询有无键按下,有键按下在屏幕显示结果
read_key(); //读取按键
if (key != 0 ) { //显示是哪个键按下
Serial.print("K");
Serial.print(key);0
Serial.println(" is pressed");
key = 0; }
}
void read_key() { //读取按键值并消抖函数
if (!digitalRead(k1) || !digitalRead(k2) || !digitalRead(k3) || !digitalRead(k4))
{
delay (20); //消抖动延时
if (!digitalRead(k1) || !digitalRead(k2) || !digitalRead(k3) || !digitalRead(k4))
{
if (!digitalRead(k1)) key = 1; //键值输出
if (!digitalRead(k2)) key = 2;
if (!digitalRead(k3)) key = 3;
if (!digitalRead(k4)) key = 4; }
else key = 0;
}
if (key1 != key) //判断按键是否释放
key1 = key;
else
key = 0; //没有键按下,返回0
}
矩阵按键接口
当按钮过多,一个按钮占用一个I/O接口显然不合理,所以在接口多采用矩阵列式,节省资源。矩阵按键同样要考虑按键触点闭合和断开时存在的抖动期。常用有扫描法和反转法。
扫描法
设行线(或列线)为输出,列线(或行线)为输入,依次将行线设置为低电平,同时读入列线的状态,如果列线的状态出现非全1状态,这时0状态的行、列交点的键就是所按下的键。扫描法的特点是逐行(或逐列)扫描查询。
int ko[4] = {5, 6, 7, 8}; //定义行
int ki[4] = {9, 10, 11, 12}; //定义列
int key = 0; //键值
int key1 = 0; //判断按键是否释放
void setup() {
Serial.begin(9600);
for (int i = 0; i < 4; i++) {
pinMode(ko[i], OUTPUT); //行输出
pinMode(ki[i], INPUT_PULLUP); //列输入,带内部上拉电阻
}
}
void loop(){
read_key(); //调用读键值函数
if (key != 0 ) {
Serial.print("K");
Serial.print(key);
Serial.println(" is pressed");
key = 0;
}
}
void read_key() {
for ( int l = 0; l < 4; l++) // 首先把行线全部输出高电平
digitalWrite(ko[l], HIGH);
for ( int i = 0; i < 4; i++) {
digitalWrite(ko[i], LOW); //逐行输出低电平
delay(5); //等待稳定
for (int k = 0; k < 4; k++) { //逐列读入
if (!digitalRead(ki[k])) { //低电平表示有键按下
delay(20); //延时消抖动
if (!digitalRead(ki[k])) { //再次读入,低电平确认有键按下
key = i * 4 + k + 1; //计算键值,行×4+列,键值1~16
}
else key = 0;
}
}
}
if (key1 != key) //判断按键是否释放
key1 = key;
else
key = 0;
}
对于read_key的解释:
初始化所有行为高电平:这一步是准备步骤,确保在开始扫描之前,所有行都不会触发任何列。如果某些行被设为低电平,那么在扫描过程中可能会错误地检测到未被按下的键。
逐行输出低电平:接下来,程序逐行将每一行设为低电平,并检查所有列的状态。这样做的目的是为了逐个检查每一行,看看是否有按键被按下。
当某一行被设为低电平时,如果这一行的任何键被按下,相应的列会被拉到低电平(因为按键连接了行和列,形成了电路闭合)。①此时,通过检测到的低电平列,我们可以确定是哪个键被按下了。②如果这一行没有键被按下,那么所有列都会保持高电平状态,因为内部上拉电阻会将它们拉高
反转法
反转法通过两个步骤获得键值。
① 将行线设置为低电平,从列线对应引脚读取数据,发现有列线变成低电平,说明该列有按键按下。
②反之,将该列线输出全部设置为低电平,从行对应的引脚读取数据,,发现行有低电平,说明行线有键按下。
//反转法矩阵按键例程
int kl[4] = { 5, 6, 7, 8}; //行线引脚定义
int kc[4] = { 9, 10, 11, 12}; //列线引脚定义
int key = 0; //键值
int key1 = 0; //按键释放检测
int key_l; //行
int key_c; //列
int flag = 0; //有键按下标志
void setup(){
Serial.begin(9600);
}
void loop()
{
read_key();
if (key != 0 )
{
Serial.print("K");
Serial.print(key);
Serial.println(" is pressed");
key = 0;
}
}
void read_key() {
for (int i = 0; i < 4; i++) //行输出,列输入
{
pinMode(kl[i], OUTPUT);
digitalWrite(kl[i], LOW);
pinMode(kc[i], INPUT_PULLUP); //带内部上拉电阻
}
delay(5);
for (int k = 0; k < 4; k++) {
if (!digitalRead(kc[k])) {
delay(20);
if (!digitalRead(kc[k])) {
key_c = k;
flag = 1; //有键按下标志
}
else flag = 0;
}
}
if (flag == 1) {
for (int n = 0; n < 4; n++) { //列输出,行输入
pinMode(kc[n], OUTPUT);
digitalWrite(kc[n], LOW);
pinMode(kl[n], INPUT_PULLUP);
}
delay(5);
for (int j = 0; j < 4; j++) {
if (!digitalRead(kl[j])) {
key_l = j;
key = key_l * 4 + key_c + 1; //计算键值,行×4+列,键值1~16
flag = 0;
} } }
if (key1 != key) //判断按键是否释放
key1 = key;
else
key = 0;
}
区别
代码上看,扫描法是两个循环嵌套,反转法是四个循环。
模拟量按键接口
仅需一个模拟信号接口,通过输入的电压值不同处理不同的结果
两种:
并联式
串联式
5.2 红外技术
红外遥控机工作原理
红外遥控器是一种无线发射装置,在波长为0.76~1.5um的近红外线来传输控制信号的遥控设备。
红外线二极管发射光波->红外线接收器把红外信号转换为电信号->处理器处理->解调指令
红外发光二极管:特殊的二极管,发出不可见光
红外接收头:VDD,GND,VOUT三个头
特点:
不可穿墙,电路调试简单,编码解码容易
编码
组成:
- 起始码
- 用户码
- 数据码
- 数据码反码(纠错)
软件编码:八位二段用户码,8位数据码和8位数据反码
5.3 数码管
数码管是8个发光二极管组成的元件,七个段用a~g表示,小数点用dp表示
分为共阳极(阴极连接成公共端,接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线方式
LiquidCrystal(rs,enable,d4,d5,d6,d7)
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 超声波测距
超声波测距传感器,采用超声波回波测距原理。
下图为SR04原理
HR-SR04类库函数
构造函数SR04(int echonPin,int tiggerPin)
- Distance()
返回测量距离,long类型,单位cm
下例为超声波测量的例子
#include "SR04.h" //添加库函数
#define TRIG_PIN 6 //定义引脚
#define ECHO_PIN 7 //定义引脚
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN); //构造函数
long a;
void setup() {
Serial.begin(9600); //定义串口波特率
Serial.println("Example written by Coloz From Arduin.CN");
delay(1000);
}
void loop() {
a=sr04.Distance(); //读取障碍物和SR04的距离
Serial.print(a); //送串口监视器显示
Serial.println("cm");
delay(1000);
}
蜂鸣器(模块)
是一种一体化结构的电子讯响器,直流电压供电,用作发声器件
有源蜂鸣器(内含驱动电路),可以将直流电转化为一定的脉冲信号,引起磁场变化,带动震动膜片发出震动声音。
和无源蜂鸣器(外部驱动)
有源蜂鸣器
蜂鸣器发声时间不同,频率就不同,声音就不同。
int buzzer = 8; //设置控制蜂鸣器的数字引脚 正极连接
void setup() {
pinMode(buzzer,OUTPUT); //设置数字引脚为输出模式
}
void loop() {
unsigned char i, j; //定义变量
for(i=0; i<80; i++) { //输出一个频率的声音
digitalWrite(buzzer,HIGH); //发声
delay(1); //延时1ms
digitalWrite(buzzer,LOW); //不发声
delay(1); } //延时1 ms
for(j=0; j<100; j++) { //输出另一个频率的声音
digitalWrite(buzzer,HIGH); //发声
delay(2); //延时2ms
digitalWrite(buzzer,LOW); //不发声
delay(2); } //延时2ms
}
6.3 温湿度传感器
DHT11是这学期用到的的。是一款已校准数字信号输出的复合传感器。
有关DHT11的实战可以看我另外一篇博客DHT11+ESP-01S实现上传云数据
DHT11类库函数
read()
获取温湿度状态返回码 0无错误,-1有错,-2超时DHT11.humidity
int型湿度值DHT11.temperature
int型温度值
6.4 直流电机(概念即可)
直流电机把直流电转换为机械能,
定子:直流电机运行时静止不动的部分。定子的主要作用是产生磁场。
转子:运行时转动的部分,其主要作用是产生电磁转矩和感应电动势
如何调速?
- 改变电压,电压大小决定转速
- 改变磁通量
- 串联几个调节电阻(本质还是调节电压)
如何转向?
改变电流方向即可
6.5 步进电机
步进电机把电脉冲转化为角位移的执行器件。
当步进电机驱动器接收到一个脉冲信号时,它就驱动步进电机按照规定方向转动一个固定角度(步距角)
6.6 陀机
是一种位置(角度)伺服的驱动器,适用于需要角度不断变化并能保持的控制系统
标准的舵机三条引出线是:电源线(红色)、地线(橙色)、控制线(黄色)。舵机的控制信号是PWM信号,可利用占空比的变化,改变舵机的位置。角度变化和脉冲宽度成正比
陀机类库函数
Servo.h
attach(pin,min,max)
pin:信号引脚
min:脉冲宽度(可选,默认544/0°)
max:脉冲最大(可选,默认2400/180°)write(angle)
设定角度值writeMicroseconds(us)
设定脉冲宽度read()
读取陀机的角度值,返回int型(0~180)atached()
检查陀机是否指定引脚detach()
分离陀机和指定引脚
陀机代码
例子一:将串口监视器输入的0~9数字转换问0~180对应角度,控制陀机位置
int servopin=9; //定义舵机接口数字接口9
int myangle; //定义角度变量
int pulsewidth; //定义脉宽变量
int val;
void servopulse(int servopin,int myangle) { //定义一个脉冲函数
pulsewidth=(myangle*11)+500; //将角度转化为500~2480的脉宽值
digitalWrite(servopin,HIGH) ; //将舵机接口电平置高
delayMicroseconds(pulsewidth); //延时脉宽值的微秒数
digitalWrite(servopin,LOW ); //将舵机接口电平置低
delay(20-pulsewidth/1000); }
void setup() {
pinMode(servopin,OUTPUT); //设定舵机接口为输出接口
Serial.begin(9600); //连接到串行端口,波特率为9600
Serial.println("servu=o_seral_simple ready" ) ;
}
//将0到9的数转化为0到180角度
void loop()
{
val=Serial.read(); //读取串行端口的值
if(val>'0'&&val<='9')
{
val=val-'0'; //将字符转化为数值变量
val=val*(180/9); //将数字转化为角度
Serial.print("moving servo to ");
Serial.print(val,DEC);
Serial.println();
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse(servopin,val); //引用脉冲函数
}
}
}
实例2:采用Servo类库,通过电位器控制舵机。程序下载后,当改变电位器的值时,舵机转动的角度会随之改变。
#include <Servo.h> //使用伺服电机类库
Servo myservo; //定义伺服对象myservo
int potpin = 0; //模拟引脚用于连接电位器
int val; //电位器的模拟值存放变量
void setup() {
myservo.attach(9); //指定9脚连到舵机
}
void loop() {
val = analogRead(potpin); //读取电位器的值( 0~1023)
val = map(val, 0, 1023, 0, 180); //变换为控制舵机的角度值(0~180)
myservo.write(val); //根据换算后的值设置舵机位置
delay(15); //等待舵机到位,以防舵机抖动
}
6.7 SD卡读写模块(概念)
特点:价格低廉,储存容量大,使用方便,通用性和安全性强的特点
两种总线方式
SD方式(六总线):CLK,CMD,DAT0~DAT3
SPI方式(四总线):CLK,CS,DI,DO
SD比SPI较快,但是单片机用SPI偏多。
MicroSD卡和SD兼容,但是MicroSD不带写保护
6.8 三色LED灯(重要)
三色LED灯由三块LED封装而成,分为共阴极和共阳极(原理同LCD1602)。通过analogWrite()
,控制三色组合来实现各种颜色。
其中引脚最长的是公共端
例子:
void setup() {
// 初始化引脚6为输出模式
pinMode(6, OUTPUT);
}
void loop() {
// 逐渐增加亮度
for (int i = 0; i <= 255; i++) {
analogWrite(6, i);
delay(10); // 稍作延迟以便观察变化
}
// 逐渐减少亮度
for (int i = 255; i >= 0; i--) {
analogWrite(6, i);
delay(10); // 稍作延迟以便观察变化
}
}
6.9 继电器(概念)
继电器(relay)是一个电控制器件,可以把小信号(输入信号)转化为高电压大功率控制信号(输出信号)的自动开关。
电磁继电器工作原理
电磁继电器由铁芯,线圈,衔铁,触点簧片组成。
简单就是线圈带电产生磁场,吸引弹簧片实现常开,断电弹簧片慢慢回弹实现常闭。分为以下几种:
7 通信模块以及应用
7.1 蓝牙通信模块
蓝牙是一种高效稳定的数据传输技术。蓝牙标准中定义了多种协议,使蓝牙协议可应用于各种数据传输。蓝牙端口协议(Serial Port Profile,SPP)是用于规范文本数据传输的协议,该协议可使蓝牙接口能被当成串口一样进行数据传输。
最主要的功能就是取代串口线
HC-05
嵌入式 Arduino 期末复习的更多相关文章
- SCE信号期末复习省流小助手(懒人版)
XDU-SCE网信院信号期末复习省流小助手(懒人版) 本人根据西安电子科技大学网络与信息安全18年期末考试整理的考点和题型 以下题型代表了信号与系统课程的 精髓 若能掌握以下知识点和题型,80分稳有: ...
- JavaEE期末复习
期末复习 基础 jsp技术中嵌入java代码,使用的符号 <%%> 掌握jsp技术中引用其他标签库指令标签的书写 掌握jsp技术中request对象setAttribute( ).setC ...
- Hadoop期末复习
Hadoop期末复习 选择题 以下选项中,哪个程序负责HDFS数据存储. B A.NameNode B.DataNode C.Secondary NameNode D.ResourceManager ...
- python爬虫期末复习
python期末复习 选择题 以下选项中合法的是(A). A 爬取百度的搜索结果 B 爬取淘宝的商品数据 C 出售同学的个人信息 D 为高利贷提供技术服务 网站的根目录下有一个文件告诉爬虫哪些内容可以 ...
- JavaEE期末复习知识点总结
JavaEE期末复习知识点总结 Java企业应用开发环境 Maven的基础概念 Maven是一个项目管理工具,可以对 Java 项目进行构建.依赖管理 Maven仓库 Maven 仓库是项目中依赖的第 ...
- now code——处女座的期末复习
题目描述 快要期末考试了,处女座现在有n门课程需要考试,每一门课程需要花ai小时进行复习,考试的起始时间为bi,处女座为了考试可以不吃饭不睡觉,处女座想知道他能否复习完所有的科目(即在每一门考试之前复 ...
- 南京邮电大学 JavaA期末复习要点总结
南京邮电大学 JavaA复习要点: Chap1 入门 1. Java应用程序开发过程教材P14~P15 Chap 2 基本语法 1. 标识符的命名规则教材P19 字母下划线美元符号开头,除 ...
- C#知识点提炼期末复习专用
根据内部消息称:有三类题型: 程序阅读题:2题 简答题:2题 (主要是对概念的考查) 编程题:暂定2-3题 复习要点: .net framework 通用语言开发环境..NET基础类库..NET ...
- 微信小程序期末复习
过什么六一,复习不完了... 第1章作业 一.单选题(共10题,100.0分) 1以下哪个不是主流的手机操作系统? A.Android B.iOS C.Windows Phone D.Blackber ...
- 【嵌入式】ARM9复习
一.嵌入式系统基础 二.ARM处理器 1. 在每条指令后,用;//注释这条指令的寻址方式,以及实现的功能(25分) 注:变址寻址需要标注是基址加偏移.还是基址加索引,是前变址还是后变址.SUB SP, ...
随机推荐
- PHP vs Golang ? 想什么呢 ! What Are You Thinking !
在使用 PHP 多年之后,我对 PHP 的优势和劣势已经非常清楚,与后起之秀 Golang 相比,两者已经不在一个重量级. PHP 更像是 70 kg 级别的选手,脚本语言,极速开发,部署方便,性能可 ...
- dotnet 8 破坏性改动 在 AssemblyInformationalVersionAttribute 添加上 git 的 commit 号
我在一个 WPF 项目里面,在界面显示应用的版本号,更新到 dotnet 8 的 SDK 之后,发现我的界面布局损坏了.本质上这个破坏性改动和 WPF 没有什么关系,是 dotnet 的 SDK 或编 ...
- dotnet core 3.1 将 UWP 控件嵌入到 WPF 应用 收到 UIA 消息主线程卡住
本文记录一个问题,此问题是在 .NET Core 3.1 的 WPF 应用里面,嵌入 UWP 控件之后,在收到 UIA 的消息时,可能让主线程卡住.暂时此问题还不知道具体的复现步骤,此问题预计和 WP ...
- WPF 列表控件数据源绑定多个数据集合方法
在 WPF 用的多的列表控件如 ListBox 或 ListView 等,本文告诉大家在这些列表控件上进行绑定多个数据集合来源的多个实现方法.如有一个显示动物列表的控件,需要绑定的数据来源是阿猫和阿狗 ...
- 使用组合逻辑电路驱动VGA显示器
使用组合逻辑电路驱动VGA显示器 1. 概述 本文讲述一种不使用缓冲存储器驱动VGA显示的简单方法.其中,VGA分辨率采用DE10-Lite建议使用的640X480.像素的时钟25MHz,刷新率59. ...
- 【GUI软件】小红书评论采集v4.0升级版:自动采集1w多条,含二级评论!
目录 一.爬取目标 1.1 效果截图 1.2 演示视频 1.3 软件说明 二.代码讲解 2.1 爬虫采集模块 2.2 软件界面模块 2.3 日志模块 三.获取源码及软件 一.爬取目标 您好!我是@马哥 ...
- pikachu靶机练习平台-xss
第一题:反射性xss(get) 输出的字符出现在url中 第二题:反射性xss(post) 登录后输入<script>alert(1)</script> 第三题:存储型xss ...
- 02 go-zero入门--微服务demo
参考文档: https://go-zero.dev/cn/docs/advance/rpc-call 视频地址: https://space.bilibili.com/387126464/channe ...
- 03. Ruby入门理解
Ruby入门学习: 视频教程 https://www.bilibili.com/video/BV1QW411F7rh?t=401&p=1 笔记 https://github.com/haima ...
- Go语言连接Redis之go-redis使用指南
参考下面的连接: https://mp.weixin.qq.com/s?__biz=MzU5MjAxMDc1Ng==&mid=2247483899&idx=1&sn=b103c ...