如何自己编写Arduino支持的C++类库

12 篇文章 6 订阅

http://www.geek-workshop.com/thread-1884-1-1.html

我们在上一讲中实现了一个TN901红外温度传感器51程序到Arduino程序的转换,如果代码越来越多这样程序的可维护性会随之降低,也不适合团度开发。我们应该把常用的文件封装成C++库,这样在复用的时候就会方便很多。
    首先让我们来看下官方的C++类库是怎样的结构,以官方的LCD类库为例,如下图所示:

未命名.jpg

2012-9-12 12:21 上传
下载附件 (15.8 KB)



上面的文件大体是这样的结构:

文件名文件类型文件说明
keywords.txtkeywords.txtArduino库色标文件
LiquidCrystal.h.hC++头文件
LiquidCrystal.cpp.cppC++程序文件



以下几种文件的作用如下:

.h 头文件:头文件作为一种包含功能函数、数据接口声明的载体文件,用于保存程序的声明(declaration),而定义文件用于保存程序的实现 (implementation)。

.cpp 文件:C++程序源文件主要的逻辑写在这里。

keywords.txt 文件:用来定义库在程序中显示关键字的颜色。

下面让我们来做个实际的例子将我们昨天写的程序改造成C++类库 可以点击这里

TH901.rar (992 Bytes, 下载次数: 174)

2012-9-12 16:58 上传
点击文件名下载附件


下载上一讲中的程序

首先我们来尝试下头文件的编写 有关宏定义的具体用法可以参见5楼zcbzjx的详细说明:)

ARDUINO 代码 复制打印
  
  
  1. #ifndef TH901_H   //根据条件进行编译
  2. #define TH901_H
  3. //我们在这中间添加程序
  4. #endif             //条件编译结束
  
  
  1. #ifndef TH901_H   //根据条件进行编译
  2. #define TH901_H
  3. //我们在这中间添加程序
  4. #endif             //条件编译结束



我们在这中间添加程序主体的代码部分,首先来添加程序的头文件,需要引用什么都可以加进来

ARDUINO 代码 复制打印
  
  
  1. #include <inttypes. h> //引用相关的头文件
  
  
  1. #include <inttypes. h> //引用相关的头文件



之后我们可以预定义一些需要的常量,这样维护起来比较方便,如果常量值改变只要统一修改这里就好

ARDUINO 代码 复制打印
  
  
  1. #define TN901_OTADDRESS 0x4c
  2. #define TN901_ETADDRESS 0x66
  3. #define TN901_ENDADDRESS 0x0d
  
  
  1. #define TN901_OTADDRESS 0x4c
  2. #define TN901_ETADDRESS 0x66
  3. #define TN901_ENDADDRESS 0x0d



接下来我们来定义变量和声明程序的方法,需要外部调用和访问的就声明成public,不需要外部访问的就声明为private

ARDUINO 代码 复制打印
  
  
  1. class TN901      //定义类主体及类名
  2. {
  3.   public:   //以下定义为公共方法
  4.     short ET;    //环境温度输出
  5.     short OT;    //目标温度输出
  6.     void Init ( int TN_Data, int TN_Clk, int TN_ACK ); //程序初始化
  7.     void Read ( );   //读取方法
  8.     void ReadData ( char flag ); //读取指定地址的数据
  9.     int  GetData ( ); //获取数据
  10.   private:   //以下定义为私有方法
  11.     int _dataPin;   //数据引脚
  12.     int _clkPin;    //时钟引脚
  13.     int _ackPin;    //反馈引脚
  14.     unsigned char  Data [ 5 ];   //数据数组
  15. };
  
  
  1. class TN901      //定义类主体及类名
  2. {
  3.   public:   //以下定义为公共方法
  4.     short ET;    //环境温度输出
  5.     short OT;    //目标温度输出
  6.     void Init ( int TN_Data, int TN_Clk, int TN_ACK ); //程序初始化
  7.     void Read ( );   //读取方法
  8.     void ReadData ( char flag ); //读取指定地址的数据
  9.     int  GetData ( ); //获取数据
  10.   private:   //以下定义为私有方法
  11.     int _dataPin;   //数据引脚
  12.     int _clkPin;    //时钟引脚
  13.     int _ackPin;    //反馈引脚
  14.     unsigned char  Data [ 5 ];   //数据数组
  15. };



这样我们一个头文件就写好了

ARDUINO 代码 复制打印
  
  
  1. /**
  2.  * TN901 Library
  3.  * 说明: 台湾燃太红外TN901传感器库
  4.  * 作者: 水乐天
  5.  * Email: [email]45268175@qq.com[/email]
  6.  */
  7.  
  8. #ifndef TH901_H  
  9. #define TH901_H
  10.  
  11.  
  12. #include <inttypes. h> //引用相关的头文件
  13.  
  14. #define TN901_OTADDRESS 0x4c
  15. #define TN901_ETADDRESS 0x66
  16. #define TN901_ENDADDRESS 0x0d
  17.  
  18.  
  19. class TN901      //定义类主体及类名
  20. {
  21.   public:   //以下定义为公共方法
  22.     short ET;    //环境温度输出
  23.     short OT;    //目标温度输出
  24.     void Init ( int TN_Data, int TN_Clk, int TN_ACK ); //程序初始化
  25.     void Read ( );   //读取方法
  26.     void ReadData ( char flag ); //读取数据
  27.     int  GetData ( ); //获取数据
  28.   private:   //以下定义为私有方法
  29.     int _dataPin;   //数据引脚
  30.     int _clkPin;    //时钟引脚
  31.     int _ackPin;    //反馈引脚
  32.     unsigned char  Data [ 5 ];   //数据数组
  33. };
  34.  
  35. #endif             //程序结束
  
  
  1. /**
  2.  * TN901 Library
  3.  * 说明: 台湾燃太红外TN901传感器库
  4.  * 作者: 水乐天
  5.  * Email: [email]45268175@qq.com[/email]
  6.  */
  7.  
  8. #ifndef TH901_H  
  9. #define TH901_H
  10.  
  11.  
  12. #include <inttypes. h> //引用相关的头文件
  13.  
  14. #define TN901_OTADDRESS 0x4c
  15. #define TN901_ETADDRESS 0x66
  16. #define TN901_ENDADDRESS 0x0d
  17.  
  18.  
  19. class TN901      //定义类主体及类名
  20. {
  21.   public:   //以下定义为公共方法
  22.     short ET;    //环境温度输出
  23.     short OT;    //目标温度输出
  24.     void Init ( int TN_Data, int TN_Clk, int TN_ACK ); //程序初始化
  25.     void Read ( );   //读取方法
  26.     void ReadData ( char flag ); //读取数据
  27.     int  GetData ( ); //获取数据
  28.   private:   //以下定义为私有方法
  29.     int _dataPin;   //数据引脚
  30.     int _clkPin;    //时钟引脚
  31.     int _ackPin;    //反馈引脚
  32.     unsigned char  Data [ 5 ];   //数据数组
  33. };
  34.  
  35. #endif             //程序结束



接下来我们来书写程序的主体,就是CPP文件。首先我们引用已经写好的程序头文件

ARDUINO 代码 复制打印
  
  
  1. #include "TN901.h"
  
  
  1. #include "TN901.h"



之后我们引用一些需要的库文件,需要哪些可以参见标准C++的库文件说明

ARDUINO 代码 复制打印
  
  
  1. #include "TN901.h"
  2.  
  3. #include <stdio. h>
  4. #include <string. h>
  5. #include <inttypes. h>
  6. #include "Arduino.h"
  
  
  1. #include "TN901.h"
  2.  
  3. #include <stdio. h>
  4. #include <string. h>
  5. #include <inttypes. h>
  6. #include "Arduino.h"



然后我们逐一实现在头文件中定义的方法,注意类型要与定义类型相对应。所有的方法都要属于你定义的类名,格式如下

ARDUINO 代码 复制打印
  
  
  1. 类名::方法名
  
  
  1. 类名::方法名




另外i啊我们要为程序的封装考虑程序应有的结构,总之是怎样使你的库使用起来最方便,在一般的逻辑中尽量减少调用的次数。我们可以把程序的逻辑分割为几个部分来书写。如:

ARDUINO 代码 复制打印
  
  
  1. 1.初 始 化
  2. 2.实现功能
  3. 3.显示数据
  
  
  1. 1.初 始 化
  2. 2.实现功能
  3. 3.显示数据



当然这个逻辑以具体的程序为准。

我们来尝试写第一个初始化的方法,这样我们可以自己定义程序的端口。

ARDUINO 代码 复制打印
  
  
  1. //初始化TN901传感器
  2. void TN901:: Init ( int TN_Data, int TN_Clk, int TN_ACK )
  3. {
  4.    //定义私有端口
  5.   _dataPin=TN_Data;
  6.   _clkPin=TN_Clk;
  7.   _ackPin=TN_ACK;
  8.  
  9.    pinMode (_clkPin, INPUT );
  10.    pinMode (_ackPin, OUTPUT );
  11.    digitalWrite (_ackPin, HIGH );
  12. }
  
  
  1. //初始化TN901传感器
  2. void TN901:: Init ( int TN_Data, int TN_Clk, int TN_ACK )
  3. {
  4.    //定义私有端口
  5.   _dataPin=TN_Data;
  6.   _clkPin=TN_Clk;
  7.   _ackPin=TN_ACK;
  8.  
  9.    pinMode (_clkPin, INPUT );
  10.    pinMode (_ackPin, OUTPUT );
  11.    digitalWrite (_ackPin, HIGH );
  12. }



然后我们书写程序的主要逻辑部分

ARDUINO 代码 复制打印
  
  
  1. //读取数据
  2. void TN901:: Read ( )
  3. {
  4.    digitalWrite (_ackPin, LOW );
  5.   ReadData (TN901_OTADDRESS ); //目标温度的第一个字节为0x4c   
  6.    if ( (Data [ 0 ]==TN901_OTADDRESS )&&
  7.       (Data [ 4 ]==TN901_ENDADDRESS ) ) //每帧的最后一个字节为0x0d   
  8.    {   
  9.     GetData_OT ( );  
  10.    }
  11.  
  12.    delay ( 1 ); //等待1毫秒
  13.  
  14.    digitalWrite (_ackPin, LOW );
  15.   ReadData (TN901_ETADDRESS ); //环境温度的第一个字节为0x66      
  16.  
  17.    if ( (Data [ 0 ]==TN901_ETADDRESS )&&
  18.       (Data [ 4 ]==TN901_ENDADDRESS ) ) //每帧的最后一个字节为0x0d   
  19.    {   
  20.     GetData_ET ( );
  21.    }
  22. }
  
  
  1. //读取数据
  2. void TN901:: Read ( )
  3. {
  4.    digitalWrite (_ackPin, LOW );
  5.   ReadData (TN901_OTADDRESS ); //目标温度的第一个字节为0x4c   
  6.    if ( (Data [ 0 ]==TN901_OTADDRESS )&&
  7.       (Data [ 4 ]==TN901_ENDADDRESS ) ) //每帧的最后一个字节为0x0d   
  8.    {   
  9.     GetData_OT ( );  
  10.    }
  11.  
  12.    delay ( 1 ); //等待1毫秒
  13.  
  14.    digitalWrite (_ackPin, LOW );
  15.   ReadData (TN901_ETADDRESS ); //环境温度的第一个字节为0x66      
  16.  
  17.    if ( (Data [ 0 ]==TN901_ETADDRESS )&&
  18.       (Data [ 4 ]==TN901_ENDADDRESS ) ) //每帧的最后一个字节为0x0d   
  19.    {   
  20.     GetData_ET ( );
  21.    }
  22. }



最后我们逐一实现程序的运算过程

ARDUINO 代码 复制打印
  
  
  1. //读取数据
  2. void TN901:: ReadData ( char flag )
  3. {
  4.    char i,j,k;
  5.    byte BitState = 0;          //每次发七帧
  6.    for (k= 0;k< 7;k++ )
  7.    {
  8.     for (j= 0;j< 5;j++ )         //每帧5个字节
  9.     {
  10.        for (i= 0;i< 8;i++ )
  11.        {
  12.          int temp= digitalRead (_clkPin );
  13.          while (temp )
  14.          {
  15.           temp = digitalRead (_clkPin );
  16.          }
  17.         temp= digitalRead (_clkPin );
  18.         BitState= digitalRead (_dataPin );
  19.         Data [j ]= Data [j ]<< 1;
  20.         Data [j ]= Data [j ]|BitState;
  21.  
  22.          while (!temp )
  23.          {
  24.           temp = digitalRead (_clkPin );
  25.          }
  26.        }
  27.     }
  28.     if (Data [ 0 ]==flag )  k= 8;
  29.    }
  30.  
  31.    digitalWrite (_ackPin, HIGH );
  32. }
  33.  
  34.    //计算环境温度
  35. void TN901:: GetData_ET ( )   
  36. {      
  37.   ET= (Data [ 1 ]<< 8 )|Data [ 2 ];   
  38.   ET = int ( ( ( float )ET/ 16 - 273.15 )* 100 );      
  39. }   
  40.  
  41. //计算目标温度
  42. void TN901:: GetData_OT ( )   
  43. {   
  44.   OT= (Data [ 1 ]<< 8 )|Data [ 2 ];   
  45.   OT = int ( ( ( float )OT/ 16 - 273.15 )* 100 );      
  46. }
  
  
  1. //读取数据
  2. void TN901:: ReadData ( char flag )
  3. {
  4.    char i,j,k;
  5.    byte BitState = 0;          //每次发七帧
  6.    for (k= 0;k< 7;k++ )
  7.    {
  8.     for (j= 0;j< 5;j++ )         //每帧5个字节
  9.     {
  10.        for (i= 0;i< 8;i++ )
  11.        {
  12.          int temp= digitalRead (_clkPin );
  13.          while (temp )
  14.          {
  15.           temp = digitalRead (_clkPin );
  16.          }
  17.         temp= digitalRead (_clkPin );
  18.         BitState= digitalRead (_dataPin );
  19.         Data [j ]= Data [j ]<< 1;
  20.         Data [j ]= Data [j ]|BitState;
  21.  
  22.          while (!temp )
  23.          {
  24.           temp = digitalRead (_clkPin );
  25.          }
  26.        }
  27.     }
  28.     if (Data [ 0 ]==flag )  k= 8;
  29.    }
  30.  
  31.    digitalWrite (_ackPin, HIGH );
  32. }
  33.  
  34.    //计算环境温度
  35. void TN901:: GetData_ET ( )   
  36. {      
  37.   ET= (Data [ 1 ]<< 8 )|Data [ 2 ];   
  38.   ET = int ( ( ( float )ET/ 16 - 273.15 )* 100 );      
  39. }   
  40.  
  41. //计算目标温度
  42. void TN901:: GetData_OT ( )   
  43. {   
  44.   OT= (Data [ 1 ]<< 8 )|Data [ 2 ];   
  45.   OT = int ( ( ( float )OT/ 16 - 273.15 )* 100 );      
  46. }



这样我们的程序就写好了,需要完整代码的朋友可以点击这里

TN901.rar (1.87 KB, 下载次数: 227)

2012-9-12 17:25 上传
点击文件名下载附件


下载

之后我们来尝试为我们的库编写一个范例程序来测试我们的程序是否运行正常。

ARDUINO 代码 复制打印
  
  
  1. #include <TN901. h>   //引用库文件
  2. TN901 tn;            //实 例 化
  3. void setup ( )
  4. {
  5.     Serial. begin ( 9600 );
  6.     tn. Init ( 7, 9, 8 );   //初 始 化
  7. }
  8.  
  9. void loop ( )
  10. {
  11.    tn. Read ( );         //数据读取
  12.    SerialValue ( );
  13.     delay ( 200 );
  14. }
  15.  
  16. void SerialValue ( )
  17. {
  18.     Serial. print ( "OT: " );
  19.     Serial. print (tn. OT, DEC );   //输出目标温度
  20.     Serial. println ( " C" );
  21.     Serial. print ( "ET: " );
  22.     Serial. print (tn. ET, DEC );   //输出环境温度
  23.     Serial. println ( " C" );
  24. }
  
  
  1. #include <TN901. h>   //引用库文件
  2. TN901 tn;            //实 例 化
  3. void setup ( )
  4. {
  5.     Serial. begin ( 9600 );
  6.     tn. Init ( 7, 9, 8 );   //初 始 化
  7. }
  8.  
  9. void loop ( )
  10. {
  11.    tn. Read ( );         //数据读取
  12.    SerialValue ( );
  13.     delay ( 200 );
  14. }
  15.  
  16. void SerialValue ( )
  17. {
  18.     Serial. print ( "OT: " );
  19.     Serial. print (tn. OT, DEC );   //输出目标温度
  20.     Serial. println ( " C" );
  21.     Serial. print ( "ET: " );
  22.     Serial. print (tn. ET, DEC );   //输出环境温度
  23.     Serial. println ( " C" );
  24. }



好了,我们看到虽然我们花了一点时间编写了库文件,但是在我们使用程序的时候可以非常方便的调用,而且这样逻辑会比较清晰。呵呵。

最后送给大家一个小礼物,就是如何为我们的库编写色标文件,色标文件就是定义你的库中的方法在编译器中显示的颜色
没有色标文件的库显示起来是这样的:

未命名.jpg

2012-9-12 17:34 上传
下载附件 (22.26 KB)



我们可以看到库文件的类名和方法名都是黑色的这样看起来不是很清楚。加上色标文件之后是这样的:

未命名.jpg

2012-9-12 17:36 上传
下载附件 (31.36 KB)



我们可以看到TN901这样的类名都被加亮了这样看起来要清楚许多。

实现这个需要定义一个色标文件放在库文件的目录中,格式如下

ARDUINO 代码 复制打印
  
  
  1. #######################################
  2. # Syntax Coloring Map For 你的类名
  3. #######################################
  4.  
  5. #######################################
  6. # Datatypes (KEYWORD1 ) 数据类型关键字
  7. #######################################
  8.  
  9. TN901        KEYWORD1
  10.  
  11. #######################################
  12. # Methods and Functions (KEYWORD2 ) 方法类型关键字
  13. #######################################
  14.  
  15. Init        KEYWORD2
  16. Read        KEYWORD2
  17. ReadData        KEYWORD2
  18. GetData        KEYWORD2
  19.  
  20. #######################################
  21. # Constants (LITERAL1 )  常量类型关键字
  22. #######################################
  23.  
  24. ET        LITERAL1
  25. OT        LITERAL1
  
  
  1. #######################################
  2. # Syntax Coloring Map For 你的类名
  3. #######################################
  4.  
  5. #######################################
  6. # Datatypes (KEYWORD1 ) 数据类型关键字
  7. #######################################
  8.  
  9. TN901        KEYWORD1
  10.  
  11. #######################################
  12. # Methods and Functions (KEYWORD2 ) 方法类型关键字
  13. #######################################
  14.  
  15. Init        KEYWORD2
  16. Read        KEYWORD2
  17. ReadData        KEYWORD2
  18. GetData        KEYWORD2
  19.  
  20. #######################################
  21. # Constants (LITERAL1 )  常量类型关键字
  22. #######################################
  23.  
  24. ET        LITERAL1
  25. OT        LITERAL1



这样我们的色标文件就写好了,我们把它保存成文件名为keywords.txt的文件放在库文件目录下就可以了。

当我们些库文件全部做好了之后我们就可以把这些文件放在,这样的目录下

ARDUINO 代码 复制打印
  
  
  1. energia:energia-0101E0008\hardware\msp430\libraries\
  2. arduino:arduino -1.0 .1-windows\arduino -1.0 .1\libraries\
  
  
  1. energia:energia-0101E0008\hardware\msp430\libraries\
  2. arduino:arduino -1.0 .1-windows\arduino -1.0 .1\libraries\



这样当你重新打开官方编译器的时候可以看到如下的内容

未命名.jpg

2012-9-12 17:45 上传
下载附件 (26.68 KB)



这样我们就可以很方便的调用了。


  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值