Intel Edison C++ 开发之I2C-使用MRAA库进行C/C++开发

来源:互联网 发布:知行理工闪退 编辑:程序博客网 时间:2024/06/06 00:29

转载出处:http://tec.gekius.com/blog/1069.html


这是一篇完整的关于在Intel Edison上进行原生程序开发的系列文章,以爱迪生通过I2C BUS连接温湿度传感器为例,详细地展示如何在 Eclipse上使用 C++ 进行 Edison 开发。文章将会涉及硬件、MRAA库、开发环境的设置、yocto linux 内核等内容,精彩内容不容错过。欢迎加入 Gekius 开发群(Q群: 329401876)深入讨论Intel Edison IoT 及嵌入式开发的方方面面 :)

2. 使用C/C++进行 Galileo/Edison I2C开发

Intel 官方不光为 Galileo/Edison 定制了 Linux 内核系统,还附带了对其进行开发的 SDK 和工具链(toolchain)。为 Edison 进行原生开发本质上是通过这 SDK 和工具链来编辑生成最终的可执行程序,并将程序运行在 Edison 上。 首先我们下载对应版本的 Intel IoT Dev kit,解压到任意目录。这是一个基于 Eclipse 完整的环境和工具,它已经为开发者配置好了系统环境变量,远程调试工具等,还包括了为 Edison 开发所需要的基本的库。程序员只需要轻点鼠标,就可以打开已经配置好的 Eclipse,立即可以上手编程。

2.1 新建工程,配置项目

接下来我们以实例一步步完成 Edison I2C开发。首先在解压好的 Intel IoT Dev Kit (以下简称 Dev Kit) 目录里找到 devkit-launcher.bat (for windows ),双击运行它。依次点击 File->New->C++ Projects ,弹出的对话框中 Toolchains 选择 Cross GCC,如下图所示,示例中项目名称定为 EdisonI2C

新建C++项目

新建C++项目

点击下一步,在出现编译器设置设置对话框里,”Cross compiler prefix”填入 “i586-poky-linux-”,如下图。点击”Finish”按钮完成新建工程

配置GCC编译器前缀

配置GCC编译器前缀

新项目创建成功后,还需要进一步配置编译器和链接器,在新建的 EdisonI2C 项目上右键,选择”Properties”,弹出项目属性对话框。进入”C/C++ Build->Tool Chain Editor”,”Current Builder”选择 “CDT Internal Builder”如下图所示

使用CDT作为默认的编译器

使用CDT作为默认的编译器

我们还要为链接器配置 –sysroot 标志,在项目属性对话框中依次点击 “C/C++ Build -> Settings -> Cross G++ Linker -> Miscellanous”,在右上角会出现 “Linker Flags”,填上 “${LDFLAGS} -lmraa”,如下图所示

配置链接器选项

配置链接器选项

最后我们还需要为编译器设置头文件包含路径。 GCC头文件包含路径为:

  • “${DEVKIT_HOME}/devkit-x86/sysroots/i586-poky-linux/usr/include”
设置GCC头文件包含路径

设置GCC头文件包含路径

G++编译器头文件包含路径为:

  • “${DEVKIT_HOME}/devkit-x86/sysroots/i586-poky-linux/usr/include”
  • “${DEVKIT_HOME}/devkit-x86/sysroots/i586-poky-linux/usr/include/c++”
  • “${DEVKIT_HOME}/devkit-x86/sysroots/i586-poky-linux/usr/include/c++/i586-poky-linux”
  • “${DEVKIT_HOME}/devkit-x86/sysroots/i586-poky-linux/usr/include/c++/bits”
  • “${DEVKIT_HOME}/devkit-x86/sysroots/i586-poky-linux/usr/include/upm”
G++头文件包含路径设置

G++头文件包含路径设置

到此编译器链接器配置完成,接下来添加源码开始编程。

2.2 使用 MRAA 库编写 I2C代码

在你买回 Edison 时,Intel 已经为你准备好了操作系统和开发工具,对于Intel IoT 战略来说支持跨平台,多种语言开发是很有必要的,这里我们以 C/C++ 语言为例进行说明,但并不意味着你只能用这两种语言进行开发。 对硬件进行编程,会涉及到从操作系统内核到驱动到上层接口各等方面问题,换句话说,就是硬件相关的。接下来的内容只针对 Intel 推出的 Arduino board 和 mini board,因为这两款扩展板使用的管脚和硬件配置不同,所以在开发上会有不少差异,好在 Intel 提供开源的MRAA 库,它对操作系统操作进行封装完成用户层和内核之间沟通,这样我们只需要简单地调用一些接口就可以很快实现我们想要的结果。 MRAA库提供 C和C++函数和类,我们可以使用 C++ 类进行操作,这样程序代码更加简洁,不过为了能更清楚地说明细节我们仍然使用 C 的函数进行开发。 我们应该首先为传感器创建类对外提供传感器控制操作,但为了简化问题我们这里忽略它,只为它创建头文件 TRH_sensor.h

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
/* Copyright (c) 2014 Gekius Hardware team.** Permission is hereby granted, free of charge, to any person obtaining* a copy of this software and associated documentation files (the* "Software"), to deal in the Software without restriction, including* without limitation the rights to use, copy, modify, merge, publish,* distribute, sublicense, and/or sell copies of the Software, and to* permit persons to whom the Software is furnished to do so, subject to* the following conditions:** The above copyright notice and this permission notice shall be* included in all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.* project_folder/includes/TRH_sensor.h** Created on: 2014年12月5日* Author: Jhon_Qiki* Join our QQ group: 329401876, discuss more details about embedded/wearable software* and hardware development** This class is created for demonstration of using Intel Edison I2C MRAA* interface to communicate with I2C chip.*/ #ifndef TRH_SENSOR_H_#define TRH_SENSOR_H_ #define TRH_SENSOR_I2C_ADDR 0x5c // sensor function code#define TRH_SENSOR_FUN_CODE_READ_REG 0x03#define TRH_SENSOR_FUN_CODE_WRITE_REG 0x10 // sensor register address#define TRH_RH_REG_ADDR_H 0x00 // high byte of humidity register address#define TRH_RH_REG_ADDR_L 0x01 // low byte of humidity register address#define TRH_T_REG_ADDR_H 0x02 // high byte of temperature register address#define TRH_T_REG_ADDR_L 0x03 // low byte of temperature register address#define TRH_STATE_REG_ADDR 0x07 // status register address /* skeleton class, ignor it nowclass TRHSensor {public:TRHSensor();virtual ~TRHSensor();};*/ #endif /* TRH_SENSOR_H_ */

当你考虑要使用某个厂商提供的传感器的时候,第一件要做的事情就是询问厂商索要器件的 datasheet 文件,文件中会包含器件的各类指标及使用方法,对于传感器IC一般厂商还会详细给出某一硬件接口上的通信协议,往往我们要严格按协议与传感器通讯才可以正确取到数据。这里的 TRH_sensor.h 文件中包括了示例所使用的传感器的地址,传感器内寄存器地址及控制命令,这些我们会在后面的程序中使用得上它们。 好了万事具备,我们开始创建main(),新建文件edison_i2c.cc

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
/* Copyright (c) 2014 Gekius Hardware team.** Permission is hereby granted, free of charge, to any person obtaining* a copy of this software and associated documentation files (the* "Software"), to deal in the Software without restriction, including* without limitation the rights to use, copy, modify, merge, publish,* distribute, sublicense, and/or sell copies of the Software, and to* permit persons to whom the Software is furnished to do so, subject to* the following conditions:** The above copyright notice and this permission notice shall be* included in all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.** project_folder/edison_i2c.cc** Created on: 2014年12月5日* Author: Jhon_Qiki* Join our QQ group: 329401876, discuss more details about embedded/wearable software* and hardware development** This class is created for demonstration of using Intel Edison I2C MRAA* interface to communicate with I2C chip.*/#include "TRH_sensor.h"#include "mraa.h"#include #include #include  #define I2C_BUS 0x06 /** The T/HR sensor will turn into sleeping mode automatically every time master finished* fetching data from it.We must activate the sensor before beginning transfer data.** @parameter: none* @return: error state* 0 for successful*/int ActivateSensor( const mraa_i2c_context i2c_context ){  if ( mraa_i2c_address( i2c_context, TRH_SENSOR_I2C_ADDR ) != MRAA_SUCCESS )    printf("can not find sensor!\n");   mraa_i2c_write_byte( i2c_context, 0 );  return 0;} int main(){  mraa_init();  mraa_i2c_context i2c_context = mraa_i2c_init(I2C_BUS);    printf( "i2c bus initialization finished\n");  uint8_t data_requirement_buffer[3];  uint8_t sensor_data_buffer[9] = {0};  int humitity_i = 0, temperature_i=0, guard;   for(;;)  {    // shake the sensor up every time you want to access its data    ActivateSensor( i2c_context );     // require temperature and humidity data    mraa_i2c_address( i2c_context, TRH_SENSOR_I2C_ADDR );    data_requirement_buffer[0] = TRH_SENSOR_FUN_CODE_READ_REG;    data_requirement_buffer[1] = TRH_RH_REG_ADDR_H;    data_requirement_buffer[2] = 4;    if ( mraa_i2c_write( i2c_context, data_requirement_buffer, 3 )==MRAA_SUCCESS)      printf("requirement has been send\n");     // ready to go, here we are going to fetching temperature    // and humidity data(4 bytes) at a time    mraa_i2c_address( i2c_context, TRH_SENSOR_I2C_ADDR );// sensor address with read mark    if (mraa_i2c_read( i2c_context, sensor_data_buffer, 8 )==MRAA_SUCCESS)      printf( "Requirement has been sent!");     guard = humitity_i;//guard command to prevent compiler common out unused variable    humitity_i = (((int)sensor_data_buffer[2])<<8) + sensor_data_buffer[3];    temperature_i = (((int)sensor_data_buffer[4])<<8) + sensor_data_buffer[5];      printf( "humitiy: %.1fRH temperature: %.1fC\n", ((double)humitity_i)/10, ((double)temperature_i)/10 );    sleep(60);//wait for another sampling available  }   mraa_i2c_stop( i2c_context );  return 0;}

文件中包含两个函数,一个是程序入口 main(),另一个为 ActivateSensor()。我们实例中所使用的传感器为被动式的传感器,传感器每隔一定时间会自动休眠以降低功耗和对环境的影响,所以在每次操作传感器之前都必需激活它,ActivateSensor()的目的就是激活传感器。mraa_i2c_address() 函数的作用是设置从机(也就是传感器)的地址,紧接着的读写操作会依赖于该地址。

我们的重点在 Edison MRAA 开发上,所以下边着重分解 main() 中的代码。

第59行调用了 mraa_init(),该函数封装了扩展板的识别和一些全局函数指针的初始化,最重要的是各管脚对应的输入输出,复用控制等也在此函数中初始化,详细见 mraa 原码 intel_edison_fab_c.cc 文件中的 mraa_intel_edison_fab_c(), 我们会在下一章节中更细致地进行剖析。

第60行对 Edison Arduino Board/Mini Board 的 I2C 接口进行初始化。Arduino Board 上的 I2C 是连接到模拟输入输出跳线帽上,也就是板上的 Analog In,这些通路都是复用的,可以作为模拟输入,GPIO和I2C使用,具体的用途得通过设置才可以正常使用,而 mraa_i2c_init()作用就在于此。我们将会在下一章节中更详细地进行分析。

第66~90行的 for 循环是读写传感器的逻辑,在第69行用 ActivateSensor() 激活传感器后,需要向传感器发送命令,第71~77行准备传感器命令和参数(TRH_SENSOR_FUN_CODE_READ_REG:读传感器数据命令;TRH_RH_REG_ADDR_H:指定从温度值高位读取开始;75行是指定一共读4个字节即包含温度和温度数据),76行开始向传感器发送命令。传感器如果正确收到命令,它会对当前环境进行采样把采集到的结果放在寄存器中,我们只要从寄存器中读取数据就可以知道上一次采集的数据量。

发送传感器命令

发送传感器命令

79~83行即为读取采样数据,82行通过 mraa_i2c_read() 向传感器发送主机读指令,并与传感器通信读取传感器数据,最终数据被保存在 sensor_data_buffer 中,我们只要把数据进行格式化输出(88行)就能看到结果。

读取传感器数据

读取传感器数据

 

2.3 编译运行代码

在开始运行代码之前,我们先配置一下 Eclipse 的远程调试工具,通过它我们可以使用 UI 界面进行 Edison 的跟踪调试,如下图在右上角找到”Remote System Explorer”,点击它会列出事先已经设置好的远程系统,你会看到名为”galileo”的主机,修改”Host Name”为 Edison 的 IP 地址(可以通过在 Edison 内输入命令 “ip a”看到),”Default User ID”设为 root

配置Eclipse 远程调试环境

配置Eclipse 远程调试环境

回到源码界面,依次选中我们的项目 EdisonI2C,展开 debug 下拉项,点击 “Debug Configurations….”如下图所示

配置远程debug项目属性

配置远程debug项目属性

依下图,点击”C/C++ Remote Application”,点击左上角添加按钮,把 EdisonI2C设置远程bug应用。

添加远程Debug应用

添加远程Debug应用

最后如下图设置可执行文件在远程系统中的路径

设置远程文件存放位置

设置远程文件存放位置

点击 debug 按钮开始远程运行我们的程序,最终我们得到的输出结果:)

程序运行结果

程序运行结果

是不是很容易呢,上边内容只是概述操作I2C的过程,在接下来的章节中我们将会深入 MRAA 了解 edison 的GPIO映射和 yocto linux的 sysfs,看看到底 mraa 为我们做了什么。如果文章中有什么错误及指正,可以通过我们的开发群 Q:329401876 与我们联系

0 0