Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Maik Schmidt - Arduino A Quick-Start Guide, 2nd Edition (The Pragmatic Programmers) - 2015.pdf
Скачиваний:
185
Добавлен:
22.03.2016
Размер:
30 Мб
Скачать
☆

Outputting Morse Code Symbols • 65

Arduino IDE, and you can find them in the hardware/arduino/cores/arduino directory of the IDE. Have a look at Arduino.h (in older Arduino versions this file was named WProgram.h). It contains all the constants we have used so far and many more. It also declares many useful macros and the Arduino’s most basic functions.

When you edit regular sketches, you don’t have to worry about including any standard header files, because the IDE does it automatically behind the scenes. As soon as you create more complex projects that contain “real” C++ code, you have to manage everything yourself. You have to explicitly import all the libraries you need, even for basic stuff such as the Arduino constants.

After importing all necessary header files, we define two string arrays named

LETTERS and DIGITS. They contain the Morse code for all letters and digits, and we’ll use them later to translate regular text into Morse code. Before we do that, we define the constructor that is responsible for creating and initializing new Telegraph objects:

TelegraphLibrary/telegraph.cpp

Telegraph::Telegraph(const int output_pin, const int dit_length) { _output_pin = output_pin;

_dit_length = dit_length; _dah_length = dit_length * 3; pinMode(_output_pin, OUTPUT);

}

The constructor expects two arguments: the number of the pin the Morse code should be sent to and the length of a dit measured in milliseconds. Then it stores these values in corresponding instance variables, calculates the correct length of a dah, and turns the communication pin into an output pin.

You’ve probably noticed that all private instance variables start with an underscore. I like that convention personally, but it isn’t enforced by C++ or the Arduino IDE.

Outputting Morse Code Symbols

After everything has been initialized, we can start to output Morse code symbols. We use several small helper methods to make our code as readable as possible:

TelegraphLibrary/telegraph.cpp

void Telegraph::output_code(const char* code) { const unsigned int code_length = strlen(code);

for (unsigned int i = 0; i < code_length; i++) { if (code[i] == '.')

report erratum • discuss

Chapter 4. Building a Morse Code Generator Library • 66

dit(); else

dah();

if (i != code_length - 1) delay(_dit_length);

}

}

void Telegraph::dit() { Serial.print("."); output_symbol(_dit_length);

}

void Telegraph::dah() { Serial.print("-"); output_symbol(_dah_length);

}

void Telegraph::output_symbol(const int length) { digitalWrite(_output_pin, HIGH); delay(length);

digitalWrite(_output_pin, LOW);

}

The function output_code takes a Morse code sequence consisting of dots and dashes and turns it into calls to dit and dah. The dit and dah methods then print a dot or a dash to the serial port and delegate the rest of the work to output_symbol, passing it the length of the Morse code symbol to be emitted. output_symbol sets the output pin to HIGH for the length of the symbol, and then it sets it back to LOW. Everything works exactly as described in the Morse code timing scheme, and only the implementation of send_message is missing:

TelegraphLibrary/telegraph.cpp

Line 1 void Telegraph::send_message(const char* message) {

-for (unsigned int i = 0; i < strlen(message); i++) {

-const char current_char = toupper(message[i]);

-if (isalpha(current_char)) {

5output_code(LETTERS[current_char - 'A']);

-delay(_dah_length);

-} else if (isdigit(current_char)) {

-output_code(DIGITS[current_char - '0']);

-delay(_dah_length);

10 } else if (current_char == ' ') {

-Serial.print(" ");

-delay(_dit_length * 7);

-}

-}

15

Serial.println();

-

}

report erratum • discuss

Installing and Using the Telegraph Class • 67

send_message outputs a message character by character in a loop. In line 3, we turn the current character into uppercase, because lowercase characters are not defined in Morse code (that’s why you can’t implement a chat client using Morse code). Then we check whether the current character is a letter using C’s isalpha function. If it is, we use the character to determine its Morse code representation that is stored in the LETTERS array. To do that, we use an old trick: in the ASCII table, all letters (and digits) appear in the correct order—that is, A=65, B=66, and so on. To transform the current character into an index for the LETTERS array, we have to subtract 65 (or 'A') from its ASCII code. When we have determined the correct Morse code, we pass it to output_symbol and delay the program for the length of a dah afterward.

The algorithm works exactly the same for outputting digits; we only have to index the DIGITS array instead of the LETTERS array, and we have to subtract the ASCII value of the character '0'.

In line 10, we check whether we received a blank character. If yes, we print a blank character to the serial port and wait for seven dits. All other characters are ignored: we only process letters, digits, and blanks. At the end of the method, we send a newline character to the serial port to mark the end of the message.

Installing and Using the Telegraph Class

Our Telegraph class is complete, and we should now create some example sketches that actually use it. This is important for two reasons: we can test our library code, and for users of our class it’s good documentation for how to use it.

The Arduino IDE looks for libraries in two places: in its global libraries folder relative to its installation directory and in the user’s local sketchbook directory. During development, it’s best to use the local sketchbook directory. You can find its location in the IDE’s Preferences (see Figure 14, Find the sketchbook location in the Preferences, on page 68). Create a new directory named libraries in the sketchbook directory.

To make the Telegraph class available, create a Telegraph subfolder in the libraries folder. Then copy telegraph.h and telegraph.cpp to the new libraries/Telegraph folder. (Do not copy TelegraphLibrary.ino.) Restart the IDE.

Let’s start with the mother of all programs: “Hello, world!” Create a new sketch named HelloWorld and enter the following code:

report erratum • discuss

Chapter 4. Building a Morse Code Generator Library • 68

Figure 14—Find the sketchbook location in the Preferences.

TelegraphLibrary/examples/HelloWorld/HelloWorld.ino

#include "telegraph.h"

const unsigned int BAUD_RATE = 9600; const unsigned int OUTPUT_PIN = 13; const unsigned int DIT_LENGTH = 200;

Telegraph telegraph(OUTPUT_PIN, DIT_LENGTH);

void setup() { Serial.begin(BAUD_RATE);

}

void loop() { telegraph.send_message("Hello, world!"); delay(5000);

}

This sketch emits the string “Hello, world!” as Morse code every five seconds. To achieve this, we include the definition of our Telegraph class, and we define constants for the pin our LED is connected to and for the length of our dits. Then we create a global Telegraph object and an empty setup function. In loop, we then invoke send_message on our Telegraph instance every five seconds.

When you compile this sketch, the Arduino IDE automatically compiles the telegraph library, too. If you forgot to copy the library files to the libraries/Telegraph folder, you’ll get an error message such as “Telegraph does not name a type.”

report erratum • discuss

Installing and Using the Telegraph Class • 69

If you’ve copied the files but made any syntactical errors, you’ll also be notified now. If you have to correct some errors, make sure you change your original source code files. After you’ve fixed the errors, copy the files to the libraries folder again, and don’t forget to restart the IDE.

Turning a static string into Morse code is nice, but wouldn’t it be great if our program could work for arbitrary strings? So, let’s add a more sophisticated example. This time, we’ll write code that reads messages from the serial port and feeds them into a Telegraph instance.

Create a new sketch named MorseCodeGenerator and enter the following code:

TelegraphLibrary/examples/MorseCodeGenerator/MorseCodeGenerator.ino

#include "telegraph.h"

const unsigned int OUTPUT_PIN = 13; const unsigned int DIT_LENGTH = 200; const unsigned int MAX_MESSAGE_LEN = 128; const unsigned int BAUD_RATE = 9600; const char NEWLINE = '\n';

char message_text[MAX_MESSAGE_LEN]; int index = 0;

Telegraph telegraph(OUTPUT_PIN, DIT_LENGTH);

void setup() { Serial.begin(BAUD_RATE);

}

void loop() {

if (Serial.available() > 0) {

int current_char = Serial.read();

if (current_char == NEWLINE || index == MAX_MESSAGE_LEN - 1) { message_text[index] = 0;

index = 0; telegraph.send_message(message_text);

}else {

message_text[index++] = current_char;

}

}

}

Again, we include the header file of the Telegraph class, and as usual we define some constants: OUTPUT_PIN defines the pin our LED is connected to, and

DIT_LENGTH contains the length of a dit measured in milliseconds. NEWLINE is set to the ASCII code of the newline character. We need it to determine the

report erratum • discuss

Chapter 4. Building a Morse Code Generator Library • 70

end of the message to be emitted as Morse code. Finally, we set MAX_MESSAGE_LEN to the maximum length of the messages we are able to send.

Next we define three global variables: message_text is a character buffer that gets filled with the data we receive on the serial port. index keeps track of our current position in the buffer, and telegraph is the Telegraph object we’ll use to convert a message into “blinkenlights.”2

setup initializes the serial port, and in loop we check whether new data has arrived, calling Serial.available. We read the next byte if new data is available, and we check whether it is a newline character or whether it is the last byte that fits into our character buffer. In both cases, we set the last byte of message_text to 0, because strings in C/C++ are null-terminated. We also reset index so we can read the next message, and finally we send the message using our telegraph. In all other cases, we add the latest byte to the current message text and move on.

You should compile and upload the program now. Open the serial monitor and choose “Newline” from the line endings drop-down menu at the bottom of the window. With this option set, the serial monitor will automatically append a newline character to every line it sends to the Arduino. Enter a message such as your name, click the Send button, and see how the Arduino turns it into light. In the following figure, you can see what happens when you enter my name.

2.http://en.wikipedia.org/wiki/Blinkenlights

report erratum • discuss

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]