本帖最后由 jinglixixi 于 2021-7-28 09:38 编辑
#申请原创#
Wio终端的外设配置较为丰富,为了便于介绍可将其分为数字I/O类、模拟I/O类及接口类。此外,还有片内的功能处理单元等。我们将按从易到难的顺序来展开介绍。 1.数字 I/O类 1)LED LED属于最简单的,也是最基本的输出型数字I/O类外设,通常以一个LED发光二极管加上一个1K左右的限流电阻即可。板载的LED电路如图1所示,它用2N7002来进行开关控制。由于LED的一端被接到了3.3V上,故只有在另一端接通GND时才发亮。
图1 LED电路 别看LED的电路简单,用它却可以判别系统是在运行工作。其通常的测试程序就是控制LED灯的闪烁。因为单是点亮或熄灭LED灯,并不能可靠地判别系统是在运行。 LED灯的闪烁程序如下: void setup() { pinMode(LED_BUILTIN, OUTPUT); }
void loop() { digitalWrite(LED_BUILTIN,HIGH); // 亮点LED delay(1000); // 延时1秒 digitalWrite(LED_BUILTIN,LOW); // 熄灭LED delay(1000); // 延时1秒 }
其中, pinMode()函数的功能是设置I/O口的工作模式,共含有3种模式,即INPUT、 OUTPUT及INPUT_PULLUP。这里,是将LED_BUILTIN引脚设置为输出端口。而delay()函数是一个毫秒级的延时函数,delay(1000)就是延时1秒钟。若采用更短的延时,可考虑微秒级的延时函数delayMicroseconds()。 函数digitalWrite()的作用是向指定的I/O引脚输出高低电位信号,以控制外设的状态变化。 经程序的编译上传,其运行效果如图2所示,其中的绿色LED为电源指示灯,而蓝色LED才是供用户测试的指示灯。
图2 运行效果 比较有意思的是,遍寻了相关的资料也没发现LED是与哪个引脚连接的,后来还是在其他的例程中发现了对其连接引脚的定义,其定义如下: #define LED_BUILTIN 13 // 蓝色LED闪烁 若认为这样的观察十分不便,可以考虑用Wio终端背面的扩展接口,该接口的引脚排列如图3所示。
图3 扩展接口 以使用引脚D0控制外观LED模块为例,其程序如下: void setup() { pinMode(D0,OUTPUT); } void loop() { digitalWrite(D0, HIGH); // 亮点LED delay(1000); // 延时1秒 digitalWrite(D0, LOW); // 熄灭LED delay(1000); // 延时1秒 }
经编译上传,其运行效果如图4所示。
图4 运行效果 注:有了这个测试经验,我们就可以随意地选用D0~D8的任意引脚来控制LED。 我们知道I/O口和A/D口是有区别的,但由图3可以发现D0和A0是共用同一个位置的,那么可以用A0来控制LED吗? 经测试验证,证明该用法是可以的,其程序和上传结果如图5所示。
图5 测试程序 2)蜂鸣器 板载的蜂鸣器是另一种I/O设备,是一种无源蜂鸣器,其电路原理图如图6所示。
图6 蜂鸣器电路 无源蜂鸣器与有源蜂鸣器的最大区别在于无源蜂鸣器需要外部提供信号源才能工作,而有源蜂鸣器却自带信号源能通电即工作。 但无源蜂鸣器的优势是在外部信号源的影响下它可以发出不同频率的蜂鸣声,甚至可以演奏出MIDI音乐。 发出蜂鸣声的程序如下: voidsetup() { pinMode(WIO_BUZZER, OUTPUT); }
void loop(){ analogWrite(WIO_BUZZER, 128); delay(1000); analogWrite(WIO_BUZZER, 0); delay(1000); } 其中WIO_BUZZER的引脚定义为: #defineWIO_BUZZER (12ul) 在程序中,函数analogWrite()的作用是向指定引脚输出指定PWM值。 由于脉冲信号是靠延时值的控制来产生的,故改变延时值的大小,可改变脉冲频率的高低,延时值约小,频率越高,声音越尖锐。 为了展示MIDI音乐的演奏能力,在例程中有一个演奏“天上星星亮晶晶,满天都是小星星。”的MIDI示例,它是通过频率及时长的设置来控制蜂鸣器发声演奏的效果。 为便于理解特在程序上添加了相应的注释,其具体内容如下: #define BUZZER_PIN WIO_BUZZER int length= 15; /* 音调值 */ charnotes[] = "ccggaagffeeddc "; // 音调 int beats[]= { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 }; // 节拍 int tempo =300; // 速度 void setup() { pinMode(BUZZER_PIN,OUTPUT); } void loop() { for(int i = 0; i < length; i++) { if(notes == ' ') { delay(beats* tempo); } else { playNote(notes, beats *tempo); } delay(tempo / 2); }
} voidplayTone(int tone, int duration) { for (long i = 0; i < duration * 1000L; i+= tone * 2) { digitalWrite(BUZZER_PIN, HIGH); delayMicroseconds(tone); digitalWrite(BUZZER_PIN, LOW); delayMicroseconds(tone); } } void playNote(char note, int duration) { char names[] = { 'c', 'd', 'e', 'f', 'g','a', 'b', 'C' }; int tones[] = { 1915, 1700, 1519, 1432,1275, 1136, 1014, 956 }; for (int i = 0; i < 8; i++) { if (names == note) { playTone(tones, duration); } } } 感兴趣的话,我们可以将自己喜欢的曲谱,加以适当的数据转换即可用来播放了。 3)按键 按键属于最简单的且最基本的输入型数字I/O类外设,通常仅是一个机械按键。板载的按键电路见图7所示,共有3个按键,并在电路中串入了4.7K的电阻作为保护。 因此按键的常规输出状态为高电平,当按键按下时则输出低电平。
图7 按键电路 以按键控制LED的程序如下: void setup() { pinMode(WIO_KEY_A, INPUT_PULLUP); pinMode(WIO_KEY_B, INPUT_PULLUP); pinMode(D0,OUTPUT); }
void loop() { if (digitalRead(WIO_KEY_A) ==LOW) { digitalWrite(D0, HIGH); // 亮点LED } else if (digitalRead(WIO_KEY_B)== LOW) { digitalWrite(D0,LOW); // 熄灭LED } delay(200); } 在程序中,函数digitalRead ()的作用是读取指定引脚状态,这里是用来读取按键的状态,以便判别其是否被按下。 其中3个按键的引脚定义为: #defineWIO_KEY_A (28ul) #defineWIO_KEY_B (29ul) #defineWIO_KEY_C (30ul)
在程序中,是将2个按键所占用的引脚设置为上拉式输入模式,将D0占用的引脚设为输出模式。 经编译上传,在按下A键时LED模块被点亮,在按下B键时则LED模块被熄灭。 其实,由于在按键电路中已添加了上拉电阻,故对于2个按键将其设置为输入模式也是能正常工作的,否则是必须要设置上拉式输入的。 将2个按设置为输入模式的语句为: pinMode(WIO_KEY_A, INPUT_PULLUP); pinMode(WIO_KEY_B, INPUT_PULLUP);
4)方向键 在Wio终端配有一个方向键,其作用相当于一个游戏杆,可以进行4个方向的控制,其电路如图8所示。在每个按键的电路中串入了100K的电阻作为保护,其常规输出状态为高电平,在按键按下时则输出低电平。
图8 方向键电路 测试方向键的程序如下: void setup() { Serial.begin(115200); pinMode(WIO_5S_UP, INPUT_PULLUP); pinMode(WIO_5S_DOWN,INPUT_PULLUP); pinMode(WIO_5S_LEFT,INPUT_PULLUP); pinMode(WIO_5S_RIGHT,INPUT_PULLUP); pinMode(WIO_5S_PRESS,INPUT_PULLUP); }
void loop() { if (digitalRead(WIO_5S_UP) ==LOW) { Serial.println("5 WayUp"); } else if (digitalRead(WIO_5S_DOWN)== LOW) { Serial.println("5 WayDown"); } else if (digitalRead(WIO_5S_LEFT)== LOW) { Serial.println("5 WayLeft"); } else if(digitalRead(WIO_5S_RIGHT) == LOW) { Serial.println("5 WayRight"); } else if(digitalRead(WIO_5S_PRESS) == LOW) { Serial.println("5 WayPress"); } delay(200); } 在程序中,使用了供调试而设置的串行通讯功能,其中函数Serial.begin()用于启动串行通讯并将波特率设置为115200bps。函数Serial.println()用于输出测试信息。 该方向键的引脚定义为: #defineWIO_5S_UP (31ul) #defineWIO_5S_LEFT (32ul) #defineWIO_5S_RIGHT (33ul) #defineWIO_5S_DOWN (34ul) #defineWIO_5S_PRESS (35ul) 经编译上传,通过串口监视器可见到按键的检测结果如图9所示。
图9 测试结果 5)风扇控制 风扇也可视为一种输出类I/O设备,通过供电情况的变化来控制其转动与否,甚至可以PWM方式来控制其转速的快慢。 在D0引脚外接风扇控制端的情况下,按键控制风扇的程序如下: void setup() { pinMode(WIO_KEY_A, INPUT_PULLUP); pinMode(WIO_KEY_B, INPUT_PULLUP); pinMode(D0,OUTPUT); }
void loop() { if (digitalRead(WIO_KEY_A) ==LOW) { digitalWrite(D0, HIGH); // 转动 } else if (digitalRead(WIO_KEY_B)== LOW) { digitalWrite(D0,LOW); // 停止 } delay(200); }
经编译上传,风扇的控制效果如图10所示。
图10 风扇控制 由于函数analogWrite()具有向指定引脚输出PWM的功能,故可以用它轻松地实现PWM调节功能。 以按键控制转速的程序如下: void setup() { pinMode(WIO_KEY_A, INPUT); pinMode(WIO_KEY_B, INPUT); pinMode(WIO_KEY_C, INPUT); pinMode(D0, OUTPUT); }
void loop() { if (digitalRead(WIO_KEY_A) == LOW) { analogWrite(D0, 230); // 一档 } if (digitalRead(WIO_KEY_B) == LOW) { analogWrite(D0, 160); // 二挡 } if (digitalRead(WIO_KEY_C) == LOW) { analogWrite(D0, 100); // 三挡 } delay(200); }
难以想象吧,较复杂的PWM调节问题在这里只需一条语句即可解决! 那Wio终端可以提供多少个PWM通道呢?答案是可以提供5个,即PWM0~PWM4。 限于篇幅,本次仅介绍了简单的数字I/O类外设及使用,下次再详细介绍模拟I/O类外设及其使用。 |