Linkit 系列博文:
联发科Linkit 7688 (一) 上手及在Mac下搭建OpenWrt交叉编译环境,C语言编译Hello,World
联发科Linkit 7688 (二)GPIO基本操作与C语言编程
联发科Linkit 7688 DUO(三): 通过 Arduino 控制外设和传感器
Linkit 7688 DUO(四): 接上各种Arduino传感器和模块——基础篇
Linkit 7688 DUO(五) 接上各种Arduino传感器和模块—扩展篇
Linkit 7688 DUO(六) 加入MQTT物联网协议
前一篇讲了 Linkit 7688DUO开发板接上一些典型Arduino传感器的作法。
本篇,我们要为开发板接上更多的Arduino的传感器和模块了。
一、 前篇概要:
Linkit 7688 DUO开发板上有两个处理器芯片。
一片是 Linkit 7688, 主处理器
一片是 ATmega32U4, 这是Arduino的处理芯片,提供Arduino编程接口,用于控制传感器外设等
两个处理器通过内部串口相连。
Linkit 7688 DUO开发板上, 从ATmega32U4管脚接出的众多管脚,其中:D0-D13 为数字IO口, A0-A5为模拟IO口, S0-S3为串口设备SPI管脚
前篇,我们练习了在开发板上接入LED、开关、继电器、蜂鸣器等, 并制定了一个两个处理器串口通讯的消息协议。
在开发中, 要写两个程序:
1, 写一个Arduino程序, 写入ATmega32U4中。Arduino程序通过串口接收主处理器Linkit 7688送来的消息, 执行相应动作。
2, 写一个主程序,写入Linkit7688中。 主程序通过串口向 ATmega32U4 发送消息
二、温度湿度传感器 (Temperature & Humidity Sensor), 见下图
模块有三个管脚,其中 (图中右侧)标注‘-’的管脚接地(GND), 图中标注"S”的管脚接 信号(数字I/O), 中间的管脚接5V
这种是DHT11传感器, 是便宜货,能粗略地测温度、湿度
用在根杜邦线把模块接到开发板上,其中“-”脚接GND, "S"脚接D3, 中间管脚接5V
要在Arduino中使用DHT传感器,首先要安装 DHT库。
新建一个名为“DHT”的文件夹, 下载 dht.cpp 和 dht.h 两个文件,放入DHT文件夹 ,然后再将DHT文件夹复制到ardunio的库文件夹。
在MAC OS的操作:右键点击Arduino IDE的图标出菜单,选菜单项“显示包内容”, 进入 “Contents/Java/libraries"(这个文件夹就是ardunio的库文件夹了)
重启Arduino IDE, 则可在 "项目“-> include library 中打开DHT库了。
编一个Arduino程序如下:采用消息协议,当收到消息,则测量温度、湿度,并发送结果消息到主控板。
注意:程序要用到 dht库(请确保已装好)。
注意:程序将使用message_protocol.ino模块,要把 message_protocol.ino 这个文件放在本Arduino项目文件夹中, 然后重新打开项目即可包含此模块
#include <dht.h> #define COMMAND_TEMPERATURE 't' #define ACK_TEMPERATURE 'u' dht DHT; // dht object int pinDHT = 3; //pin connects to DHT Temperature/Humidity sensor void setup() { MessageInit(57600); //init message pinMode(pinDHT, INPUT); //set pinDHT INPUT } void getTemperature() { //Serial.println("in"); int ret = DHT.read11(pinDHT); switch (ret) { case 0: // ok { unsigned char buf[3]; buf[0] = (int)DHT.temperature; //integer part of temperature buf[1] = (int)((DHT.temperature - (int)DHT.temperature)*10); //one digit frac buf[2] = (int)DHT.humidity; //integer part of humidity MessageSend( ACK_TEMPERATURE, buf, 3 ); //send ACK_TEMPERATURE message back return; } case -1: break; //checksum error case -2: break; //Time out error default: break; //unknown error } MessageNAK( COMMAND_TEMPERATURE ); //send NAK message back } void loop() { if ( MessageReceive() ) { if ( MessageCommand() == COMMAND_TEMPERATURE ) { getTemperature(); } } }
Arduino程序等待 COMMAND_TEMPERATURE消息, 调用getTemperature()函数 ,该函数中调用 DHT.read11()读取传感器数据。如果读取数据成功,返回 ACK_TEMPERATURE消息,消息内容三个字节,第一个字节是温度的整数位、第二个字节是温度的小数第1位。第三字节是湿度.
编一个C语言主程序 temperature_test.c,采用消息协议,向Arduino发送COMMAND_TEMPERATURE消息送到,等待Arduino返回 ACK_TEMPERATURE消息, 读取其中的温度和湿度值打印出来。
注:项目中要使用到 串口函数模块serial.c 和 消息协议模块 message_protocol.c
#include <stdio.h> #include <unistd.h> #include <memory.h> #include "serial.h" #include "message_protocol.h" #define COMMAND_TEMPERATURE 't' #define ACK_TEMPERATURE 'u' //wait ACK_TEMPERATURE message from Arduino int wait_ack_message(message_t * msg) { int times, ret; times = 0; while ( (ret = message_receive(msg)) != 1 && times++ < 30) { usleep(30*1000); } if ( ret == 1 ) { if ( message_command(msg) == ACK_TEMPERATURE ) { char temperature = (char)message_data(msg, 0); printf("Temperature: %d.%d, Humidity:%d\n", temperature, message_data(msg, 1), message_data(msg, 2)); fflush(stdout); return 1; } } return 0; } int main(int argc, char **argv) { int fd; //file descriptor of serial port message_t msg; //message object fd = serial_open(0, 57600);//open serial port 0, /etc/ttyS0 if ( fd > 0 ) { message_init( &msg, fd, 57600 ); //init message with fd, set baud rate message_send( &msg, COMMAND_TEMPERATURE, NULL, 0); //send COMMAND_TEMPERATURE wait_ack_message( &msg ); //wait for ACK_TEMPERATURE serial_close(fd); } return 0; }
主程序 发送 COMMAND_TEMPERATURE 消息, 等待 ACK_TEMPERATURE 返回消息, 从返回消息的内容中第一、二字节得到温度值,第三字节得到湿度值。
将C语言程序交叉编译后生成temperature_test,用scp命令上传到开发板
SSH登入 Linkit 7688 DUO开发板,运行 temperature_test
运行结果, 得到了当前温度和湿度:
Temperature: 25.0, Humidity:87
三、倾斜开关、水银开关(TILT SWITCH), 见下图
倾斜开关其实就是一种开关,开关上有一个玻璃管子,管子里有一个水银球。当开关倾斜,水银i球就会滚动。当开关倾斜到一定程度,水银球就会落到管子底部,把管子底部的两根电极接通。如果反向倾斜,则水银球离开管子底部,管子底部的两根电极将不通。因此,也称为水银开关。
倾斜开关可以用于监测货物有否翻倒等。
倾斜开关模块有三个管脚,其中 (图中左侧)标注‘-’的管脚接地(GND), (图中右侧)标注"S”的管脚接接信号(数字I/O) 中间的管脚接 5V
用三根杜邦线把模块接到开发板上,其中“-”脚接GND, “S"脚接 D3口,
按键抖动现象:当开关触点断开、闭合时,由于水银球的弹性作用,开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。在一段时间内会处于时断时续状态。这种现象在机械开关中也存在。这种现象叫按键抖动(key jitter)。 对于机械开关,一般不稳定期在20ms, 水银开关不稳定期长达1秒以上。
按键抖动的处理:在软件中,要对按键抖动进行消除处理,否则软件会一个短时间内出现频繁开关的不正常现象。处理方法时,在第一次检测到开关状态变化时,不要立即触发。等待一小段时间后,再次检测开关状态,如果两次或多次检测开关状态均为稳定值,则触发开关事件。 这个一小段时间片在机械开关中常为10-20ms。 在水银开关中,我把它定为间隔100ms, 且连续检测4次均为稳定值时,即开关状态变化.
编一个Arduino程序,采用上例中的通信协议,监控开关状态,如有状态变化,通过串口发送消息到到主控板, 编译上传到ATmegaU32
Arduino程序等待 COMMAND_TEMPERATURE消息, 调用getTemperature() , 其中调用 DHT.read11()读取传感器数据。
如果读取数据成功,返回 ACK_TEMPERATURE消息,消息内容三个字节,第一个字节是温度的整数位、第二个字节是温度的小数第1位。第三字节是湿度。
编一个C语言主程序 temperature_test.c,采用消息协议,向Arduino发送COMMAND_TEMPERATURE消息送到,等待Arduino返回 ACK_TEMPERATURE消息, 读取其中的温度和湿度值打印出来。 交叉编译后生成temperature_test,用scp命令上传到开发板</p><p><pre name="code" class="cpp">#include <stdio.h>
注意:程序将使用message_protocol.ino模块,要把 message_protocol.ino 这个文件放在本Arduino项目文件夹中, 然后重新打开项目即可包含此模块
#define COMMAND_SWITCH 's' int pinSwitch = 3; //pin 3 connects to switch int lastValue = 0; // last value of pin int checkTimes = 0; // check times for key jitter void setup() { MessageInit(57600); //init message < need message_protocol.ino > pinMode(pinSwitch, INPUT); //set pinSwitch INPUT lastValue = digitalRead(pinSwitch); //get last value } void loop() { int value = digitalRead(pinSwitch); //read the switch if (value != lastValue) { //if value changed //eliminate key jitter: check 4 times checkTimes = 0; delay(100); //delay 100 ms while ( value == digitalRead(pinSwitch) && checkTimes++ < 4 ) checkTimes++; //if continous 4 times if (checkTimes >= 4 ) { unsigned char c = value & 0xFF; //change to unsigned char MessageSend( COMMAND_SWITCH, &c, 1); //send message lastValue = value; } } delay(10); //delay in between reads for stability }
编一个C语言主程序 tilt_test.c,采用消息协议,监听串口有否按键消息送到,打印出来, 交叉编译后生成tilt_test,用scp命令上传到开发板
注:项目中要使用到 串口函数模块serial.c 和 消息协议模块 message_protocol.c
#include <stdio.h> #include <unistd.h> #include "serial.h" #include "message_protocol.h" #define COMMAND_SWITCH 's' int test_switch() { int fd; //file descriptor of serial port message_t msg; //message object fd = serial_open(0, 57600);//open serial port 0, /etc/ttyS0 if ( fd > 0 ) { message_init( &msg, fd, 57600 ); //init message with fd, set baud rate //loop while ( 1 ) { if ( 1 == message_receive(&msg) ) { //if received message if ( message_command(&msg) == COMMAND_SWITCH ) { printf("switch value = %d\n", message_data(&msg, 0 ) ); //print value fflush(stdout); } } usleep(10*1000); //wait 10 milli-seconds } serial_close(fd); } return 0; }
将C语言程序交叉编译后生成tilt_test,用scp命令上传到开发板
SSH登入 Linkit 7688 DUO开发板,运行 tilt_test
用手反复倾斜开关,观察水银球来回滚动,和屏幕输出结果:
switch value = 1
switch value = 0
switch value = 1
水银球接通开关时,switch value = 0. 水银球不接通开关时, switch value = 1
由于水银球在管子中只能在一个方向上滚动,所以只能测一个方面的倾斜度。
如果要测四个方面的倾斜度,则需要用到 另一个传感器 BALL SWITCH (球形开关),如下图:
这个模块的管脚接法与 水银开关(TILT_SWITCH)完全一样,功能也基本相同,只不过它是一个电子开关,支持在四个方向上的倾斜都可以触发开关。
所以, 使用的控制程序也一样,由于它是电子开关,没有水银球抖动的问题。所以在 Arduino程序中的防抖动部分: delay(100); 改为 delay(10)就好了。
请自己试一下吧。
四、激光发射器(Laser Emit), 见下图
激光发射器可以发射出一串激光,常用于计数(需配合有一个光敏电阻接收器),如生产线上统计通过的物件数量、门闸上统计进门人数等。
激光发射器有一个激光发射头,有三个管脚,其中 (图中右侧)标注‘-’的管脚接地(GND), 图中左侧标注"S”的管脚接接信号(数字I/O), 中间的管脚接5V 或 3.3V
用三根杜邦线把模块接到开发板上,其中“-”脚接GND, “S"脚接D3, 中间的管脚接5V
激光发射器的控制方法与一个LED灯一样的。
编一个Arduino程序,采用消息协议,收到消息后,将D3设置为HIGH 或 LOW, 则激光将发射或关闭。 Arduino程序如下,请编译后上传到ATmegaU32
注意:程序将使用message_protocol.ino模块,要把 message_protocol.ino 这个文件放在本Arduino项目文件夹中, 然后重新打开项目即可包含此模块
#define COMMAND_LASER 'a' int pinLaser = 3; //pin 3 connects to laser emit module void setup() { MessageInit(57600); //init message < need message_protocol.ino > pinMode(pinLaser, OUTPUT); //set pinLaser OUTPUT } void loop() { if ( MessageReceive() ) { //if receive message if ( MessageCommand() == COMMAND_LASER ) { int value = MessageData(0); if (value == 1) digitalWrite(pinLaser, HIGH); else digitalWrite(pinLaser, LOW); MessageACK( COMMAND_LASER ); } } }
编一个C语言主程序 test_laser.c,采用消息协议,向Arduino发消息。
注意:项目中要使用到 串口函数模块serial.c 和 消息协议模块 message_protocol.c
#include <stdio.h> #include <unistd.h> #include "serial.h" #include "message_protocol.h" #define COMMAND_LASER 'a' int test_laser() { int fd; //file descriptor of serial port message_t msg; //message object unsigned char value; fd = serial_open(0, 57600);//open serial port 0, /etc/ttyS0 if ( fd > 0 ) { message_init( &msg, fd, 57600 ); //init message with fd, set baud rate value = 1; message_send( &msg, COMMAND_LASER, &value, 1); //send COMMAND_LASER message, value = 1 sleep(5);//wait 5 seconds value = 0; message_send( &msg, COMMAND_LASER, &value, 1); //send COMMAND_LASER message, value = 0 serial_close(fd); } return 0; }
交叉编译后生成laser_test,用scp命令上传到开发板
将C语言程序交叉编译后生成laser_test,用scp命令上传到开发板
SSH登入 Linkit 7688 DUO开发板,运行 laser_test
运行结果: 程序一运行,则发射器发出一串激光,5秒后,激光关闭
五、光敏电阻接收器(Photoresistor), 见下图
模块有三个管脚,其中 (图中右侧)标注‘-’的管脚接地(GND), 图中左侧标注“S"的管脚接信号(数字I/O), 中间的管脚接电源3.3V
光敏电阻接收器模块的工作方式是: 当光敏电阻有强光射在上面时, “S"管脚输出 LOW. 当没有强光射在光敏电阻上面时, “S"管脚输出 HIGH
用三根杜邦线把模块接到开发板上,其中“-”脚接GND, 标注“S"的管脚接 D4口, 中间管脚接3.3V
这一次,我把激光发射器也同时接上去作为光源, 激光发射器的"S"管脚接D3口。激光发射器的"-"接GND, 中间管脚接3.3V
编一个Arduino程序,采用消息协议,不断读取D4口的状态值,如有状态变化,通过串口发送COMMAND_SWITCH消息到到主控板。这个程序同时也接收消息,如果有COMMAND_LASER消息,则打开或关闭激光。
程序如下,请编译上传到ATmegaU32
#define COMMAND_LASER 'a' #define COMMAND_SWITCH 's' int pinLaser = 3; //pin 3 connects to laser emit module int pinPhotoResistor = 4; //pin 4 connects to photoresistor module int lastValue = 0; //last value of photoresistor void setup() { MessageInit(57600); //init message < need message_protocol.ino > pinMode(pinLaser, OUTPUT); //set pinLaser OUTPUT pinMode(pinPhotoResistor, INPUT); //set pinPhotoResistor INPUT lastValue = digitalRead( pinPhotoResistor ); } void loop() { int value = digitalRead( pinPhotoResistor ); if ( value != lastValue ) // PhotoResistor status change { unsigned char c = value & 0xFF; //convert to unsigned char MessageSend( COMMAND_SWITCH, &c, 1); //send COMMAND_SWITCH to linkit 7688 lastValue = value; } if ( MessageReceive() ) { //receive message if ( MessageCommand() == COMMAND_LASER ) { //if is COMMAND_LASER int value = MessageData(0); if (value == 1) digitalWrite(pinLaser, HIGH); //turn LASER on else digitalWrite(pinLaser, LOW); //turn LASER off MessageACK( COMMAND_LASER ); return; } } delay(1); }
编一个C语言主程序 resistor_test.c,采用消息协议,首先打开激光,然后监测有否COMMAND_SWITCH消息送达,如有,则打印出来。同时,对通过的物体计数。
注:项目中要使用到 串口函数模块serial.c 和 消息协议模块 message_protocol.c
程序如下:
#include <stdio.h> #include <unistd.h> #include "serial.h" #include "message_protocol.h" #define COMMAND_SWITCH 's' #define COMMAND_LASER 'a' int test_resistor() { int fd; //file descriptor of serial port message_t msg; //message object unsigned char value; int counter = 0; fd = serial_open(0, 57600);//open serial port 0, /etc/ttyS0 if ( fd > 0 ) { message_init( &msg, fd, 57600 ); //init message with fd, set baud rate value = 1; message_send( &msg, COMMAND_LASER, &value, 1); //turn LASER on //loop while ( 1 ) { if ( 1 == message_receive(&msg) ) { //if received message if ( message_command(&msg) == COMMAND_SWITCH ) { //if is COMMAND_SWITCH value = message_data(&msg, 0 ); //get value if ( value == 0 ) counter++; //increase counter //print it out printf("switch value = %d, counter = %d\n", value, counter ); fflush(stdout); } } usleep(10*1000); //wait 10 milli-seconds } serial_close(fd); } return 0; }
将C语言程序交叉编译后生成 resistor_test,用scp命令上传到开发板
SSH登入 Linkit 7688 DUO开发板,运行 resistor_test
运行: 程序一运行,则发射器发出一串激光,将激光对准光敏电阻。
当激光射在光敏电阻上时,光敏电阻的输出值为0. 当光敏电阻收不到激光时,光敏电阻的输出值将变为1.
试着用物体穿过激光,则 激光会被遮挡一次,光敏电阻的输出值先为0,再变成1,再变成0. 此时计数器加1. 并打印在屏幕上。
如此,则可以计数了,比如:可以用于门闸计算进门的人数;也可用于生产线上,对通过的物体计数。
运行结果:
switch value = 0, counter = 1
switch value = 1, counter = 1
switch value = 0, counter = 2
switch value = 1, counter = 2
switch value = 0, counter = 3
switch value = 1, counter = 3
。。。
六、红外线接收(IR RECEIVER), 见下图
模块有三个管脚,其中 (图中左侧)标注‘-’的管脚接地(GND), 图中右侧标注"S”的管脚接信号(数字I/O), 中间的管脚接电源5V
用三根杜邦线把模块接到开发板上,其中“-”脚接GND, 标注"S”的管脚分别接 D5口, 中间的管脚接电源5V
6.1 红外线遥控原理
每个人的家中都有N多个红外线遥控器。
红外线遥控的原理: 遥控器发出某个频率红外线(通常是38K), 这束红外线有时高、有时低,即以类似“10101100..."的编码方式发出。接收器收到这束红外线后,必须先解码,得到一组数字。这个数字就是遥控器发出的命令。
但是,红外线的编码是比较复杂且很不标准的。各个厂家有不同的编码标准,典型的厂商编码标准有SONY、SHARP、NEC、SANYO、SAMSUNG、PANASONIC、LG等等。一般的家电遥控器,都是用专用的遥控器专用IC芯片去实现编码和解码的,而且不同厂商的IC芯片还不一样。 所以遥控器很不通用。
在Arduino中,我们可以使用上图这个红外线接收器模块,利用Arduino的计算能力进行解码,而且不需依赖专用IC芯片,就可以支持各种厂商的编解码,使得各种遥控器都能遥控Arduino。
6.2 IRremote库安装
要在Arduino中使用红外线,首先要安装 IRremote库。 在 https://github.com/shirriff/Arduino-IRremote 下载 整个库文件,改目录名为 “IRremote" (注意文件名大小写不能错,否则以后编译时会出现错误: “IRsend" not a named type.
然后再将IRremote文件夹复制到arduino的库文件夹。
在MAC OS的操作:右键点击Arduino IDE的图标出菜单,选菜单项“显示包内容”, 进入 “Contents/Java/libraries"(这个文件夹就是ardunio的库文件夹了)
arduino库文件夹中有一个 “RobotIRremote”的子文件夹,这是一个老版本的IRremote. 必须把RobotIRremote文件夹删除,否则以后编译时会出现 ”Multiple IRremote.h"的错误。
好了,现在重启Arduino IDE, 则可在 "项目“-> include library 中打开IRremote库了。
6.3 红外线学习程序
比如:我想用家中的电视机遥控器 遥控Arduino. 那么,首先要写一个红外线学习的Arduino程序,用于读取和记录遥控器的编码,如下:
//------------------------------------------------------------------------------ // Include the IRremote library header #include <IRremote.h> //------------------------------------------------------------------------------ int recvPin = 5; //IR receiver connects to pin 5 IRrecv irrecv(recvPin); //init IRrecv unsigned char ir_type = 0; //IR type unsigned int key_count = 0; //key count unsigned long last_key = 0; // last key value unsigned int repeat_count = 0; //repeat key count //+============================================================================= // print IR type string void printIRType() { switch (ir_type) { case NEC: Serial.print("NEC"); break ; case SONY: Serial.print("SONY"); break ; case RC5: Serial.print("RC5"); break ; case RC6: Serial.print("RC6"); break ; case DISH: Serial.print("DISH"); break ; case SHARP: Serial.print("SHARP"); break ; case JVC: Serial.print("JVC"); break ; case SANYO: Serial.print("SANYO"); break ; case MITSUBISHI: Serial.print("MITSUBISHI"); break ; case SAMSUNG: Serial.print("SAMSUNG"); break ; case LG: Serial.print("LG"); break ; case WHYNTER: Serial.print("WHYNTER"); break ; case AIWA_RC_T501: Serial.print("AIWA"); break ; case PANASONIC: Serial.print("PANASONIC"); break ; case DENON: Serial.print("DENON"); break ; default: Serial.print("UNKNOWN"); break ; } } //+============================================================================= // Configure the Arduino // void setup ( ) { irrecv.enableIRIn(); // Start the IR receiver Serial.begin(57600); // Init Serial Serial.println("please press keys on IR remote controller"); } //+============================================================================= // The repeating section of the code // void loop ( ) { decode_results results; // Somewhere to store the results if (irrecv.decode(&results)) // receive an IR code { //whether results has valid value if ( results.decode_type != UNKNOWN && results.value != 0xFFFFFFFF ) { //whether the same key is pressed if (results.value == last_key ) { repeat_count++; } else { last_key = results.value; repeat_count = 0; } if ( repeat_count == 0 ) { //print informations if ( ir_type == 0 ) { ir_type = results.decode_type; //save IR type //print type Serial.print("unsigned char ir_type = "); Serial.print(ir_type); Serial.print("; // "); printIRType(); Serial.println(""); //print ir codes array statement Serial.println("unsigned long ir_codes[] = { "); } //print IR value Serial.print("\t0x"); Serial.print(results.value, HEX); Serial.print(", //KEY "); Serial.println(key_count++); //increase key count } else if ( repeat_count == 3 ) { //repeat 3 times will end current receive task Serial.println("};"); ir_type = 0; key_count = 0; last_key = 0; repeat_count = 0; } } irrecv.resume(); // Prepare for the next value } delay(10); //wait a while for stability }
这个Arduino程序只需用Arduino IDE上传到ATmega32U4即可, 不需要使用到Linkit 7688。
程序的用途是:当遥控器逐个按下时,记录下按键值,显示在Arduino的串口监视器窗口中。如果同一按键重复按二次,则忽略。如果同一按键重复按三次,则重新开始记录。
将程序编译上传到ATmega32U4, 运行,将电视机遥控器对着红外接收模块,逐个按下遥控器的各个按钮,最后一个按键重复按三次,运行结果如下:
unsigned char ir_type = 3; // NEC
unsigned long ir_codes[] = {
0x20DF08F7, //KEY 0
0x20DF8877, //KEY 1
0x20DF48B7, //KEY 2
0x20DFC837, //KEY 3
0x20DF28D7, //KEY 4
0x20DFA857, //KEY 5
0x20DF6897, //KEY 6
0x20DFE817, //KEY 7
0x20DF18E7, //KEY 8
0x20DF9867, //KEY 9 (最后一个键,要重复按三次)
};
如此,则得到一段代码, 其中:ir_type是遥控器编码厂商类型,ir_codes[]是一个数组,分别记录了第0 至 n个 按键的值。
6.4 红外线接收程序
编一个Arduino程序,采用消息协议,监控红外线接收状态,则发送COMMAND_IR_RECEIVE消息(内容为键值到主控板,程序如下:
注意:程序将使用message_protocol.ino模块,要把 message_protocol.ino 这个文件放在本Arduino项目文件夹中, 然后重新打开项目即可包含此模块
#include <IRremote.h> #define COMMAND_IR_RECEIVE 'i' int recvPin = 5; //IR receiver connects to pin 5 IRrecv irrecv(recvPin); //init IRrecv //IR key codes unsigned char ir_type = 3; // NEC unsigned long ir_codes[] = { 0x20DF08F7, //KEY 0 0x20DF8877, //KEY 1 0x20DF48B7, //KEY 2 0x20DFC837, //KEY 3 0x20DF28D7, //KEY 4 0x20DFA857, //KEY 5 0x20DF6897, //KEY 6 0x20DFE817, //KEY 7 0x20DF18E7, //KEY 8 0x20DF9867 //KEY 9 }; void setup() { MessageInit( 57600 ); // init message < need message_protocol.ino > irrecv.enableIRIn(); // Start the IR receiver } void loop() { unsigned char i; decode_results results; // Somewhere to store the results if (irrecv.decode(&results)) // receive an IR code { if ( results.decode_type == ir_type && results.value != 0xFFFFFFFF ) { //find value in ir_codes array for (i = 0; i < sizeof(ir_codes); i++) { if (results.value == ir_codes[i]) { MessageSend( COMMAND_IR_RECEIVE, &i, 1); //send message, content is key index } } } irrecv.resume(); // Prepare for the next value } delay(10); // delay in between reads for stability }
Arduino程序中的 ir_type, ir_codes 就是从红外线学习程序的运行结果中复制来的, 注意:要把 ir_codes数组最后一个数据后的 逗号删去。
Arduino程序的作用是: 当收到红外线信号,在ir_codes数组中查找按键值。如找到,则向主控板发送一个 COMMAND_IR_RECEIVE消息,消息内容是 按键在数组中的序号
将Arduino程序编译上传到ATmega32U4
编一个C语言主程序 ir_test.c,采用消息协议,监听有否COMMAND_IR_RECEIVE消息,如有则打印其内容出来
注:项目中要使用到 串口函数模块serial.c 和 消息协议模块 message_protocol.c
/* * ir_test.c * */ #include <stdio.h> #include <unistd.h> #include "serial.h" #include "message_protocol.h" #define COMMAND_IR_RECEIVE 'i' int main() { int fd; //file descriptor of serial port message_t msg; //message object fd = serial_open(0, 57600);//open serial port 0, /etc/ttyS0 if ( fd > 0 ) { message_init( &msg, fd, 57600 ); //init message with fd, set baud rate //loop while ( 1 ) { if ( 1 == message_receive(&msg) ) { //if received message if ( message_command(&msg) == COMMAND_IR_RECEIVE ) { printf("IR key index = %d\n", message_data(&msg, 0 ) ); //print key index fflush(stdout); } } usleep(10*1000); //wait 10 milli-seconds } serial_close(fd); } else { printf("open serial fail\n"); } return 0; }
将C语言程序交叉编译后生成 ir_test,用scp命令上传到开发板
SSH登入 Linkit 7688 DUO开发板,运行 ir_test
运行: 程序后,当用遥控器对这开发板按键时,则打印出按键结果, 效果如下:
IR key index = 1
IR key index = 2
IR key index = 3
。。。
六、红外线发射(IR EMISSION), 见下图
模块上有一个红外线发射二极管
模块有三个管脚,其中 (图中右侧)标注‘-’的管脚接地(GND), 图中左侧标注"S”的管脚管脚接信号(数字I/O), 中间的管脚接电源5V
用三根杜邦线把模块接到开发板上,其中“-”脚接GND, 标注"S”的管脚接 D13口, 中间的管脚接电源5V
注:IRremote库要求必须使用ATmega32U4的 D13做为红外发射口(需要用到时钟和PWM), 接其它口是不行的。
编一个Arduino程序,采用消息协议,接收COMMAND_IR_SEND消息,根据消息内容中的按键序号,翻译为红外线值,发送红外线。程序如下:
程序中要使用到 IRremote库 和 message_protocol.ino模块,要把 message_protocol.ino 这个文件放在本Arduino项目文件夹中, 然后重新打开项目即可包含此模块
#include <IRremote.h> #define COMMAND_IR_SEND 'r' IRsend irsend; //note: for ATmega32U4, IR send module must connects to pin 13 //IR key codes unsigned char ir_type = 3; // NEC unsigned long ir_codes[] = { 0x20DF08F7, //KEY 0 0x20DF8877, //KEY 1 0x20DF48B7, //KEY 2 0x20DFC837, //KEY 3 0x20DF28D7, //KEY 4 0x20DFA857, //KEY 5 0x20DF6897, //KEY 6 0x20DFE817, //KEY 7 0x20DF18E7, //KEY 8 0x20DF9867 //KEY 9 }; void setup() { MessageInit( 57600 ); // init message < need message_protocol.ino > } int sendIR(unsigned char index) { if (index >= sizeof(ir_codes)) return 0; switch (ir_type) { case NEC: irsend.sendNEC(ir_codes[index], 32); return 1; case SONY: irsend.sendSony(ir_codes[index], 32); return 1; case RC5: irsend.sendRC5(ir_codes[index], 32); return 1; case RC6: irsend.sendRC6(ir_codes[index], 32); return 1; case DISH: irsend.sendDISH(ir_codes[index], 32); return 1; case SHARP: irsend.sendSharp(ir_codes[index], 32); return 1; case JVC: irsend.sendJVC(ir_codes[index], 32, false); return 1; case SANYO: return 0; case MITSUBISHI: return 0; case SAMSUNG: irsend.sendSAMSUNG(ir_codes[index], 32); return 1; case LG: irsend.sendLG(ir_codes[index], 32); return 1; case WHYNTER: irsend.sendWhynter(ir_codes[index], 32); return 1; case AIWA_RC_T501: irsend.sendAiwaRCT501(ir_codes[index]); return 1; case PANASONIC: irsend.sendPanasonic(0, ir_codes[index]); return 1; //?address case DENON: irsend.sendDenon(ir_codes[index], 32); return 1; default: return 0; } return 0; } void loop() { if ( MessageReceive() ) { //if message received if ( MessageCommand() == COMMAND_IR_SEND ) { unsigned char index = MessageData(0); //get index of ir_codes from message data(0) if ( sendIR(index) ) //send IR MessageACK( COMMAND_IR_SEND ); //if send OK, response ACK message else MessageNAK( COMMAND_IR_SEND ); //if send fail, response NAK message } } }
Arduino程序的作用是: 当收到COMMAND_IR_SEND消息,在消息内容中取得按键编号,发送红外线。如发送成功,返回ACK消息。如不成功返回NAK消息。
将Arduino程序编译上传到ATmega32U4
编一个C语言主程序 ir_send.c,采用消息协议,向ATmega32U4发送COMMAND_IR_SEND消息,则可以控制它发送红外线
注:项目中要使用到 串口函数模块serial.c 和 消息协议模块 message_protocol.c
#include <stdio.h> #include <unistd.h> #include "serial.h" #include "message_protocol.h" #define COMMAND_IR_SEND 'r' int main(int argc, char **argv) { int fd; //file descriptor of serial port message_t msg; //message object unsigned char value; if (argc > 1 ) { value = atoi(argv[1]); } else { printf("Usage: ir_send <key>\n"); return 1; } fd = serial_open(0, 57600);//open serial port 0, /etc/ttyS0 if ( fd > 0 ) { message_init( &msg, fd, 57600 ); //init message with fd, set baud rate message_send( &msg, COMMAND_IR_SEND, &value, 1); //send COMMAND_IR_SEND message serial_close(fd); } return 0; }
C程序的作用是: 读取命令行参数,取得按键编号,向ATmega32U4发送COMMAND_IR_SEND消息
使用方法举例: ir_send 0 即红外线发送 第0个按键
将C程序交叉编译后生成ir_send,用scp命令上传到开发板
SSH登入 Linkit 7688 DUO开发板,将红外发射头对着电视机,运行ir_send:
ir_send 0
则可以看到,电视机接收到红外线信号,作出了反应。
ir_send 1
则可以看到,电视机再次接收到红外线信号,作出了反应。
呵呵, 可以遥控电视机了。
相关代码可以在我的资源中下载:Linkit7688DUO开发板连接多种Ardunio模块的范例程序