大数跨境
0
0

【红外遥控数码管】基于Mind+ Ardunio入门教程15

【红外遥控数码管】基于Mind+ Ardunio入门教程15 蘑菇云创造
2020-01-22
1
导读:Mind+Arduino入门教程系列的完结篇!

点击上方“蘑菇云创造”可以关注我们哦


数码管,常见的用来显示数字的,比如像计算器。在本实验之前我们先来了解一下数码管是如何工作的。数码管,其实也算是LED中的一种。数码管的每一段,都是一个独立的LED,通过数字引脚来控制相应段的亮灭就能达到显示数字的效果。下面让我们通过实验的方式来感受一下数码管的神奇之处吧!


所需元件

■ 1× 八段数码管  

■ 8× 220欧电阻  




硬件连接

按下图连线图连接,注意数码管各段所对应的引脚。右边引脚说明图上为什么画这么几个箭头呢?个人觉得,这样看起来更方便。可以给你作为参考。我们从上面一排看,红色箭头的方向,从右往左,b→a→f→g的顺序正好对应下面红色箭头逆时针顺序b→a→f→g。蓝色箭头也是表达的同样的意思。


我还特意在连接图上,对数码管所连接的引脚做了标示。这样就能更清楚的知道哪个引脚控制哪一段了。这8个电阻同样是起限流的作用。


图 15-1数码管显示连线图


代码编程

样例代码15-1:

 //项目15 – 数码管显示  

void setup(){  

   for(int pin = 2 ; pin <= 9 ; pin++){   // 设置数字引脚2~9为输出模式  

    pinMode(pin, OUTPUT);  

       digitalWrite(pin, HIGH);  

   }  

}  


void loop() {   

    // 显示数字0            

int n0[8]={0,0,0,1,0,0,0,1};   

//数字引脚2~9依次按数组n0[8]中的数据显示   

for(int pin = 2; pin <= 9 ; pin++){   

      digitalWrite(pin,n0[pin-2]);  

    }  

    delay(500);  


  // 显示数字1 

int n1[8]={0,1,1,1,1,1,0,1};  

// 数字引脚2~9依次按数组n1[8]中的数据显示

    for(int pin = 2; pin <= 9 ; pin++){  

        digitalWrite(pin,n1[pin-2]);  

    }  

    delay(500);  


  // 显示数字2 

int n2[8]={0,0,1,0,0,0,1,1};  

// 数字引脚2~9依次按数组n2[8]中的数据显示

    for(int pin = 2; pin <= 9 ; pin++){  

       digitalWrite(pin,n2[pin-2]);  

    }  

delay(500);    


 // 显示数字3  

int n3[8]={0,0,1,0,1,0,0,1};  

// 数字引脚2~9依次按数组n3[8]中的数据显示

    for(int pin = 2; pin <= 9 ; pin++){  

        digitalWrite(pin,n3[pin-2]);  

    }  

    delay(500);    


// 显示数字4 

int n4[8]={0,1,0,0,1,1,0,1};  

// 数字引脚2~9依次按数组n4[8]中的数据显示

    for(int pin = 2; pin <= 9 ; pin++){  

        digitalWrite(pin,n4[pin-2]);  

    }  

    delay(500);    


// 显示数字5 

int n5[8]={1,0,0,0,1,0,0,1};  

// 数字引脚2~9依次按数组n5[8]中的数据显示  

    for(int pin = 2; pin <= 9 ; pin++){  

        digitalWrite(pin,n5[pin-2]);  

    }  

    delay(500);   


// 显示数字6

int n6[8]={1,0,0,0,0,0,0,1};  

// 数字引脚2~9依次按数组n6[8]中的数据显示 

    for(int pin = 2; pin <= 9 ; pin++){  

        digitalWrite(pin,n6[pin-2]);  

    }  

    delay(500);   


// 显示数字7  

int n7[8]={0,0,1,1,1,1,0,1};  

// 数字引脚2~9依次按数组n7[8]中的数据显示

    for(int pin = 2; pin <= 9 ; pin++){  

         digitalWrite(pin,n7[pin-2]);  

    }  

    delay(500);   


 // 显示数字8

int n8[8]={0,0,0,0,0,0,0,1};  

// 数字引脚2~9依次按数组n8[8]中的数据显示 

    for(int pin = 2; pin <= 9 ; pin++){  

        digitalWrite(pin,n8[pin-2]);  

    }  

    delay(500);   


  // 显示数字9  

int n9[8]={0,0,0,0,1,1,0,1};  

// 数字引脚2~9依次按数组n9[8]中的数据显示 

    for(int pin = 2; pin <= 9 ; pin++){  

        digitalWrite(pin,n9[pin-2]);  

    }  

    delay(500);  


完成下载后,数码管就会循环显示0~9的数字。由于要看懂代码的话,首先需要了解数码管的构造,所以我们这回先说硬件部分。


硬件回顾

数码管

数码管其实就是一个前面介绍的LED的组合体,这个组合体包含8个led,所以也称之为八段数码管。说白了就八个灯。哪八段?不用多说了吧!a到g以及小数点DP。其实用法和前面说的LED也是一样的,每段都是一个发光二极管,分别用8个数字口来控制它们的亮灭,通过不同段的显示,就能组成0~9的数字。比如,我们让b、a、f、e、d、c亮起的话,就能显示一个数字“0”了。


下图15-2是引脚说明图,不陌生了吧!在前面硬件连接的时候,已经看到过一次了。


这里,b→a→f→g→e→d→c→DP分别连接到Arduino数字引脚2~9。


图15-2 引脚说明图


数码管的共阴共阳在使用上有什么区别


共阳数码管,它们公共端接5V,那在代码中,控制另一端的数字引脚为LOW,这样才能让数码管点亮。如果是共阴数码管,公共端接GND,在代码中中,控制另一端数字引脚为HIGH,才让数码管点亮。


所以,共阴共阳只是在代码上要稍作修改。我们这里选用的是共阳数码管。了解了硬件,我们来看看软件部分。


代码学习

硬件部分我们已经说过,数码管需要接到8个数字引脚,所以在一开始,需要定义8个数字引脚作为输出。这次我们用一个for循环来完成这8个数字引脚的设置。数码管b、a、f、g、e、d、c、DP分别和Arduino数字引脚2~9对应。

  for(int pin = 2 ; pin <= 9 ; pin++){   // 设置数字引脚2~9为输出模式  

       pinMode(pin, OUTPUT);  

       digitalWrite(pin, HIGH);  

  }  


从引脚2开始,一直循环到引脚9,都设为OUTPUT模式,初始化为HIGH。前面说过,共阳的话,设置HIGH,不被点亮,所以开始先不点亮数码管。(当然,你一个一个引脚分开设置输出模式也是不会错的,只是会让代码显得很冗长。)


好了,到了主函数,要分别显示0~9的数字。是不是觉得代码大部分都是相似的。所以,我们只要看明白如何显示数字0,那整段代码就都迎刃而解了。


数组

int n0[8]={0,0,0,1,0,0,0,1};   

这里我们要引入一个数组的概念。数组是一个变量的集合,可以通过索引号来找到数组中的元素。在我们的程序中,声明了一个int型的数组。并取名为n0。之后用8个数值来初始化这个数组。那如何获得数组中的元素呢?你只需要简单的指出这个元素的索引号。数组是从0开始索引的,这意味着数组中的第一个元素的索引号为0而不是1,因此数组中的8个元素的索引号是0~7。在这里元素4,对应索引号为3(n0[3]),值为1。元素8(索引号7,n0[7])的值为1。


声明中n0[8]的方括号中的8代表有8个元素。

定义完数组后,进入又一个for循环。

for(int pin = 2; pin <= 9 ; pin++){   

digitalWrite(pin,n0[pin-2]);  

}  


这个for循环是给2~9引脚写入状态值,也就是HIGH还是LOW,digitalWrite函数中写入HIGH的另一种形式就是写入“1”,LOW则可以写为“0”。我们通过数组索引的方式给2~9引脚赋值。


比如当pin=2,代入n0[pin-2]中,对应为n0[0],n0[0]意思是获得数组的第一个元素,为0。完成了引脚2置低(LOW)。我们前面说了,共阳的数码管,置低(LOW)的话,是被点亮,所以,b端被点亮了。循环到pin=3,a段被点亮,。循环到pin=4,f段被点亮,依次类推……


整个循环过程如下:

pin=2 à n0[0] =0 à digitalWrite(2,0) à b段点亮

pin=3 à n0[1] =0 à digitalWrite(3,0) à a段点亮

pin=4 à n0[2] =0 à digitalWrite(4,0) à f 段点亮

pin=5 à n0[3] =1 à digitalWrite(5,1) à g段不点亮

pin=6 à n0[4] =0 à digitalWrite(6,0) à e段点亮

pin=7 à n0[5] =0 à digitalWrite(7,0) à d段点亮

pin=8 à n0[6] =0 à digitalWrite(8,0) à c段点亮

pin=9 à n0[7] =1 à digitalWrite(9,1) à DP段不点亮


这样就完成了显示数字“0”了。同样用数组的方法显示数字1~9。自己动手画一下,哪几段亮,哪几段不亮就一目了然了。


如果代码1弄明白后,我们要教大家一种更简单的方法。


代码编程2

样例程序15-2

 //项目15 – 数码管数字显示 

int number[10][8] =   

{  

  {0,0,0,1,0,0,0,1},   //显示0

  {0,1,1,1,1,1,0,1},   //显示1  

  {0,0,1,0,0,0,1,1},   //显示2  

  {0,0,1,0,1,0,0,1},   //显示3

  {0,1,0,0,1,1,0,1},   //显示4  

  {1,0,0,0,1,0,0,1},   //显示5 

  {1,0,0,0,0,0,0,1},   //显示6  

  {0,0,1,1,1,1,0,1},   //显示7

  {0,0,0,0,0,0,0,1},   //显示8  

  {0,0,0,0,1,1,0,1}    //显示9

};  

void numberShow(int i){   //该该函数用来显示数字

    for(int pin = 2; pin <= 9 ; pin++){  

       digitalWrite(pin, number[i][pin - 2]);  

    }  

}  

void setup(){  

  for(int pin = 2 ; pin <= 9 ; pin++){    // 设置数字引脚2~9为输出模式  

      pinMode(pin, OUTPUT);  

      digitalWrite(pin, HIGH);  

  }  

}  


void loop() {        

    for(int j = 0; j <= 9 ; j++){    

        numberShow(j);   //调用numberShow()函数,显示0~9  

        delay(500);  

    }  

}  


代码学习

对比一下代码1,能发现明显的区别在哪里了吗?代码1中,我们创建了10个一维数组,代码2只需要创建一个二维数组就全部搞定了。不要被什么一维、二维数组的名字给吓唬到,其实用法一样的。

 

图15-3 数组关系图


通过上面这个图,元素、一维数组、二维数组之间的关系就一目了然了。一维数组由元素组成,而二维数组则是由一个个一维数组组成的,关系就是那么简单。


代码1中,分别用10个数组,每个数组有8个元素,每个元素依次对应到数码管b~DP引脚状态值,这样就能在数码管上反映为0~9的数字显示。


而我们现在则是把前面散开的10个一维数组整合到一起,变为一个二维数组。同样通过索引的方式来找到这些元素。但,还是不要忘了索引号也是从0开始的!前面的方括号写入的是只是元素个数。


看一下代码:

int number[10][8] =   

{  

  {0,0,0,1,0,0,0,1},   //显示0

  {0,1,1,1,1,1,0,1},   //显示1

  {0,0,1,0,0,0,1,1},   //显示2 

  {0,0,1,0,1,0,0,1},   //显示3

  {0,1,0,0,1,1,0,1},   //显示4

  {1,0,0,0,1,0,0,1},   //显示5  

  {1,0,0,0,0,0,0,1},   //显示6

  {0,0,1,1,1,1,0,1},   //显示7

  {0,0,0,0,0,0,0,1},   //显示8

  {0,0,0,0,1,1,0,1}    //显示9

};  


这就是一个二维数组。索引号从0开始,如果让你找number[0][0],能找到是哪个数吗?就是二维数组中第1行的第1个数,为0。number[9][7]也就是第10行的第8个数,为1。


void numberShow(int i){         //该该函数用来显示数字  

    for(int pin = 2; pin <= 9 ; pin++){  

       digitalWrite(pin, number[i][pin - 2]);  

    }  

}  



void loop() {        

    for(int j = 0; j <= 9 ; j++){    

        numberShow(j);       //调用numberShow()函数,显示0~9  

        delay(500);  

    }  

}  


上面这两段代码我们整合在一起看,loop()主函数中,for循环让变量j在0~9循环,j每赋一次值,numberShow()函数就要运行一次。


numberShow()函数整个运行过程如下:

程序一开始j=0,numberShow(j)为numberShow(0),跳回到上面的numberShow()函数,i现在的值就为0了,pin初始值为2,所以digitalWrite()现在值为digitalWrite(2,number[0][0]),回到数组number[10][8]中找到number[0][0]对应的值,为0。此时,digitalWrite(2,0),代表引脚2被置LOW,引脚2对应的b段点亮(共阳数码管置LOW才被点亮)。之后再是循环pin=3,pin=4,……,一直到pin=9整个for循环才结束,也代表数组的第一行的8个元素全被运行了一遍,最终显示一个数字“0”。


回顾一下代码1是如何显示一个数字“0”的:

// 显示数字0 

int n0[8]={0,0,0,1,0,0,0,1};   

//数字引脚2~9依次按数组n0[8]中的数据显示 

for(int pin = 2; pin <= 9 ; pin++){   

   digitalWrite(pin,n0[pin-2]);  

    }  


原理是一样的,通过给引脚2~9循环赋值,控制数码管b~DP段亮灭,就能显示出一个我们想要的数字。


numberShow(0)循环完后,再次回到loop()中的for函数:

j=1  numberShow(1)  i=1  number[1][pin-2]  显示数字1

j=2  numberShow(2)  i=2  number[2][pin-2]  显示数字2

j=3  numberShow(3)  i=3  number[3][pin-2]  显示数字3

……

j=9  numberShow(9)  i=9  number[9][pin-2]  显示数字9


好了,这就是整段代码的分析过程,好好体会一下一维数组和二维数组的区别,以及整段代码如何巧妙运行的。


了解了数码管和红外接收管各自的工作原理后,我们需要把这两者结合起来,看看红外接收管和数码管结合能迸发出怎样的火花呢?想到了吗?遥控数码管!Arduino控制器把红外接收管从Mini遥控器那儿接到的信号,经处理传达给数码管。让Mini遥控器上0~9对应在数码管上显示0~9,除此之外,还有递减,递增的功能。


所需元件

■ 1×  八段数码管      

■ 1×  红外接收管    

■ 1× Mini遥控器    

■ 8×  220欧电阻    

 


图15-4红外遥控数码管连线图

 

代码编程

在输入代码的过程中,结合前面的项目十四和十五,看看整段代码是如何把这两者整合的,程序中是如何处理把红外接收管接到的信号,再转变为数码管的显示的。


样例程序15-3

 //项目十五 - 红外遥控数码管  

#include <DFRobot_IRremote.h>  //调用IRremote.h库

int RECV_PIN = 2;   //定义RECV_PIN变量为2 

IRremote_Receive remoteReceive_2;  //声明对象 


String results;   //定义results变量为红外结果存放位置

int currentNumber = 0;   //该变量用于存放当前数字


String codes[12]=   //该数组用来存放红外遥控器发出的红外码  

{  

   "FD30CF","FD08F7",               // 0 ,1

   "FD8877","FD48B7",               // 2 ,3

   "FD28D7","FDA857",               // 4 ,5  

   "FD6897","FD18E7",               // 6 ,7  

   "FD9867","FD58A7",               // 8 ,9

   "FD20DF","FD609F",               // + ,-  

};  


int number[10][8] =   //该数组用来存放数码管显示的数字  

{  

  {0,0,0,1,0,0,0,1},//0  

  {0,1,1,1,1,1,0,1},//1  

  {0,0,1,0,0,0,1,1},//2  

  {0,0,1,0,1,0,0,1},//3  

  {0,1,0,0,1,1,0,1},//4  

  {1,0,0,0,1,0,0,1},//5  

  {1,0,0,0,0,0,0,1},//6  

  {0,0,1,1,1,1,0,1},//7  

  {0,0,0,0,0,0,0,1},//8  

  {0,0,0,0,1,1,0,1} //9  

};  


void numberShow(int i) {   //该函数用来让数码管显示数字  

  for(int pin = 3; pin <= 10 ; pin++){  

     digitalWrite(pin, number[i][pin - 3]);  

  }  

}  


void setup(){  

   Serial.begin(9600);  //设置波特率为9600

    remoteReceive_2.begin(RECV_PIN); //启动红外解码  


   for(int pin = 3 ; pin <= 10 ; pin++){   //设置数字引脚2~9为输出模式  

       pinMode(pin, OUTPUT);  

       digitalWrite(pin, HIGH);  

   }  

}  


void loop() {  

//判断是否接收到解码数据,把接收到的数据存储在变量results中  

    results = (remoteReceive_2.getIrCommand());  

   if (results !="0") {  

      for(int i = 0; i <= 11; i++){  

  //判断是否接收到0~9按键的红外码

         if(results == codes[i]&& i <= 9){  

               numberShow(i);   //在数码管上对应显示0~9

               currentNumber = i;  //把当前显示的值赋给变量currentNumber  

               Serial.println(i);  

               break;                

         }  


  // 判断是否接收到递减的红外码,并且当前值不为0

         else if(results == codes[10]&& currentNumber != 0){  

               currentNumber--;   //当前值递减 

               numberShow(currentNumber);  //数码管显示递减后的值  

               Serial.println(currentNumber); //串口输出递减后的值  

               break;          

         }  


  //判断是否接收到递增的红外码,并且当前值不为9 

         else if(results == codes[11]&& currentNumber != 9){  

               currentNumber++;    //当前值递增

               numberShow(currentNumber);     //数码管显示递增后的值  

               Serial.println(currentNumber); //串口输出递增后的值  

               break;              

         }  

     }   


   Serial.println(results);  //串口监视器查看红外码


  }  


 

图15-5遥控数按键说明

 

下载完代码后,尝试按下上图15-5指出部分的按钮,看看是数码管是个怎样的变化。


代码学习

int currentNumber = 0;   //该变量用于存放当前数字

在这里,我们多定义了一个变量currentNumber,通过名字应该就可以看出来含义了吧。这个变量的作用是,用来存储当前的数字,数字递增递减是能找到对应的参照点。


同样用数组的方式来存放这些红外码。long是变量的类型,如果你还想用遥控器上的其他按钮来控制做一些其他事情的话,把红外码替换掉就好了。


String codes[12]=  //该数组用来存放红外遥控器发出的红外码  

{  

   ”FD30CF”,”FD08F7”,               // 0 ,1 

   ”FD8877”,”FD48B7”,               // 2 ,3 

   ”FD28D7”,”FDA857”,               // 4 ,5 

   ”FD6897”,”FD18E7”,               // 6 ,7 

   ”FD9867”,”FD58A7”,               // 8 ,9  

   ”FD20DF”,”FD609F”,               // + ,- 

};  


紧接着是,一个二维数组number[10][8]的定义。我们在数码管那一章节已有说明了,通过调用数组的元素,把这些元素的值依次赋给数码管显示段的控制引脚,并在numberShow()函数中得以实现数码管数字显示。


setup()函数中,仍然是波特率设置,启动红外解码,数字引脚模式设置等,这些常规设置。


到了主函数loop(),一开始还是先判断是否接收到红外码,并把接收到的数据存储在变量results中。


  if (results !="0") {  


一旦接收到数据后,程序就要做两件事。第一件事,判断是哪个红外码,也就能对应找到是哪个按键按下的。第二件事,找到对应按扭后,让数码管干什么事?让我们接着看看程序是如何完成这两件事的。


第一件事:

会有三种情况需要判断,第一种情况,按遥控器0~9时,数码管显示数字0~9。第二种情况,每按下“后退”键,数字在原有基础上递减一位,直到减到0为止。第三种情况,每按下“前进”键,数字在原有基础上增一位,直到增到9为止。


对这三种情况进行判断,这里呢,同样用到了if语句,与以往有所不同的,我们选择用 if…else if。if…else和if…else if的区别在哪儿?区别在于else if后面需要接判断表达式,else不需要判断表达式。然而,不管是else还是else if都是依附于if语句存在的,不能独立使用。


回到代码中,这就是以下三种情况:

if(results == codes[i]&& i <= 9){  

if(results == codes[10]&& currentNumber != 0){  

if(results == codes[11]&& currentNumber != 9){  


第一个if判断的是第一种情况,显示数字0~9。判断条件就是接收到的数据results.value的值是不是数组中codes[0]~codes[9]的红外码。


第二个if判断的是第二种情况,是否接到“后退”键指令,也就是code[10]= 0xFD20DF,并且当前显示数字不为0。


第三个if判断的是第三种情况,是否接到“前进”键指令,也就是code[11]= 0xFDA857,并且当前显示数字不为9。


还有一个问题——如何找到数组中的元素呢?所以,就需要在if判断前设置一个for循环,让变量i一直在0~11之间循环。


第一件事判断是哪个红外码完成后,开始执行第二件事。就是每个if语句后,都有相应的执行代码,其中有一处需要进行讲解。


break语句

break语句用于跳出循环。在判断是否为数字0-9、“后退”键、或“前进”键,且执行完相应的显示后,使用break语句,能够跳出当前循环,不再向下执行代码。这样做是为了实现,在一次for循环中只执行一次数码管显示的刷新,排除干扰造成的误显示,并且能够提升程序执行的效率。



整段代码就讲完了,这段代码应该是所以项目中最复杂的代码,可以一开始不能完全看明白,不过没关系,实践出真知,通过一遍遍不断的尝试,相信你总有一天能明白的。


课后作业

通过这个遥控项目,DIY一个你的遥控作品吧!比如简单的会动的小人,结合我们前面的舵机,通过遥控器上不同的按键,让舵机转动不同的角度,感觉随你的控制转动,发挥你的想象做出更多Arduino作品吧!



———————  正文完    ———————

 



教育的目的是为了培养学生协作能力、沟通能力、批判思维以及创造力,其中最核心的是创造力,蘑菇云创客教育作为国内为数不多的一站式创客教育服务供应商旨在培养孩子的创造力。

为让学生们在课堂上学习到的知识更好地连接现实世界,蘑菇云将指导学校规划、建立、运营自己的创客空间。并根据学生年龄段的不同,在设计与布局上进行了区分



小学创客空间注重趣味性,

强调互动场景;

初中创客空间注重实用性,

强调学习场景;

高中创客空间注重技术性,

强调应用场景;



 

在内容上, 蘑菇云和国内一线创客名师联手,编纂了一系列适合国内创客教育的教材。并拥有一套完整的创客教育课程体系,包括课程内容及教具,课程培训,技术答疑。同样根据学生年龄段的不同,在课程分类与设计上也会有所区别。

小学通过游戏化和体验化的方式来开展,要以“玩中学”为主。

初中引导学生在实际动手过程中进行探究式学习,促进“做中学”。

高中基于问题和设计的学习,需要教师为学生创设相关的真实情境,使高中生在“思中学”。






推荐阅读:

【 红外遥控灯】基于Mind+ Ardunio入门教程14

【 自制风扇】基于Mind+ Ardunio入门教程13

【 彩灯调光台】基于Mind+ Ardunio入门教程12

【可控舵机】基于Mind+ Ardunio入门教程11

【舵机初动】基于Mind+ Ardunio入门教程10

【感光灯】基于Mind+ Ardunio入门教程09

【震动传感器】基于Mind+ Ardunio入门教程08

【温度报警器】基于Mind+Arduino入门教程07

【报警器】基于mind+Arduino入门教程06

【政策解读】探讨智能时代下的“教与学”改革

【炫彩 RGB LED】基于Mind+Arduino入门教程05

【呼吸灯】基于Mind+Arduino入门教程04

【互动交通信号灯】基于Mind+Arduino入门教程03

【S.O.S求救信号】基于Mind+ Ardunio入门教程02

【LED闪烁】基于Mind+Arduino入门教程01

【初识Arduino & Mind+】基于mind+ Arduino入门教程00



我知道你在看

【声明】内容源于网络
0
0
蘑菇云创造
蘑菇云是DFRobot旗下专注于AI人工智能、创客、STEAM、劳动教育的科技创新教育品牌;以为中国培养下一代科技创新人才为使命,为学校提供k12全龄段科技创新教育解决方案。
内容 969
粉丝 0
蘑菇云创造 蘑菇云是DFRobot旗下专注于AI人工智能、创客、STEAM、劳动教育的科技创新教育品牌;以为中国培养下一代科技创新人才为使命,为学校提供k12全龄段科技创新教育解决方案。
总阅读2.0k
粉丝0
内容969