Linkit 7688 DUO(五) 接上各种Arduino传感器和模块—扩展篇

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模块的范例程序

时间: 2024-10-11 16:42:42

Linkit 7688 DUO(五) 接上各种Arduino传感器和模块—扩展篇的相关文章

Linkit 7688 DUO(四): 接上各种Arduino传感器和模块——基础篇

前一篇讲了 Linkit 7688DUO操作Arduino的原理和基本方法.现在,我们要为开发板接上各类Arduino的传感器和模块了,这些模块提供了各类输入输出. 一.首先要充分了解 Linkit 7688 DUO开发板的引出管脚 Linkit 7688 DUO开发板上有两个处理器芯片. 一片是  Linkit 7688, 主处理器 一片是  ATmega32U4,  这是Arduino的处理芯片,提供Arduino编程接口,用于控制传感器外设等 两个处理器通过内部串口相连. 在开发中, 要写

Linkit 7688 DUO(六) 加入MQTT物联网协议

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(六

Arduino传感器连载之温度测量篇

来源:http://www.hzhike.com/School/2016/201607/20160711100131.html 温度是我们经常接触到的物理量,能够被我们所直观的感受得到,例如天气凉了需要增添衣物,吃的食物太烫需要吹一吹,同时也需要对温度精确的测量,例如人类的正常体温是37.5℃,一个大气压下纯水沸腾时的温度是100℃,都需要我们去做实验来找出其中的科学.下面我们将详细讲解几种常用的温度传感器,并利用Arduino来实现温度的测量,包括热敏电阻.LM35.DS18B20.DHT11

五年后你在何方 怎样设定目标总结篇

原文是谁所写,是否真实已经无从考究,不过个人觉得真的不错,很想分享一下. 一九七六年的冬天,当时我十九岁,在休斯顿太空总署的大空梭实验室里工作,同时也在总署旁边的休斯顿大学主修电脑.纵然忙于学校.睡眠与工作之间,这几乎占据了我一天二十四小时的全部时间,但只要有多余的一分钟,我总是会把所有的精力放在我的音乐创作上. 我知道写歌词不是我的专长,所以在这段日子里,我处处寻找一位善写歌.词的搭档,与我一起合作创作.我认识了一位朋友,她的名字叫凡內芮(Valerie Johnson).自从二十多年前离开德

智能手机上的常用传感器

Android操作系统11种传感器介绍 在Android2.3 gingerbread系统中,google提供了11种传感器供应用层使用. #define SENSOR_TYPE_ACCELEROMETER 1 //加速度 #define SENSOR_TYPE_MAGNETIC_FIELD 2 //磁力 #define SENSOR_TYPE_ORIENTATION 3 //方向 #define SENSOR_TYPE_GYROSCOPE 4 //陀螺仪 #define SENSOR_TYPE

在 OSX 10.9.4 上编译安装 FastDFS 及其 PHP 扩展

经我测试,在OSX 10.9.4上安装FastDFS V5.01的话会很悲剧,一开始就无法安装,会遇到这帖子中的问题:http://www.oschina.net/question/252582_162768 而我还死活解决不了,貌OSX上就没有ldconfig这个东东,反正我也不懂Linux和UNIX这类的系统. 于是只好退而求其次,安个老版本来用,毕竟我只是为了装FastDFS的PHP扩展,以便在Mac上开发PHP项目,而真正的FastDFS模拟服务器环境是在另一台联想Win7上的虚拟机中的

解决Mac上PyDev无法导入某些模块的问题

前一阵一直在恶补数学知识,昨天突然打开Mac上的Pydev发现有些模块不能正确引入,很奇怪的现象=.= 后来查知自己在pip的时候不小心下了个python2.7.10并把opencv依赖到这个版本的python上了!而本机自带的python2.7.6是通过pip默认安装模块的那个版本. 2.7.6里可以引入scipy.matplotlib但是不能用cv2,而2.7.10里只能引入neurolab.cv2. pydev里不知怎么搞的可以引入除了scipy.neurolab和matplotlib的其

(五)NS3中示例:网桥模块示例csma-bridge.cc程序的注释

(五)NS3中示例:网桥模块示例csma-bridge.cc程序的注释 1.Ns3 bridge模块中csma-bridge.cc示例程序注释 // Network topology // // n0 n1 // | | // ---------- // | Switch | // ---------- // | | // n2 n3 // // // - CBR/UDP flows from n0 to n1 and from n3 to n0 恒定的比特流从n0转发到n1,从n3转发到n0

Arduino 温湿度传感器DHT11模块实验

网上有很多DHT11的测试,试了N个程序,总是不得要领,各种报错,最后终于找到一套可用的库. 首先是DHT11.h文件 #ifndef __DHT11_H__ #define __DHT11_H__ #include <Arduino.h> //DHT11 IO设置 #define DHT11_DQ 2 #define DHT11_DQ_0 digitalWrite(DHT11_DQ,LOW) #define DHT11_DQ_1 digitalWrite(DHT11_DQ,HIGH) //函