Message Boards Message Boards

Communicating with the ATMega328p microcontroller via Wolfram/RPi

See full video here: https://youtu.be/OLVH-2cFiGg
enter image description here

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.

enter image description here

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.

POSTED BY: BoB LeSuer
2 Replies

enter image description here -- you have earned Featured Contributor Badge enter image description here Your exceptional post has been selected for our editorial column Staff Picks http://wolfr.am/StaffPicks and Your Profile is now distinguished by a Featured Contributor Badge and is displayed on the Featured Contributor Board. Thank you!

POSTED BY: EDITORIAL BOARD
Posted 10 years ago

Your students are lucky -- and not just because their papers aren't getting graded. ;-)

POSTED BY: David Keith
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract