So, my desk is getting pretty cluttered; on one side of the desk sits a pile of ungraded papers; on the other side of the desk a pile of unopened static-protection envelopes of integrated circuits. At the moment, I felt like I needed to call for help - to send out a distress signal. That reminded me of my younger years when I would watch my Dad in front of his amateur radio setup. I never learned Morse code and was always impressed with his ability to communicate across the world with dits and dahs. The trip down memory lane got me thinking about a mini-project that would help me learn about programming microcontrollers and allow me to procrastinate on the grading just a little bit more.
I have at my disposal a Raspberry Pi (model B) and the ATMega328p microcontroller. I don't have a programmer for the microcontroller so I need the RPi to do that. Fortunately, there are a number of resources around the web to help out with this setup. I could point you to a bunch of links (and here they are to keep me honest, 1, 2 and 3 ), but I'll also walk through the process as well, because it bothered me that I had to do a whole bunch of web searching, to find these bits and pieces. Better to do it all in one place.
Hardware setup
Below is a fritzing diagram of my setup. Note that I have a very minimal microcontroller configuration. I make no attempt to either optimize or protect the microcontroller. It is running off of the 3.3V line of the RPi and I will program it through the SPI interface and communicate with it through the serial UART interface. I use one of the digital out pins to power the LED.
RPi setup
I needed to do a few things here. First, some software. To program the microcontroller, I am using avrdude, which is installed by doing this:
<!-- language: lang-sh-->
sudo apt-get install arduino
wget http://project-downloads.drogon.net/gertboard/avrdude_5.10-4_armhf.deb
sudo dpkg -i avrdude_5.10-4_armhf.deb
sudo chmod 4755 /usr/bin/avrdude
It'll also be important to tell your RPi that you plan to use the UART for your own purposes; the default behavior is to allow console acess throught the TX/RX lines. You can disable this behavior easily through raspi-config
under the advanced options.
There are a number of not-so-obvious but straightforward steps that need to be performed to complete the microcontroller setup. First, in any folder in which you will be creating a project, you'll need a makefile
which looks something like this:
ARDUINO_DIR=/usr/share/arduino
BOARD_TAG = bob
ARDUINO_PORT = /dev/ttyAMAO
ARDUINO_LIBS = include /usr/share/arduino/Arduino.mk
The big difference is going to be the 2nd line. I called my microcontroller "bob" and he has a profile that is very similar to the profile for the "uno" microcontroler except for one minor difference; "bob" has a much lower clock frequency. One reason for this is because I forgot to buy a 16 MHz crystal when I bought the ATMega328p. The 2nd is that I want to make sure that the microcontroller is not drawing too much current from the RPi, so I keep it running only as fast as I need it to. Essentially, I modified the file
/usr/share/arduino/hardware/arduino/boards.txt
to contain an additional entry that looks just like the one for uno except that the symbol names are prefixed with bob instead of uno and the CPU line is 1000000L.
We should be good to go at this point, and can check to see if that is true by doing
avrdude -p m328p -c gpio
Code
I made a file called morse.ino, which looks a lot like c with some additional libraries to make writing to and reading from the microcontroller's pins a bit easier.
<!-- language: lang-c-->
#define LED 7
#define DAH 300
#define DIT 150
#define CPAUSE 100
void setup(){
Serial.begin(9600);
Serial.setTimeout(1);
pinMode(LED, OUTPUT);
}
void loop (){
if (Serial.available()) {
char ser = Serial.read();
switch (ser) {
case '.':
digitalWrite(LED, HIGH);
delay(DIT);
digitalWrite(LED, LOW);
delay(CPAUSE);
break;
case '-':
digitalWrite(LED, HIGH);
delay(DAH);
digitalWrite(LED,LOW);
delay(CPAUSE);
break;
case ' ':
delay(3*CPAUSE);
break;
}
}
}
We can compile this by typing make and then flash the microcontroller with
avrdude -p m328p -c gpio -e -U flash:w:build-cli/morse.hex
Wolfram
<!-- language: lang-mma-->
Now let's hop on over to wolfram to make sure everything is working. We can open the serial device with
dev = DeviceOpen["Serial","/dev/ttyAMA0"]
and after having flashed the microcontroller with the code above, sending a "." or "-" will cause the led on pin 7 to blink.
DeviceWrite[dev,"."]
Lastly, I created a small Mathematica package that contains a couple functions to convert a string of alphanumeric text into morse code and fires that off to the microcontroller: (I grabbed the morse code symbol from this source).
BeginPackage["ArduinoMorse`"]
morsecode::usage = "List of rules to convert characters to morse code"
createMorseString::usage = "Converts a string of characters to morse code"
blinkMorseString::usage = "Blinks morse code"
Begin["`Private`"]
morsecode = (#1 -> Characters[#2]) & @@@ {
{"a", ".-"}, {"b", "-..."}, {"c", "-.-."},
{"d", "-.."}, {"e", "."}, {"f", "..-."},
{"g", "--."}, {"h", "...."}, {"i", ".."},
{"j", ".---"}, {"k", "-.-"}, {"l", ".-.."},
{"m", "--"}, {"n", "-."}, {"o", "---"},
{"p", ".--."}, {"q", "--.-"}, {"r", ".-."},
{"s", "..."}, {"t", "-"}, {"u", "..-"},
{"v", "...-"}, {"w", ".--"}, {"x", "-..-"},
{"y", "-.--"}, {"z", "--.."}, {"0", "-----"},
{"1", ".----"}, {"2", "..---"}, {"3", "...--"},
{"4", "....-"}, {"5", "....."}, {"6", "-...."},
{"7", "--..."}, {"8", "---.."}, {"9", "----."}
};
Clear[createMorseString];
createMorseString[str_String]:=str//Characters//ToLowerCase//(#/.morsecode &)//Flatten//StringJoin;
Clear[blinkMorseString];
blinkMorseString[dev_DeviceObject,str_String]:=DeviceWrite[dev,str]
End[];
EndPackage[];
We can now do something like
blinkMorseString[dev,createMorseString["SOS"]]
and voila, my microcontroller is sending a morse code distress signal, probably because the pile of ungraded lab reports is toppling onto my hardware!
I made a short video showing how the first 7 letters of the alphabet look. It's riveting.