【雕爷学编程】Arduino 手册之高级 I/O 函数 shiftIn()

在这里插入图片描述
在这里插入图片描述
什么是Arduino?
Arduino 是一款开源的电子原型平台,它可以让你用简单的硬件和软件来创建各种创意的项目。无论你是初学者还是专家,Arduino 都能为你提供无限的可能性。你可以用 Arduino 来控制传感器、灯光、马达、机器人、物联网设备等等,只要你能想到的,Arduino 都能帮你实现。

如果你想了解更多关于 Arduino 的信息,你可以访问 Arduino 的官方网站,那里有丰富的资源和教程供你参考。你也可以加入 Arduino 的社区,和来自世界各地的爱好者、学生、设计师和工程师交流心得和经验。此外,你还可以使用 Arduino 的在线编程工具,在云端编写代码并上传到你的开发板上。

Arduino 是一个不断发展和创新的平台,它有着广泛的应用领域和潜力。这里希望本手册能激发你对 Arduino 的兴趣和热情,让你享受 Arduino 带来的创造力和乐趣

在这里插入图片描述

维基百科的定义
Arduino 是一个开源嵌入式硬件平台,用来供用户制作可交互式的嵌入式项目。此外 Arduino 作为一个开源硬件和开源软件的公司,同时兼有项目和用户社群。该公司负责设计和制造Arduino电路板及相关附件。这些产品按照GNU宽通用公共许可证(LGPL)或GNU通用公共许可证(GPL)许可的开源硬件和软件分发的,Arduino 允许任何人制造 Arduino 板和软件分发。 Arduino 板可以以预装的形式商业销售,也可以作为 DIY 套件购买。

Arduino 2005 年时面世,作为意大利伊夫雷亚地区伊夫雷亚互动设计研究所的学生设计,目的是为新手和专业人员提供一种低成本且简单的方法,以建立使用传感器与环境相互作用的装置。初学者和爱好者可用Arduino制造传感器、简单机器人、恒温器和运动检测器等装置。

Arduino 这个名字来自意大利伊夫雷亚的一家酒吧,该项目的一些创始人过去常常会去这家酒吧。 酒吧以伊夫雷亚的 Arduin(Arduin of Ivrea)命名,他是伊夫雷亚边疆伯爵,也是 1002 年至 1014 年期间的意大利国王。

在这里插入图片描述

十五、Arduino高级 I/O 函数 shiftIn()
shiftIn()函数是一种用于从数字引脚输入串行数据的函数。shiftIn()的作用是让Arduino从一个数据引脚逐位读取一个字节(8位)的数据,同时根据另一个时钟引脚的变化来确定读取的时机,以便获取或处理外部的设备或电路的数据,例如移位寄存器、键盘、编码器等。

shiftIn()的使用范围:
1)当需要从一个数字引脚输入多个二进制位的数据时,例如输入一个字符、一个数字、一个状态等。
2)当需要扩展Arduino的数字输入引脚时,例如使用移位寄存器来读取更多的开关、传感器、信号等。
3)当需要与其他支持串行通信的设备或电路进行数据交换时,例如使用SPI协议来读取其他Arduino、传感器、显示器等。

应用场景:
1)并行数据接收:当需要从外部设备接收并行数据时,Arduino的输入引脚数量可能不足。通过使用移位寄存器和shiftIn()函数,可以将并行数据位串行地接收到Arduino,并通过移位寄存器的输出引脚实现对多个输入设备的扩展。这在读取多个开关、按键或传感器状态的应用中非常有用。
2)数据采集和监测:移位寄存器可以用于采集和存储多个输入设备的状态,并通过shiftIn()函数将数据传输到Arduino进行处理和监测。这在需要同时监测多个传感器状态或读取外部设备的数据的应用中非常有用。
3)与其他微控制器通信:移位寄存器不仅可以用于输入控制,还可以用于输出控制。通过使用shiftIn()函数,可以从移位寄存器的输出引脚接收其他微控制器发送的数据。这在与其他设备进行并行数据传输或通信的应用中非常有用。

使用shiftIn()时,需要注意以下事项:
1)shiftIn()函数的第一个参数是要输入数据的数字引脚的编号,可以是任意一个数字引脚。第二个参数是要输入时钟信号的数字引脚的编号,可以是任意一个数字引脚。第三个参数是要输入数据的顺序,可以是MSBFIRST(最高位先入)或LSBFIRST(最低位先入)。
2)shiftIn()函数会根据指定的顺序和时序,从数据引脚逐位读取数据,并返回一个字节(8位)的值。每当时钟引脚从低电平变为高电平时,外部设备或电路会输出下一位数据到数据引脚。每当时钟引脚从高电平变为低电平时,Arduino会读取当前位数据。这样,一共需要8个时钟周期才能输入完整的一个字节。
3)shiftIn()函数只能用于已经设置为输入模式的数字引脚,否则会导致不可预测的结果。要设置数字引脚的模式,可以使用pinMode()函数。
4)shiftIn()函数只能用于输入串行数据,不能用于输出串行数据。如果要输出串行数据,可以使用shiftOut()函数或其他方法。

下面是几个实际运用程序案例,展示了在Arduino中使用shiftIn()函数的应用场景:

案例一:读取多个开关状态:

const int dataPin = 2;
const int latchPin = 3;
const int clockPin = 4;

void setup() {
    
    
  pinMode(dataPin, INPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
}

void loop() {
    
    
  digitalWrite(latchPin, LOW);
  byte switchStates = shiftIn(dataPin, clockPin, MSBFIRST); // 从移位寄存器接收开关状态
  digitalWrite(latchPin, HIGH);

  // 处理开关状态
  if (bitRead(switchStates, 0)) {
    
    
    // 第一个开关打开
  }
  else {
    
    
    // 第一个开关关闭
  }

  if (bitRead(switchStates, 1)) {
    
    
    // 第二个开关打开
  }
  else {
    
    
    // 第二个开关关闭
  }

  // ...
}

在此案例中,我们使用移位寄存器和shiftIn()函数来读取多个开关的状态。通过将开关状态从移位寄存器的输出引脚接收到Arduino,可以同时读取多个开关的状态。通过使用bitRead()函数处理接收到的字节数据,可以判断每个开关的状态。

案例二:读取多个传感器数据:

const int dataPin = 2;
const int latchPin = 3;
const int clockPin = 4;

void setup() {
    
    
  pinMode(dataPin, INPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
}

void loop() {
    
    
  digitalWrite(latchPin, LOW);
  int sensorData = shiftIn(dataPin, clockPin, MSBFIRST); // 从移位寄存器接收传感器数据
  digitalWrite(latchPin, HIGH);

  // 处理传感器数据
  // ...

}

在此案例中,我们使用移位寄存器和shiftIn()函数从多个传感器接收数据。通过将传感器数据从移位寄存器的输出引脚接收到Arduino,可以同时读取多个传感器的数据。根据实际应用需求,可以在处理数据的部分对接收到的数据进行解析和处理。

案例三:与其他微控制器通信:

const int dataPin = 2;
const int clockPin = 3;

void setup() {
    
    
  pinMode(dataPin, INPUT);
  pinMode(clockPin, OUTPUT);
}

void loop() {
    
    
  int receivedData = shiftIn(dataPin, clockPin, MSBFIRST); // 从移位寄存器接收其他微控制器发送的数据

  // 处理接收到的数据
  // ...
}

在此案例中,我们使用移位寄存器和shiftIn()函数从其他微控制器接收数据。通过将其他微控制器发送的数据从移位寄存器的输出引脚接收到Arduino,可以实现与其他设备的并行数据传输或通信。根据实际应用需求,可以在处理数据的部分对接收到的数据进行解析和处理。

案例四:使用shiftIn()函数读取一个4x4矩阵键盘,从而获取用户按下的按键值。

// 定义四个常量ROW_PIN1-4,表示连接到键盘的行引脚
#define ROW_PIN1 2
#define ROW_PIN2 3
#define ROW_PIN3 4
#define ROW_PIN4 5

// 定义三个常量DATA_PIN、CLOCK_PIN、LATCH_PIN,表示分别连接到键盘的数据引脚、时钟引脚和锁存引脚
#define DATA_PIN 6
#define CLOCK_PIN 7
#define LATCH_PIN 8

// 定义一个数组keys,表示键盘上每个按键对应的字符
char keys[4][4] = {
    
    
  {
    
    '1', '2', '3', 'A'},
  {
    
    '4', '5', '6', 'B'},
  {
    
    '7', '8', '9', 'C'},
  {
    
    '*', '0', '#', 'D'}
};

void setup() {
    
    
  // 将ROW_PIN1-4四个引脚设为输出模式,并设为低电平
  pinMode(ROW_PIN1, OUTPUT);
  digitalWrite(ROW_PIN1, LOW);
  pinMode(ROW_PIN2, OUTPUT);
  digitalWrite(ROW_PIN2, LOW);
  pinMode(ROW_PIN3, OUTPUT);
  digitalWrite(ROW_PIN3, LOW);
  pinMode(ROW_PIN4, OUTPUT);
  digitalWrite(ROW_PIN4, LOW);

  // 将DATA_PIN、CLOCK_PIN、LATCH_PIN三个引脚设为输入模式,并启用上拉电阻
  pinMode(DATA_PIN, INPUT_PULLUP);
  pinMode(CLOCK_PIN, INPUT_PULLUP);
  pinMode(LATCH_PIN, INPUT_PULLUP);

  // 初始化串口通信,波特率为9600
  Serial.begin(9600);
}

void loop() {
    
    
  // 定义两个局部变量row和col,表示按键的行索引和列索引,并初始化为0
  int row = 0;
  int col = 0;

   // 循环遍历每一行
   for (row = 0; row < 4; row++) {
    
    
     // 根据当前行索引,将对应的行引脚设为高电平,其他行引脚设为低电平
     switch (row) {
    
    
       case 0:
         digitalWrite(ROW_PIN1, HIGH);
         digitalWrite(ROW_PIN2, LOW);
         digitalWrite(ROW_PIN3, LOW);
         digitalWrite(ROW_PIN4, LOW);
         break;
       case 1:
         digitalWrite(ROW_PIN1, LOW);
         digitalWrite(ROW_PIN2, HIGH);
         digitalWrite(ROW_PIN3, LOW);
         digitalWrite(ROW_PIN4, LOW);
         break;
       case 2:
         digitalWrite(ROW_PIN1, LOW);
         digitalWrite(ROW_PIN2, LOW);
         digitalWrite(ROW_PIN3, HIGH);
         digitalWrite(ROW_PIN4, LOW);
         break;
       case 3:
         digitalWrite(ROW_PIN1, LOW);
         digitalWrite(ROW_PIN2, LOW);
         digitalWrite(ROW_PIN3, LOW);
         digitalWrite(ROW_PIN4, HIGH);
         break;
     }

     // 等待10毫秒,让电路稳定
     delay(10);

     // 将LATCH_PIN引脚设为低电平,即开始读取数据
     digitalWrite(LATCH_PIN, LOW);

     // 调用shiftIn()函数,从DATA_PIN和CLOCK_PIN两个引脚输入一个字节的数据,顺序为最高位先入,返回值赋给col
     col = shiftIn(DATA_PIN, CLOCK_PIN, MSBFIRST);

     // 将LATCH_PIN引脚设为高电平,即结束读取数据
     digitalWrite(LATCH_PIN, HIGH);

     // 判断col的值是否为0,如果是,则表示没有按键被按下,继续下一行的循环
     if (col == 0) {
    
    
       continue;
     }

     // 定义一个局部变量key,表示按下的按键对应的字符,并初始化为空字符
     char key = '\0';

     // 判断col的值是否为1,如果是,则表示第0列的按键被按下,将keys数组中对应的字符赋给key
     if (col == 1) {
    
    
       key = keys[row][0];
     }

     // 判断col的值是否为2,如果是,则表示第1列的按键被按下,将keys数组中对应的字符赋给key
     if (col == 2) {
    
    
       key = keys[row][1];
     }

     // 判断col的值是否为4,如果是,则表示第2列的按键被按下,将keys数组中对应的字符赋给key
     if (col == 4) {
    
    
       key = keys[row][2];
     }

     // 判断col的值是否为8,如果是,则表示第3列的按键被按下,将keys数组中对应的字符赋给key
     if (col == 8) {
    
    
       key = keys[row][3];
     }

     // 通过串口输出按下的按键对应的字符
     Serial.println(key);

     // 等待500毫秒,防止抖动和重复读取
     delay(500);
   }
}

案例五:使用shiftIn()函数读取一个旋转编码器,从而获取旋转方向和角度。

// 定义三个常量DATA_PIN、CLOCK_PIN、LATCH_PIN,表示分别连接到编码器的数据引脚、时钟引脚和锁存引脚
#define DATA_PIN 10
#define CLOCK_PIN 11
#define LATCH_PIN 12

// 定义一个全局变量position,表示编码器的当前位置,并初始化为0
int position = 0;

void setup() {
    
    
  // 将DATA_PIN、CLOCK_PIN、LATCH_PIN三个引脚设为输入模式,并启用上拉电阻
  pinMode(DATA_PIN, INPUT_PULLUP);
  pinMode(CLOCK_PIN, INPUT_PULLUP);
  pinMode(LATCH_PIN, INPUT_PULLUP);

  // 初始化串口通信,波特率为9600
  Serial.begin(9600);
}

void loop() {
    
    
  // 定义两个局部变量oldState和newState,表示编码器的旧状态和新状态,并初始化为0
  byte oldState = 0;
  byte newState = 0;

   // 将LATCH_PIN引脚设为低电平,即开始读取数据
   digitalWrite(LATCH_PIN, LOW);

   // 调用shiftIn()函数,从DATA_PIN和CLOCK_PIN两个引脚输入一个字节的数据,顺序为最低位先入,返回值赋给oldState
   oldState = shiftIn(DATA_PIN, CLOCK_PIN, LSBFIRST);

   // 将LATCH_PIN引脚设为高电平,即结束读取数据
   digitalWrite(LATCH_PIN, HIGH);

   // 等待1毫秒
   delay(1);

   // 将LATCH_PIN引脚设为低电平,即开始读取数据
   digitalWrite(LATCH_PIN, LOW);

   // 调用shiftIn()函数,从DATA_PIN和CLOCK_PIN两个引脚输入一个字节的数据,顺序为最低位先入,返回值赋给newState
   newState = shiftIn(DATA_PIN, CLOCK_PIN, LSBFIRST);

   // 将LATCH_PIN引脚设为高电平,即结束读取数据
   digitalWrite(LATCH_PIN,

案例六:使用shiftIn()函数读取一个8位移位寄存器74HC165,从而扩展Arduino的数字输入引脚,可以用来读取更多的开关、传感器、信号等。

// 定义三个常量DATA_PIN、CLOCK_PIN、LATCH_PIN,表示分别连接到移位寄存器的数据引脚、时钟引脚和锁存引脚
#define DATA_PIN 2
#define CLOCK_PIN 3
#define LATCH_PIN 4

void setup() {
    
    
  // 将DATA_PIN、CLOCK_PIN、LATCH_PIN三个引脚设为输出模式
  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);

  // 初始化串口通信,波特率为9600
  Serial.begin(9600);
}

void loop() {
    
    
  // 定义一个局部变量data,表示要从移位寄存器读取的数据,并初始化为0
  byte data = 0;

   // 将LATCH_PIN引脚设为低电平,即开始读取数据
   digitalWrite(LATCH_PIN, LOW);

   // 调用shiftIn()函数,从DATA_PIN和CLOCK_PIN两个引脚输入一个字节的数据,顺序为最高位先入,返回值赋给data
   data = shiftIn(DATA_PIN, CLOCK_PIN, MSBFIRST);

   // 将LATCH_PIN引脚设为高电平,即结束读取数据
   digitalWrite(LATCH_PIN, HIGH);

   // 通过串口输出读取到的数据
   Serial.println(data, BIN);

   // 等待100毫秒
   delay(100);
}

这些案例展示了shiftIn()函数在不同应用中的使用方式,希望对你有所帮助。请注意根据具体情况调整代码和引脚配置。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41659040/article/details/132640625