7449浏览
查看: 7449|回复: 7

[进阶] Arduino 扩展库的制作(官网原文件精细翻译)--附详细实例...

[复制链接]
Writing a Library for Arduino


为Arduino编个扩展库


This document explains how to create a library for Arduino. It starts with a sketch with a sketch for flashing Morse code and explains how to convert its functions into a library. This allows  other people to easily use the code that you've written and to easily update it as you improve the library.

  本文档介绍了如何创建一个Arduino扩展库。它将向你描述如何将一个摩尔斯代码信号的功能做成一个扩展库。这将会使别人很容易使用你的代码,并且你也可以很方便的编辑和修改你的扩展库。
We start with a sketch that does simple Morse code:

  我们从写一个简单的摩尔斯码开始:

  1. int pin = 13;
  2. void setup()
  3. {
  4. pinMode(pin, OUTPUT);
  5. }
  6. void loop()
  7. {
  8. dot(); dot(); dot();
  9. dash(); dash(); dash();
  10. dot(); dot(); dot();
  11. delay(3000);
  12. }
  13. void dot()
  14. {
  15. digitalWrite(pin, HIGH);
  16. delay(250);
  17. digitalWrite(pin, LOW);
  18. delay(250);
  19. }
  20. void dash()
  21. {
  22. digitalWrite(pin, HIGH);
  23. delay(1000);
  24. digitalWrite(pin, LOW);
  25. delay(250);
  26. }
复制代码

If you run this sketch, it will flash out the code for SOS (a distress call) on pin 13.

  运行这段代码,会使Pin 13脚发出SOS紧急呼救的莫尔斯代码信号。

The sketch has a few different parts that we'll need to bring into our library. First, of course, we have the dot() and dash() functions that do the actual blinking. Second, there's the ledPin

variable which the functions use to determine which pin to use. Finally, there's the call to pinMode() that initializes the pin as an output.

  代码有几个不同的地方,我们将其写入我们的库。首先,我们显然要有dot()函数和dash()函数功能,它们提供闪烁的功能。其次,还要用“ledpin”变量来确定使用哪个针脚。最后,要用pinmode()函数来初始化引脚输出。

Let's start turning the sketch into a library!

  让我们开始把程序写成扩展库!

You need at least two files for a library: a header file (w/ the extension .h) and the source  file (w/ extension .cpp). The header file has definitions for the library: basically a listing of  everything that's inside; while the source file has the actual code. We'll call our library

"Morse", so our header file will be Morse.h. Let's take a look at what goes in it. It might seem a bit strange at first, but it will make more sense once you see the source file that goes with  it.

  你至少需要两个文件:一个头文件(扩展名为.h)和一个源文件(扩展名为.cpp)。头文件定义扩展库:基本上是一个原代码中所有元素的列表。我们引用我们的扩展库“Morse”,所以我们把头文件名写为“Morse.h”,让它看上去一目了然。它看上去有点奇怪,但它与源文件一起运行时将有更多的功能。

The core of the header file consists of a line for each function in the library, wrapped up in a class along with any variables you need:

  头文件的核心是一个扩展库中所有函数的列表,这个列表以及你所需要的所有的变量写在一个类里面:class Morse
  1. {
  2. public:
  3. Morse(int pin);
  4. void dot();
  5. void dash();
  6. private:
  7. int _pin;
  8. };
复制代码
A class is simply a collection of functions and variables that are all kept together in one place. These functions and variables can be public, meaning that they can be accessed by people using your library, or private, meaning they can only be accessed from within the class itself. Each class has a special function known as a constructor, which is used to create an instance of the class. The constructor has the same name as the class, and no return type.

  类是一个函数和变量的简单集合。这些函数和变量可以是公开的,以使别人可以使用你的扩展库。或者,他们只能从类内部访问。每个类有一个特殊的函数,称为构造函数,它用来创建一个类的过程。构造函数与类具有相同的名字,但它没有返回类型。

You need a couple of other things in the header file. One is an #include statement that gives you access to the standard types and constants of the Arduino language (this is automatically added to normal sketches, but not to libraries). It looks like this (and goes above the class definition given previously):

  在头文件里你还需要一些其他的东西。用一个#include声明让你访问Arduino语言中的标准变量和常量(它自动添加,但不在扩展库中)。就像这样(它将在最开始运行):
  1. #include "WProgram.h"
复制代码

Finally, it's common to wrap the whole header file up in a weird looking construct:
  最后,它将把整个头文件打包进一个特殊的构造里:
  1. #ifndef Morse_h
  2. #define Morse_h
  3. // the #include statment and code go here...
  4. // 把声明和代码写在这里
  5. #endif
复制代码

Basically, this prevents problems if someone accidently #include's your library twice.

  基本上,这可以防止别人不小心重复引用库。

Finally, you usually put a comment at the top of the library with its name, a short description of what it does, who wrote it, the date, and the license.

  最后,我们通常会在顶部加入一些自己的信息,比如库的名字、简短的描述、作者的名字、日期和许可等等。

Let's take a look at the complete header file:

  下面,让我们看一下完整的头文件:


  1. /*
  2. Morse.h - Library for flashing Morse code.
  3. Created by David A. Mellis, November 2, 2007.
  4. Released into the public domain.
  5. */
  6. #ifndef Morse_h
  7. #define Morse_h
  8. #include "WProgram.h"
  9. class Morse
  10. {
  11. public:
  12. Morse(int pin);
  13. void dot();
  14. void dash();
  15. private:
  16. int _pin;
  17. };
  18. #endif
复制代码
Now let's go through the various parts of the source file, Morse.cpp.
  现在让我们看看.cpp文件的组成部分。
First comes a couple of #include statements. These give the rest of the code access to the standard Arduino functions, and to the definitions in your header file:
  首先是一组#include报表,要把它写在文件开头,提供其余代码使用标准Arduino功能:
  1. #include "WProgram.h"
  2. #include "Morse.h"
复制代码

Then comes the constructor. Again, this explains what should happen when someone creates an instance of your class. In this case, the user specifies which pin they would like to use. We
configure the pin as an output save it into a private variable for use in the other functions:

  然后是构造函数,再次声明当有人使用你的类的过程时会发生什么。在本例中,用户可以指定要使用的针脚。我们将输出引脚的配置保存到一个私有变量用于其他功能:
  1. Morse::Morse(int pin)
  2. {
  3. pinMode(pin, OUTPUT);
  4. _pin = pin;
  5. }
复制代码

There are a couple of strange things in this code. First is the Morse:: before the name of the function. This says that the function is part of the Morse class. You'll see this again in the  other functions in the class. The second unusual thing is the underscore in the name of our private variable, _pin. This variable can actually have any name you want, as long as it matches  the definition in the header file. Adding an underscore to the start of the name is a common convention to make it clear which variables are private, and also to distinguish the name from that of the argument to the function (pin in this case).
  有一些特殊的东西在这个代码里。首先是在这个函数名字前的“Morse::”。这表示,此函数属于“Morse”类,你会在这个类的其它函数里多次看到。其二是在私有变量名称前的下划线,“_pin”。这个变量可以是其它名字,只要可以与头文件匹配。加下划线开始的名字是私有变量的一个约定俗成的写法,同时也能从函数的功能段区分名字(在本例中)。
Next comes the actual code from the sketch that you're turning into a library (finally!). It looks pretty much the same, except with Morse:: in front of the names of the functions, and _pin
instead of pin:
  扩展库的代码和源代码看起来非常类似,除了函数名前有“Morse::”和用“_pin”代替了“pin”:

  1. void Morse::dot()
  2. {
  3.   digitalWrite(_pin, HIGH);
  4.   delay(250);
  5.   digitalWrite(_pin, LOW);
  6.   delay(250);  
  7. }
  8. void Morse::dash()
  9. {
  10.   digitalWrite(_pin, HIGH);
  11.   delay(1000);
  12.   digitalWrite(_pin, LOW);
  13.   delay(250);
  14. }
复制代码

Finally, it's typical to include the comment header at the top of the source file as well.Let's
see the whole thing:

  最后,在源文件的顶部同样会有注释部分。让我们来看看整个扩展库源文件:

  1. /*
  2.   Morse.cpp - Library for flashing Morse code.
  3.   Created by David A. Mellis, November 2, 2007.
  4.   Released into the public domain.
  5. */
  6. #include "WProgram.h"
  7. #include "Morse.h"
  8. Morse::Morse(int pin)
  9. {
  10.   pinMode(pin, OUTPUT);
  11.   _pin = pin;
  12. }
  13. void Morse::dot()
  14. {
  15.   digitalWrite(_pin, HIGH);
  16.   delay(250);
  17.   digitalWrite(_pin, LOW);
  18.   delay(250);  
  19. }
  20. void Morse::dash()
  21. {
  22.   digitalWrite(_pin, HIGH);
  23.   delay(1000);
  24.   digitalWrite(_pin, LOW);
  25.   delay(250);
  26. }
复制代码
And that's all you need (there's some other nice optional stuff, but we'll talk about that later). Let's see how you use the library.
  这就是所有必要的部分(其它一些可选的东西,我们将在以后再谈)。让我们来看看如何使用扩展库。

First, make a Morse directory inside of the libraries sub-directory of your sketchbook directory.Copy or move the Morse.h and Morse.cpp files into that directory.Now launch the Arduino
environment.If you open the Sketch > Import Library menu, you should see Morse inside.The library will be compiled with sketches that use it.If the library doesn't seem to build, make sure that  the files really end in .cpp and .h (with no extra .pde or .txt extension, for example).
  首先,在扩展库的子目录建一个莫尔斯扩展库目录。把Morse.h和Morse.cpp文件复制或移动到该目录中。现在打开Arduino编译器。打开“Sketch”>“Import Library”菜单,你应该看到有“Morse”选项。在使用的时候该扩展库将同时被编译。如果没有看到这个扩展库,请确保文件名为正常的“.cpp”和“h”(没有其它多余的如“.pde”或“.txt”这样的扩展名)。

Let's see how we can replicate our old SOS sketch using the new library:
  让我们看看现在我们怎样用新的扩展库来编写我们的原先的程序:
  1. #include <Morse.h>
  2. Morse morse(13);
  3. void setup()
  4. {
  5. }
  6. void loop()
  7. {
  8.   morse.dot(); morse.dot(); morse.dot();
  9.   morse.dash(); morse.dash(); morse.dash();
  10.   morse.dot(); morse.dot(); morse.dot();
  11.   delay(3000);
  12. }
复制代码

There are a few differences from the old sketch (besides the fact that some of the code has moved to a library).
  除了将一些代码已经转移到扩展库里,这些代码有些差别。
First, we've added an #include statement to the top of the sketch.This makes the Morse library available to the sketch and includes it in the code sent to the board.That means if you no longer need a library in a sketch, you should delete the #include statement to save space.
  首先,我们仅需要在代码顶部添加#include语句,就可以使程序使用这个扩展库,并且在编译时会被同时编译进去。这也意味着你在程序中不需要再编写长长的代码。而且如果你不再需这个功能,只要删除这个“#include”语句就可以了。
Second, we now create an instance of the Morse class called morse :
  现在,我们来创建一个莫尔斯类的过程:
Morse morse(13);
When this line gets executed (which actually happens even before the setup() function), the constructor for the Morse class will be called, and passed the argument you've given here (in
this case, just 13 ).
  当此行被执行时(实际上它在setup()函数执行之前就已经被执行了),将引用“Morse”类(本例子中使用针脚13)。
Notice that our setup() is now empty; that's because the call to pinMode() happens inside the library (when the instance is constructed).
  请注意,在这里“void setup()”是空的,这是因为“pinMode()”的调用发生在扩展库中(在调用函数的时候)。
Finally, to call the dot() and dash() functions, we need to prefix them with morse. - the name of the instance we want to use.We could have multiple instances of the Morse class, each on their own pin stored in the _pin private variable of that instance.By calling a function on a particular instance, we specify which instance's variables should be used during that call to a
function.That is, if we had both:
  最后,调用“dot()”和“dash()”函数时,我们需要用“morse”作它们的的前缀。程序中我们可以多次引用,它们每个的针脚数据都储存在“_pin”私有变量里。我们可以定义多个“Morse”类的函数,每一个都有自己的“_pin”私有变量。在某过个程中调用函数时,我们可以指定的不同的针脚变量,这些私有变量都仅是在函数调用过程中被使用。也就是说,如果我们有两次调用:
  1. Morse morse(13);
  2. Morse morse2(12);
复制代码

then inside a call to morse2.dot() , _pin would be 12.
  后面的私有变量“_pin”将会是针脚12 。

If you tried the new sketch, you probably noticed that nothing from our library was recognized by the environment and highlighted in color.Unfortunately, the Arduino software can't automatically figure out what you've define in your library (though it would be a nice feature to have), so you have to give it a little help.To do this, create a file called keywords.txt in the Morse directory.It should look like this:
  如果你尝试使用新的的代码,你会看到我们的扩展库没有被认可,并且用高亮显示出来。不幸的是,Arduino软件不能自动找出你在扩展库中已经定义的功能(虽然这将是一个很好的功能),所以你必须给它一个小小的提示。为了做到这一点,我们要在Morse扩展库目录中创建一个名为“keywords.txt”的文件。它的内容是这样的:
Morse        KEYWORD1
dash        KEYWORD2
dot        KEYWORD2

Each line has the name of the keyword, followed by a tab (not spaces), followed by the kind of  keyword.Classes should be KEYWORD1 and are colored orange; functions should be KEYWORD2 and will  be brown.You'll have to restart the Arduino environment to get it to recognize the new keywords.
  每行有一个关键字,后面有个Tab(注意,不是空格),再后面是keyword。类名为KEYWORD1;函数是KEYWORD2。你必须重新启动Arduino的环境,找到到新的关键字。
H文件内容:

  1. /*
  2.   Add2.h - Library
  3.   功能:将两个操作数相加,返回结果
  4. */
  5. #ifndef Add2_h
  6. #define Add2_h
  7. #include "WProgram.h" //此句声明了Arduino的标准常量和变量,必须要
  8. class Add2 //类名称(可与文件名不同)
  9. {
  10.   public: //此处定义全局函数和变量
  11.     Add2(); //构造函数,名字要与类名相同
  12.     int Calculation(int Val1, int Val2);
  13.   private: //此处定义私有函数和变量
  14.         int Result; //私有函数名前习惯加下划线“_”
  15. };
  16. #endif
复制代码


CPP文件内容:

  1. /*
  2.   Add2.h - Library
  3.   功能:将两个操作数相加,返回结果
复制代码


keywords文件内容:

Add2        KEYWORD1 //类名,用KEYWORD1,注意:中间为Tab符,而不是空格
Calculation        KEYWORD2 //函数名,用KEYWORD2,,注意:中间为Tab符,而不是空格




示例程序:
  1. #include <Add2.h>
  2. Add2 ad; //此处声明扩展库中的Add2类在本代码中使用的缀名,可自定义
  3. void setup()
  4. {
  5.   Serial.begin(9600);
  6. }
  7. void loop()
  8. {
  9.   for (int i = 0; i < 500; i++)
  10.   {
  11.     int val =  ad.Calculation(i,i);
  12.     Serial.println(val);
  13.     delay(500);
  14.   }
  15. }
复制代码

下载附件扩展库实例.rar

大连林海  初级技神
 楼主|

发表于 2015-11-1 09:52:17

库其实就是一个类,把某些个功能封装起来,提供给别人用的,省得每次重写。

根据目测--还没看官网reference的--库的命名有点规律,就是文件名/文件夹名称/类名相同,放在libraries目录中。如果是范例,要在库文件的根目录底下再建一个examples文件夹,然后根据一个范例一个文件夹的规则在examples下面。
头文件代码

  1. #ifndef LED_H
  2. #define LED_H
  3. /*
  4. 在类初始化的时候,必须传递LED数码管的位数和第一个
  5. 引脚的位置
  6. 接线时,前面几个脚接每一位的片选脚,紧接着是数码管abcdefg
  7. 对应的引脚
  8. 所有的引脚都是连续的
  9. */
  10. class LED
  11. {
  12. public:
  13.     /** Default constructor */
  14.     LED(int iCounts, int iFirstPin);
  15.     /** Default destructor */
  16.     ~LED();
  17.     void Display(int Position,int Number);
  18. protected:
  19. private:
  20.     void ledDisplay(int seg[8]);
  21.     int Counts;
  22.     int firstPin;
  23. };
  24. #endif // LED_H
复制代码


下面就是实现LED类库的代码

  1. #include "led.h"
  2. #include <WProgram.h>
  3. int     ledZero[8]  =   {0,0,0,0,0,0,0,0};  //LED数码管中abcdefg的电平设置
  4. int     ledOne[8]   =   {0,1,1,0,0,0,0,0};
  5. int     ledTwo[8]   =   {1,1,0,1,1,0,1,0};
  6. int     ledThree[8] =   {1,1,1,1,0,0,1,0};
  7. int     ledFour[8]  =   {0,1,1,0,0,1,1,0};
  8. int     ledFive[8]  =   {1,0,1,1,0,1,1,0};
  9. int     ledSix[8]   =   {1,0,1,1,1,1,1,0};
  10. int     ledSeven[8] =   {1,1,1,0,0,0,0,0};
  11. int     ledEight[8] =   {1,1,1,1,1,1,1,0};
  12. int     ledNine[8]  =   {1,1,1,1,0,1,1,0};
  13. int     ledPoint[8] =   {0,0,0,0,0,0,0,1};
  14. LED::LED(int iCounts, int iFirstPin)
  15. {
  16.     Counts = iCounts;
  17.     firstPin= iFirstPin;
  18.     for (int i= firstPin; i<= firstPin+ Counts; i++ )
  19.         pinMode(i, OUTPUT);
  20. }
  21. LED::~LED()
  22. {
  23. //析构函数
  24. }
  25. void LED::ledDisplay(int seg[8])
  26. {
  27.     int first;
  28.     first = firstPin + Counts ;
  29.     for (int i = 0; i<=8; i++)
  30.     {
  31.         digitalWrite(first + i, seg[i]);
  32.     }
  33. }
  34. void LED::Display(int Position, int Number)
  35. {
  36.     digitalWrite(Position+ firstPin-1,HIGH);    //在串口监视器中显示结果
  37.     Serial.print("the ");
  38.     Serial.print(Position);
  39.     Serial.print(" of ");
  40.     Serial.println(Number);
  41.     switch(Number)
  42.     {
  43.     case 0:
  44.         ledDisplay(ledZero);
  45.         break;
  46.     case 1:
  47.         ledDisplay(ledOne);
  48.         break;
  49.     case 2:
  50.         ledDisplay(ledTwo);
  51.         break;
  52.     case 3:
  53.         ledDisplay(ledThree);
  54.         break ;
  55.     case 4:
  56.         ledDisplay(ledFour);
  57.         break ;
  58.     case 5:
  59.         ledDisplay(ledFive);
  60.         break;
  61.     case 6:
  62.         ledDisplay(ledSix);
  63.         break;
  64.     case 7:
  65.         ledDisplay(ledSeven);
  66.         break;
  67.     case 8:
  68.         ledDisplay(ledEight);
  69.         break;
  70.     case 9:
  71.         ledDisplay(ledNine);
  72.         break;
  73.     default:
  74.         ledDisplay(ledZero);
  75.     }
  76. }
复制代码
回复

使用道具 举报

丄帝De咗臂  高级技匠

发表于 2015-11-1 11:52:08

你开始研究代码啦
回复

使用道具 举报

hnyzcj  版主

发表于 2015-11-1 14:33:30


非常好
回复

使用道具 举报

大连林海  初级技神
 楼主|

发表于 2015-11-1 16:41:58


就是看到了 学习学习 大家一起学 就分享出来了 要是翻译也是不难的 因为有在线翻译
回复

使用道具 举报

大连林海  初级技神
 楼主|

发表于 2015-11-1 16:42:17


大师 是不是觉得很有料
回复

使用道具 举报

丄帝De咗臂  高级技匠

发表于 2015-11-1 17:16:57

大连林海 发表于 2015-11-1 16:41
就是看到了 学习学习 大家一起学 就分享出来了 要是翻译也是不难的 因为有在线翻译 ...

在线翻译
回复

使用道具 举报

大连林海  初级技神
 楼主|

发表于 2015-11-1 17:47:03


哈哈 必须啊
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail