Surviving ECE 3720 Microcontrollers Lab at Clemson University

This lab is known to be one of the most difficult labs in the Electrical Engineering major, partially by design and partially due to the disconnect between the class and the lab and the luck of which T.A. you get. Hopefully some future students will find this page helpful.  You can also download the Clemson Microcontrollers Lab Manual for ECE 3720 on this page.

10/2/2019 - At the request of the ECE department I went through and removed the code and circuit diagrams and some other things.  Sorry future students - you gotta learn a little bit yourself.  Know that there is actually a lot of help in Bill Reid's homework problems or slides, you just might have to look ahead a few days/weeks. One of the main purposes of this lab is to teach you how to look through datasheets and manuals to figure out how a certain controller, component, or system works.  Use the PDF's below, most of the things you need are hidden somewhere in them. 


Good luck, and please don't let this lab turn you away from microcontrollers.  Things are much easier if you use an Arduino Uno or a ESP8266 where it's easy to use external libraries and accomplish more complicated projects with less work.  Just poke around the Projects page on my website - All of those are running off an Arduino or ESP8266, and I never had to set a single registry or interrupt priority or anything. 

If this page is helping you get through the lab, would you consider buying me a coffee or a beer?  

Venmo - @jakabo27  or click here


Microsoft Visio Components


The main hardware in this lab is the PIC32MX150F128D microcontroller.  I'll call this the PIC32 for most of this page because that name is crazy long.  The controller is made by the company Microchip.  


The lab also uses lots of peripherals such as a push-button, potentiometer, digital latch chip, LEDs, resistors, a motor, a digital encoder, and lots more.  If the lab provides you with your own personal hardware at the beginning you shouldn't have any problems caused by faulty hardware.  In the past students have used common equipment in the lab that was often years old which caused countless headaches in the lab as they tried to troubleshoot faulty hardware.  

Software - personal installation

The main IDE used in the lab is MPLAB X IDE.   It is preinstalled on the lab computers, but since we have our own hardware you might find it helpful to have this software on your personal laptop or desktop computer so you can do the labs at home.  The steps for getting it working outside of lab aren't simple, so I've typed them below.  

Note - these steps might not be the most efficient way to do it.  I did steps 1-3, found that interrupts didn't work, then figured out steps 4-5.  So yeah, mess with the steps at your own risk.  Also it probably doesn't work on Mac. 

1. Install MPLAB X IDE:
2. Install the XC32 compiler
3. Download and install the legacy peripheral libraries

4.  Copy ALL FOLDERS AND FILES in C:\Program Files (x86)\Microchip\xc32\v1.40\pic32mx to C:\Program Files (x86)\Microchip\xc32\v2.10\pic32mx and replace any duplicates

5. Download and unzip the following file:  This is an earlier version of the XC32 compiler that supports interrupts..  Paste the entire "v1.40" folder to C:\Program Files (x86)\Microchip\xc32\   Note:  If that download breaks because I deleted the file, I got it by copying the entire v1.40 directory from the lab computers. 

Once you load the software and plug in your microcontroller it should detect you have a legitimate product and load something like "licensed debugger" for it.  Congrats, now you can program the controller at home!

Lab 1

Lab 1 is fairly straightforward.  They provide the code and the wiring diagram, all you have to do is upload it.  Follow the steps in the lab manual and you should be fine.  

One thing they might not tell you is how to tell the compiler what device you're using .  To do that...

1. Plug in your PIC32 to the computer using the mini-USB cable in the debugger.  

2. Wait until your computer finishes setting up the device

3. Right click your project and select Properties.  

4. Go to the selection for "Device".  and select our microcontroller.  

5. Try to compile your project.  If it doesn't work, go back to the project Properties and set the Hardware tool to Licensed Debugger and the Compiler Toolchain to XC32

How to Create a New MPLAB Project

  1. Click File, New Project...

  2. On the right column select Standalone Project and click Next

  3. Type or paste PIC32MX150F128D and select the one result and click Next  Copy/pastable version:      PIC32MX150F128D 

  4. Select the Licensed Debugger if you don't have your board plugged in, or if it is plugged in select the thing below Licensed Debugger.  Click Next

  5. Select the compiler toolchain you have available.  On your personal computer it should be XC32 (V2.10) or greater.  On the lab computers it's probably something different like version 1.3.  Click Next

  6. Give your project a name like Lab_4  preferably with no spaces.  Select the project location.  Check the boxes for Set as main project and Use project location as the project folder.  Click Finish

  7. Your new project should appear in the file tree on the left.  Right-click the Source Files folder and select New, xc32_newfile.c and give it a better name like Lab4Main.c and click Finish

  8. Open the new file, delete everything in it, and paste the code from a previous lab in it so that you have the header and body set up. 

  9. If you have problems compiling it:  Plug in your microcontroller using the Mini-USB port to the debugger.  Right click your project and click Properties.  Under Hardware Tool:  select chipKitProgrammer - SN: etc.  Then click OK and build your project. 

Lab 2 - Digital Latch

Now the lab starts to get fun! (not) 

The lab manual does a poor job of explaining what you're trying to do.  Here's my translation of what it should do: 

Lab 2 in the Microcontrollers Lab at Clemson requires students to use the PIC32MX microcontroller in tandem with a digital latch circuit to control some LED lights. One pair of lights shows the state of the two digital inputs, while the other pair of lights is controlled by the digital latch circuit. Pressing a pushbutton effectively copies the state of the digital inputs to the latched pair of lights and the lights will retain that state until the pushbutton is pressed again

You can see a demonstration of this in the video on the right. 

Note:  This lab can be accomplished without the use of the microcontroller or the digital latch chip (you can use one or the other), but since the lab tells us to use both we have to come up with a way to use both.  The easiest way to do this is basically to pass the signals through the microcontroller from one pin to another.  (Ex pin 1 is an input, pin 2 is an output, the code says pin2 = the value read from pin 1. )


Pins and Registers

The picture above is your best friend.  Print it out a few times and save it in your notes files. A few things to pay attention to for now about the diagram:

  • The black column with white text labels the pins on the microcontroller by Pin Number.  If I say "Pin 6", it means the pin with pin number 6.  

  • See the green letter numbers labelled PIC32 Register ID?  That's the register associated with the pin.  So for pin 4 it is register RB09.  That means it's Register B, byte 09  Basically you can ignore the R and just look at the other 3 digits.  

  • Note that the pin numbers with an asterisk* beside them means that those pins are 5V tolerant.  Any time you need 5v in your circuit you should try to use these pins for safety.  

TRISBbits.TRISB5 = 1  (PinMode Input/Output)

The command TRIS is used to set a digital pin mode to be an input or an output.  The letter after it is the register the pin is on - so for register B the command is TRISBbits.  For register A it is TRISAbits, and for register C it is TRISCbits.  

The next part you do TRIS and the register you're setting.  

Set the first part = 1 for an input, and =0 for an output.  You can remember these by thinking that 0 is like an O for Output and 1 is like an I for Input. 


To set pin 16 to be an input, you would write the following code:   TRISBbits.TRISB14 = 1;

To set pin 18 to be an output:   TRISAbits.TRISA0 = 0;

LATBbits.LATB9 = 1;  (Digital Write)

The command LAT is used to write a value to a pin.  The pin/register naming is the same as in TRISXbits.TRIS above.  If you're confused, reread that.  


To set pin 16 to HIGH (5V or 3.3V):  LATBbits.LATB14 = 1;

To set it low, =0

x = PORTBbits.RB5 (Digital Read)

The command PORT is used to read the value on a port.  Like in any programming language you can set the value read to a variable.  This one is slightly different in that the part after the dot only is the register code for the pin.  


Store the state of pin 19 into variable dog:   dog = PORTAbits.RA1

Set one output pin to the state of an input pin

In order to set pin 4 to the state of pin 34 you would do the following

LATBbits.LATB9 = PORTCbits.RC5; 

^This is the main part of this lab.  

When you read in the value of the pushbutton you'll probably have to set the output pin to the opposite of the value (ex read in 0, set it 1).  This can be done by putting the not (!) operator before the reading step

LATCbits.LATC4 = !(PORTBbits.RB5);

Set pins to Digital mode instead of Analog

The following code needs to be at the top of the Main loop of your code so that the pins know to be in digital mode instead of analog mode.  Supposedly Analog mode is the default.  Better safe than sorry


Wiring (diagram removed at request of the ECE department)

If you use the LEDs in the NI-ELVIS board you won't need a resistor before the LED because they're build into the board.  

Feel free to use other combinations of input/output pins and modify your code accordingly.  

NOTE - you should use the NI-ELVIS DIO instead of the LEDs, since half the LEDs don't work.  

Lab 3 - Comparator

Summary of the lab:  Our microcontroller has 3 comparators built into it.  You can use these comparators to compare the voltage of an input pin to another voltage and it will change a bit in a register.  The second voltage can be an internal voltage (3.3V, 1.2V, or ground).  The comparator isn't wired to any particular pin, so to output the result you write a pin to the value of a bit in the comparator register.  More on that in a bit.  

CMXCON means "Comparator 1/2/3/X Control register".  These are all set individually, in this lab we set them up as if they are working together.  


1. You need to turn it on!

CM1CONbits.ON = 1;  Note - all registers we cover in this lab have some kind of "on" bit.  Something required to activate it.  Nothing is activated by default(generally). 

The "detailed" explanation for each of these are in the PIC32 Datasheet on pages 211-216.  

IVREF is 1.2V as it says on page 254.  The others are certain pins.  There's a table with C1IND etc on page 23 but it doesn't seem to match up to the pins I had to use to make it work sooo... yeah.  

CVRSS - which voltage reference do we use?  An external reference or internal reference?  If you want an internal reference, use AVdd - AVss which is pin 2 and 40.  We don't use this one.

We'll use the external one which is Vref+ - Vref-.  These are actual pins.  

For our lab:  CVRSS = 1 according to my lab TA.... but I got it working using = 0... so not sure about this.  Maybe someone will share their code with me using 1.  Or it might not matter.  Not sure here.  


This relates to the math that a comparator will perform.  See page 216 in the PIC32 Datasheet pdf. 

CVR<3:0>: CV REF Value Selection 0 ≤ CVR<3:0> ≤ 15 bits  //This means you can do CVRCONbits.cvr = 15 where 15 can be 0 through 15. 
When CVRR = 1:
      CV REF = (CVR<3:0>/24) • (CV RSRC )
When CVRR = 0:
      CV REF = 1/4 • (CV RSRC ) + (CVR<3:0>/32) • (CV RSRC )

We set ours to 15 which is close enough to 16 that it's approximately 75%.  

Expected results

LED 1 should turn on after the potentiometer output passes 1.2V because it is directly comparing to the internal 1.2V reference source. 

LED 2 should turn on at 2.48V, which is 3.3V*0.75 = 2.48V.  This is because it is comparing to the internal 3.3V multiplied by 0.75 because of the value of CVR we set for the comparator.  

LED 3 should turn on at 3.0V because that is what your external voltage reference is at (3.0 V) 

Code skeleton

Lab 4 - Keypad

This lab isn't very hard if your keypad and wires all work.  If your keypad has something broken, it might take you a while to figure out what's wrong and to switch to a different keypad.  If a single one of your columns or rows isn't working (but only one), try a different keypad. 

The keypad is set up with 4 rows and 4 columns.  With the keypad facing you, the left 4 pins are associated with rows 1-4, and the right 4 pins are columns 1-4.  

Code Overview

First do the usual things like set the output pins to output (use B0-B3, pins 20-23) and set all the pins to digital mode.

Internal Pull-Up Resistors

One cool thing about our microcontroller is that it has some internal pull-up and pull-down resistors that you can enable and disable using software.  Most of the pins on Register C definitely have them, I'm not sure about the other registers. 

Note - the homework for Microcontrollers class will help with this part.   

To turn on the pull up resistors for pins 4-7.  You'll need to convert the coto binary.  0xF0 is 11110000.  Now label from right to left C0 to C7: 

This method is how you can set the state of multiple pins on the register at once.  Using the same method if we wanted to set pins C1, C4, and C6 we would do 01010010, which is 0x52 in hex.  

Change Notifications Enable

Our microcontroller also has options for getting notifications when pins change.  I'm not sure we actually need these because of the way our loop is set up, but for good measure include the following code which will enable change interrupts for the pull-up resistor pins

CNENC = 0xF0;  

Startup Sequence

It's always a good idea to make sure your LEDs are all working, so I wrote this short startup sequence that turns on each LED in order then turns them off. 

//Startup sequence
TRISB = 0x0000; delay(10);
LATBbits.LATB0 = 1;  delay(150);
LATBbits.LATB1 = 1;  delay(150);
LATBbits.LATB2 = 1;  delay(150);
LATBbits.LATB3 = 1;  delay(150);
TRISB = 0x0000; delay(10);

Understanding the Bitmask

Their fancy bitmask looks confusing and magical, but if you convert it into binary it really isn't.  See below

Notice that each numberLetter has a single 0 in it.  So when you look through each pair, they have some combination of E,D,B, and 7.  That means that one input pin is set to 0 and one output pin is 0.  Somehow this allows us to isolate which row and column is pressed.  I'm not sure why it works using one pair set to 0 and not one pair set to 1, but it works.  

unsigned char mask[16]={0xEE,0xDE,0xBE,0x7E,

Key Bitmask

The key bitmask simply converts a row/column combination to the hex value on that keypad key.  We need this because our keypad doesn't go 0 to F in order, it goes 1,2,3,A,4,5,6,B etc.

 unsigned char key[16] ={   0x1,0x2,0x3,0xA,

The main loop part of this code can be found in Reid's slides. 

LATC = (mask[count] & 0x0F); 

Set the bits in LATC to the value in the right.  The & symbol here is a bitwise AND operator, basically you're combining the item at spot count with 0x0F (00001111).  The effect this has is that only the right letter in the pair will be written.  So for the first spot, (0xEE & 0x0F) = 00001110 = 0xE.  That means pins C1, C2, and C3 will be high but the others are low. 

if((PORTC & 0xF0) == (mask[count] & 0xF0))

This step looks for a match.  So if the controller reads the values on C4-C7 (because of & 0xF0) and they match the left side of the keymask item, then it is a match.  The second line will set press to the item in the key bitmask for the match we got... So if count was 4 when it found a match, press will be key[4] which is 0xA.  Then LATB = press will turn on/off the LEDs corresponding to that hex value.  

Wiring Diagram removed, sorry!  Just hook the pins of the keypad to input pins on the PIC32. 

Lab 5 - Interrupts

The lab manual actually gives us a lot of help for the code.  I'm going to put some here as a reference

INTEnableSystemMultiVectoredInt(); //Need this line exactly as written!!!  Enables interrupts globally

INTCON - Used to set interrupt edge trigger direction

IECx - Interrupt Enable register

IFSx - high values mean interrupt has occurred

IPCx - Interrupt Priority Control register.  Pick something from 1 (highest priority) to 7 (lowest)

__ISR(vector, ipl) - Interrupt Service Routine - what the microcontroller does when interrupts occur.  Typically Do work, Clear flag, return.  

ISR Flow
Main runs like normal – should have infinite loop executing over and

  1. Interrupt is Triggered (input to MC changed)

  2. This sets a flag

  3. Which in turn alerts the MC that an interrupt occurred

  4. MC saves main state

  5. MC looks up what to do when this specific interrupt occurs

  6. MC executes what it found

  7. If flag is clear, interrupt restores main state and continues operation

Also they want us to use a debouncer, so you'll need the 74LS00N chip from the ECE LAB KIT that you got Freshman Year.  Each kit should have a few of them and we only need one, so ask a friend if you can't find yours.  Future students:  It should be included in the lab kit.  This year there was some mistake with ordering and we got AND gates instead of NAND in Fall 2018.

Note:  The 74LS00N chip needs Vcc to be 4.75V-5.25V, so Vcc will have to be 5V for this circuit.  That means our input pin must be 5V tolerant. 


I used the top two NAND gates, I don't recommend that though because the wiring gets cluttered.  Use two in opposite corners of each other.  Follow the diagram exactly, you don't need any extra wires for the pushbutton.  This circuit is called a SR Data Latch, read more about it here:

Note:  The SPDT pushbutton required for this lab will be supplied when you show up to lab that day.  

Umm... My code isn't working on my computer, I think it's a software version issue though.  The whole interrupt function (void __ISR etc) has red stop signs and exclamation marks beside it, compiling just says Error 255 and Error 2.  

Adding this gets rid of the error flag but still won't compile

#if !defined(__STRICT_ANSI__)
#define __ISR(v,...) __attribute__((vector(v), interrupt(__VA_ARGS__), nomips16))

Lab 6 - Peripheral Pin Select

Our encoder is the 61C22 - go find the datasheet!

Here are some notes I took while our TA (James Bittner) was teaching us 

Peripheral pin select - A mapping system for interrupts to pins.  Can put interrupt 1 on whatever pin you want (with some restrictions) - so if a pin doesn’t work you have more options available to you.  

Input/output mapping - determine which pin to connect to the peripheral.  Think of it as “if you’re going to be using an input function like an interrupt (these are always an input), that’s input mapping.”

Note when setting a pin as input/output - can’t say B6 or A2 - have to do RPB6 or RPA2.  Probably stands for "Remap Pin B6"

Don’t need IOL1WAY or IOLOCK.  Just ignore that info. Important to know they exist but we don’t need them for our projects.  

Important tables

Tables 11-1 - all the input mappings. Table 11-2 is all the output mapping.  These are on page 146 and 148 of the PIC32_Datasheet.pdf (the 330 page one)

Timing Logic

This is the reason this lab is hard.  We have two input pins, and from those we need to determine if it was turned clockwise or counterclockwise.  Seems easy right?  Well it's not.  Kinda.  We got this.  

Look at the picture on the right and consider Output A to be Interrupt 0 and for Output B to be interrupt 1.  That's how you'll wire/code it. 

The first important thing to notice is this:  When one of them is high, the interrupt needs to look for a falling edge.  Look at the green ball I put on the diagram for Output A - it's going to "fall" either to the left or the right, depending on if the encoder is turned to position 1 or to position 4. 


Let's say the encoder is currently in position 3 and it is turned to position 4.  Output B stays constant so that interrupt won't be triggered.  A changes, so since we had it check for falling edge it was triggered.  When it triggers we check and see if B is high or low, in this case B is high.  So we have A Falling EdgeB=HIGH, therefore it has to be Clockwise 3 to 4, so our counting variable should be incremented.  

The combination of falling/rising edge on the triggered interrupt and the state of the untriggered interrupt can be combined to determine any of the 6 direction combinations and whether it is clockwise or counterclockwise.  See the code for more understanding.

Lab 7 - Timers w/ Speaker

Basically we'll toggle a pin on and off really quickly to achieve the desired frequency for a note to play a sound.  This pin will be toggled on/off by an interrupt - each time the interrupt is called, you'll tell the pin to write the opposite of what it just was.  An internal clock on the microcontroller will be used to count how many clock ticks have happened, and by changing the number of clock ticks it counts to we can change the time between each interrupt call and therefore change the pitch of the note.  

This lab comes with skeleton code written for us, woohoo!  The skeleton they gave us is decent, but it will make more sense if you rename (ctrl+r) "i" to "note" or "noteNum" and "j" to "num_notes".  Basically you should just copy my skeleton code because I added more notes, renamed them a better way (You can use D sharp or E flat and it's the same note, denoted by Ds or Eb instead of their cryptic underscore for sharp), and made everything better.  You're welcome. 

Interrupt function vector

You'll find this in table 7-1 on page 88 of the PIC32 Datasheet.  Use Timer 2.

If you want to use a different timer, use a different function vector too. 

The magical "PRx"

So when you read the lab manual you'll come across this sentence:

PRx – Value to “count” to, or value to match

We'll use PR2 for timer 2.  This will set the amount of clock ticks that the controller will count to until the interrupt is triggered again.  In combination with toggling the output value

Note - you can only change the PR2 value in an interrupt.  I think this is because when it interrupts the PR2 isn't counting any more and therefore you can say "hey next time count to 20,000 kay thanks" whereas if you tried to change it while it was already counting some weird stuff could happen.  

Note definition notes

A few things that I thought were kinda confusing:

-The value of r for a rest doesn't matter.  All that matters is that the value is unique.  In the interrupt function we check and see if the value to play is the rest value, and if it is not then we play the note.  So you can make it 69420 for all the code cares.  

-The value beside the note defined is not the frequency!!! So 3400 is not 3400Hz.  3400 is the amount of time it's going to count to until it switches from high to low, so basically it's the period of the note.  So a period of 3000 is a lower frequency than a period of 1500.  I added a comment for the lowest notes and highest notes in the code. 

Writing your own song

If your lab TA is cool (shout out to James Bittner) they'll probably give you a free 100 on this lab report if you program your own song for the controller to play.  This actually is pretty easy - just search for sheet music of the song you want!  Look for simple versions or just the right-hand part of a song, because we can only play one tone at a time for our code.  

Once you have a piece of sheet music in front of you, I recommend the following:

  1. Google "Treble clef note names" and open a picture with each note labelled.  (Unless you played a high instrument in highschool)

  2. Open Microsoft Excel and paste in all your note definition for easy referencing.  This is especially helpful when doing the notes that are up/down an octave from the rest of the notes you've been using. 

  3. Make two columns - "Note" and "Length".  

    1. Under "Note" you'll put the note on the sheet music you're looking at.  So if it's an E flat, you'll put "Eb".  

    2. Under "Length" corresponding with the duration of the note.  If it's a quarter note and you're using my stuff you'll put "t4".  If it's a dotted half note you'll put "dh" or "d4"  (I wasn't sure how I'd want to write it so I made it so either would work)

  4. Once your whole song is written, Copy all the values and then right click and under the paste options find the "Transpose and paste" option.  Do that.  Now your nice column is a row.  

  5. Make a formula to the bottom that is =A1 & "," to add a comma between each note or duration.

  6. Copy everything and paste it into MPLAB.  Congrats, you wrote the code without having to keep track of which note you're on in the list.

Wiring Diagram

Tip - add a pushbutton or something between your speaker and power or ground so that it only plays music when you press the button.  Much less annoying. 


This code is long, you might want to view it at the actual Gist link:

Lab 8 - PWM (Motor)

You'll use PWM and a motor driver chip to turn a motor different directions.  Unlike Arduino boards, PWM is far more complicated than "analogWrite(100,2);" and seems to use the comparators to work. 

Motor driver chip tutorial:

Motor driver raw datasheet:

The new motor they give us (as of Fall 2018) doesn't function the same as their old motor.  This one simply won't turn below a certain duty cycle.  Because of this, we can't run it like the past lab did with 25% and 50%.  

Notes from lab 8

PWM is a variable duty-cycle square wave where you change how long the peak of the square wave is on vs how long the 0 of the wave is on.  By varying the duty cycle you can effectively fake a voltage so that things don’t have to run at full speed or full volume.


This lab is similar to lab 7 in that they both use a timer.  Treat this PR value like the PR value in lab 7. You don’t want to change the PR value while the timer is running, you should only change it in the interrupt.  OCxR is basically the PR value.


OCxRS is a built in buffer that will load into OCxR at the earliest possible time (aka when it is done counting).  This allows you to change it outside of an interrupt. At the end of each signal, OCxR will load the value of OCxRS into it.  Therfore, we don’t have to use a timer interrupt to change it like we did in lab 7. Don’t touch OCxR, just change OCxRS.

The x in OCxR is the output compare that you’re using.  We have 5 OC’s available. Just use two of them (for two directions)


Timer 1, 4, and 5 cannot be used in PWM!! Only Timer2 and Timer3 have this ability.  (I think this is because there is a bit you set for those that tell the output compare to look at timer2 or timer3 for counting, and those are your only options.)  Also you can only use 16-bit mode because otherwise timer2 and 3 are occupied I think. If you used a 32 bit timer you would want to use Timer 3 (because it is odd).


Bit to choose timer:  OCTSEL = Output Compare Timer Select.  

Remember - the timer is not a PWM by default.  So how do we set it up to act as a PWM?

Set the PWM mode (OCM) to 6 or 7 - fault detection on or off, it doesn’t matter which one.  But also according to James changing the mode from off to on or on to off might fix it…. Soooo feel free to change that and keep it in mind.  


Notes:  DON’T USE PIN B4!!! It’s always at 1.2V (The internal reference voltage).  Yeah if you try to output to that it just won’t work.

Duty cycle and period must be integers.  Don’t use fractions.  Fractions bad.

Period - how long do we want the period to last?  PR2+1 is what sets the period (assuming you’re using timer 2)

Duty cycle - set by setting OCxRS as a smaller number than PR2+1

Note - the motor is not driven by a frequency.  It is driven by a duty cycle - how much is it high out of a whole.  So if it’s on for 50% of the time it might run at half the power of full.  

Note - either have a debouncing circuit or a delay in your code so that when you press the pushbutton it doesn’t read it 5 times before you release the pushbutton.  I opted to just add a 0.2s delay, but you could also add the complicated debouncing circuit if you want.


Random note:  My code seems to work backwards of the logic that should work for two motors.  When I set OCxRS to 100 it should mean 100% duty cycle which would be full speed, but instead mine doesn’t move.  Then at OCxRS = 0 my motor is full speed. Idk why this happens - maybe I wired something wrong with the motor driver chip.  Soooo if it doesn’t work, just change the array with values to 0, 25, 50, 75, 100.

Lab 9 - Serial Peripheral Interface (SPI)

Use the DIO on the NI-ELVIS board for your LEDs because they usually don't have 7 functioning LEDs. 

Lab 9 Notes from the great James Bittner

What is SPI and what is it used for?  It is a communication protocol.

Some other protocols are I2C, UART.  I2C is for complicated sensors like gyroscopes.  UART is typically for communicating with other processors.  SPI is typically to communicate with liquid displays (LCDs) and basic IC’s (like we use in lab today).  SPI is different in that it works off a master-slave protocol. A single processor is defined as the master of the network.  All the connections are made to the slaves of the network.

The master can have multiple slaves, but slaves can only connect back to the master.  Slaves can’t talk to each other. (wow this is really dark honestly)


Block diagram 1 - SPIxSR is a shift register.  It’s internal to the SPI and necessary for it to function properly.  Think of it as the volume controller - how many bits and how far they can go at once.

Don’t talk about the FIFO block in your code.  Everything will run just fine if you don’t tell ti what to do, but if you try to mess with it then bad things might start happen.  It will manage everything for us.

We get data from the SPIxBUF buffer.  

NOTE - SPI doesn’t save things in the buffer!! As soon as you write something to it it gets shifted out and it’s gone.  Basically the internal circuit will deal with data so that we don’t have to. So don’t put anything in the while loop dealing with it, just deal with it in the interrupt.  


M___ = master mode operation.  (S____ = slave)

MCLKSEL = master clock select.  Set it to 0 to use the PBCLK (peripheral bus clock)

FIFO = first in first out.  The first bit you put in is the first bit that goes out.

SS = slave select.  

MSSEN - master slave select enable.  

Set the Baud rate to 1000 ish.  Depending on your TA they'll tell you somewhere between 2 and 1000.  I did 666, Grant did 500, James told us to do 1000, so yeah anything works. 


What data widths are available?  (how many data bits can you send at a time) 8, 16, 32, and 24.  24 is for SPI in audio mode. We use 8 because that is what our chip is designed to use .

Which pin controls SPI data output (SDO)?  DISSDO - we need SDO, so you should probably set this to 0 so we can use it.  

We need that will pulse 8 times for every 1 time the RCLK pulses.  We do that by setting some waveform stuff woohoo. Pulse SRCLK 8 times to get 8 shifting operations.  


Set ~SRCLR to HIGH.  Set ~OE to gnd.

Lab 10 - Analog to Digital Converter (ADC)

Just like SPI, this uses a ton of configuration bits!! Woohoo!! 

This actually should be kinda cool - you use a Force-Sensitive Resistor (FSR) circuit and display the input voltage like a bar graph on 8 LEDs

Final Project Inspiration

Basically you want a project that uses some combination of the following:

  • User input - buttons, keypad, use the rotary encoder for increase/decrease, etc.  

  • Sound - either do it like in the Timer lab, or use PWM if that's easier.  It's easy to have some kind of a celebration sound on your project, or just have a sound play whenever the user presses a button and call it "audial feedback for improved immersion and user experience"

  • Lights - why wouldn't you add some lights?  They're easy and we've been using them the whole semester. 

  • Quantum tunneling with quark-boson spooky interaction - I thought lab 61 was really helpful, you should definitely implement these in your project for a guaranteed A.  

Requirement Details straight from James Bittner

James says there are two questions you should answer for him about your proposed final project ideas:

  1. Why should I accept this idea as a final project?

  2. Why would it be useful?

Some examples of the usefulness part:  The pirate ship that sailed the 7 seas purpose might be a Hasbro toy

Chainsaw that sang lumberjack tunes at you - chopping wood

Things that makes their grading more lenient

Including things that we have not discussed in class.  Ex. using a LCD display, stepper motors, linear actuators, etc.

Things that make the TA laugh.  Well at least on days that he got enough sleep.  

Past projects we've heard about

  • Attempt at a DIY drone using a remote control module bought online (Trent Loftis)

  • "A ship that sailed the high seas" -  I think this was some kind of a battery powered project that could float?  Not sure lol 

  • Attempt at a "Frogger" arcade game using a LED matrix bought on eBay (James Jolly)

  • Keypad lock like on the door with sounds

  • Equivalent of combination lock with encoder

  • Pinball machine that kept score

  • Force sensitive robotic arm with force sensitive grip from balsa wood

  • Program controller to accept tv remote commands

  • Someone is gonna try to make a radio connection so one will play the song and the other will receive the song

  • A "frog" that can hop - somehow using a 3D printed frog and some motors (different than in lab I think) making a frog that can hop

  • A singing christmas card that plays a song on demand - Jenny bought a singing christmas card and tried to make it so that when you press a button on the controller the song will play

Hardware Resources

Clemson actually has a lot of tools available to us if you want to make your project look good.  

  • Makerspace - the makerspace in the Watts center (As of fall 2018) has a laser cutter, CNC machine, 20ish 3D printers, and various tools like exacto knives and pliers and all the usual stuff.  They have staff that can tell you how to use things.  Overall it's an amazing resource you should totally use if you want to score some extra design points for your final project

  • Soldering - The basement of Riggs has soldering stations you can use if you need to do any soldering for your final project.  Alternately, buy your own!  A soldering iron is like $15-$50 with the high end being super nice.  [Cheap kit] [Expensive one]  My personal opinion:  You should know how to solder as a junior/senior electrical engineering major.  If you don't know how to, go learn while you're still in college!

Software Resources

Instructables!!  Or google.  Just look up "arduino project" and you'll find plenty.  This can also be a good way to find code where you can copy the general algorithm instead of coming up with everything on your own.  Arduino is also written in a variation of C, there are just different variations on how the hardware on the microcontroller is interacted with.

My Final Project

The final project that I (and kinda sorta ish Michael)(he came up with the idea, I did the entire project) ended up doing is a security suite.  It has a PIR motion sensor, a piezo speaker, a keypad, a rotary encoder, a 7-segment display, and uses two SPI chips.  You press A on the keypad to arm the system, then if the motion sensor detects movement the speaker/alarm goes off until you put in the correct password.  The password is put in with the first 5 digits being on the keypad and the last 3 digits being on the rotary encoder.  The 7-segment display is used to show the current number for the encoder or the number you pressed with the pushbutton or the status of the system ("A" for armed, "C" for check or complete)

I've put the code from my final project below, you might find it useful if you're using lots of components together.  Note that I didn't use an interrupt for SPI, and I don't have the buzzer always making noise like we did in that lab.  

One challenge about this project was mapping pins so that everything could work together.  The rotary encoder needs to use three separate interrupts and they all need to be mapped to 5V tolerant pins.  Then there needs to be a separate interrupt for the PIR sensor which also needs to be 5V tolerant.  Lastly, the keypad code used in a previous lab used pins 0-7 on register C, so all the other interrupts needed to not use pins C0-C7.  I printed out a sheet with all the input and output remapping options and eventually figured out a combination that would let everything work together.

Quiz tips and help

The lab also has some kinda confusing quiz questions.  

If you're feeling social with your lab group and other class members you'll probably hang out together.  Maybe you'll hang out together before a quiz is due.  I don't know why it would happen, but it's possible that the subject of the quizzes will come up.  You could even complain about the questions to each other!  Maybe while you're there someone will take the quiz while the others are talking to them.  You could even work together to do the quizzes and get good answers.  Since the person that takes the quiz first probably won't get 100, you should probably rotate who takes the quiz first each week.  

Jacob's Custom Library

Update from Jacob later on in the semester - we get into things that are far more complicated than a library can handle.  This is nice for the first few labs, but then you need to use register names like they want us to. 

I found the programming language provided for the controller to be cumbersome when using digital inputs/outputs, so I wrote my own functions for the following functions that should be familiar to anyone that has used Arduino before:

  • delay()

  • digitalWrite()

  • digitalRead()

  • pinMode()

If this page helped you get through the lab, would you consider buying me a coffee or a beer?  

Venmo - @jakabo27  or click here

Jacob Thompson

Clemson, SC

© 2020 By Jacob Thompson

Terms of Use and Privacy Policy

  • Facebook Social Icon
  • Instagram Social Icon
This site was designed with the
website builder. Create your website today.
Start Now