Printer-friendly version
Programming in C, a Primer
Purpose
This document is meant as an aid for those who have minimal or no programming background.
Description
In Gadgetry, we will be programming microcontrollers using a version of the C programming language that has been specialized to small 8-bit microcontrollers. C is perhaps the most durable programming language ever; it is still relevant 30-40 years after it was designed. This document will cover the very basics of programming in C. We will discuss syntax, variables, conditionals, loops, and functions (concepts that are common to all programming languages) and do so while showing examples that use C syntax.
Syntax
Syntax for programming languages is like grammar for natural languages: It is the rules under which statements are structured. It is also the most common cause of errors for beginning programmers. The syntactic rules of programming languages are very strict, and violating them will cause either compiler errors, or (possibly worse) logical errors that allow your program to compile but function in mysterious ways. Here are two general syntactical rules:
End statements with a semicolon, except when otherwise indicated
Make sure every open brace has a matching close one, and keep track of brace pairings
Each of the following topics will show some proper syntax for using a given construct.
Variables
Variables are just program elements that store a value (that can be varied during program execution). There are many types of variables, but there is only one that really matters to begin writing programs: The int variable type (if you want to look up other types, you can also use char, bool, float, and double types in your programs). An int is a variable that stores integers, or whole numbers. This type has a natural range of numbers – it can store any number between -32,768 and +32,767 (it is 16 bit, so the range can have no more than 2^16th positions, and the range is centered on 0). To declare a variable in C, do the following:
int theAnswer;
You can also give it an initial value:
int theAnswer = 42;
Variables must be declared at the start of a function. Once declared, you can use them throughout the function (Which is not the same as your whole program if you have multiple functions). Note that once declared, you don’t need (and aren’t allowed) to put the keyword ‘int’ before them. For example:
int main(void)
{
// This is a comment – the start of the function comes after the open brace “{“
// Here I am declaring three variables
int theAnswer = 42;
int questionOne = 6;
int questionTwo;
// Here I am using the variables in my program – note no “int”
questionTwo = theAnswer/questionOne;
}
If you want to make a variable that can be used in multiple functions, you can declare what is known as a global variable. You should do this right after any #include and #define statements are used, but outside of any function braces. Global variables are commonly used in this type of embedded programming.
You can use regular mathematical operations with integers (+,-,*,/), but be aware that you should avoid exceeding the integer range. Also, since ints are integers, if you divide and have a remainder, the remainder will be removed (so 23/5 = 4, NOT 4.6). If you want to see what the remainder would be, use the modulus operator ‘%’ (as in 23%5 = 3).
If statements
If statements are ways to have your program execute fragments of code only if certain conditions are met. Thus, they are very important to use if you have sensors on your gadget and want to do something based on a sensor value. The following is the basic structure of an If-statement:
if(condition1 is true) {
execute plan A;
}
else if(condition2 is true) {
execute plan B;
}
else {
execute plan C;
}
The structure is very flexible – the only required part is the if, you can opt to have an else, or an else if, and you may have as many else ifs as you like (though only one else).
The part in the () is the conditional statement that is evaluated. There are a number of logical operators that can be used to create a conditional statement – they are: less than ‘<’, greater than ‘>’,less than or equal to ‘<=’, greater than or equal to ‘>=’, equals ‘==’ (yes, two equal signs, you use one for assigning a value to a variable, two when comparing two values). Furthermore, you can chain statements together to make larger statements through the use of a logical or ‘||’, and a logical and ‘&&’. Lastly, you can logically evaluate a single variable in an if-statement without any operators. This works because in C, any value that is 0 is consider false, and a value that is not 0 is consider true. So you can construct an if like:
if(theAnswer)
{
print(“theAnswer is clearly non-zero”);
}
This is useful when you have digital inputs like buttons, as they will be read in as either 0 or 1, depending on if they are open or closed.
For an if-statement, you should place any code you wish to execute for each statement in { } after the if statement. You should not place a semicolon after the if, else if, or else statements. The following are some example statements using proper syntax:
int main(void)
{
int theAnswer = 42;
int question1 = 6;
int question2 = 9;
int sensorValue;
if(theAnswer == (question1*question2)) {
blinkGreenLED();
}
else {
blinkRedLED();
}
// Here we’re calling a function that will return a value, which is copied into ‘sensorValue’
sensorValue = readSensor();
// In English, if the sensor is less than 100 and more than 50, do the following
if((sensorValue < 100)) && (sensorValue > 50)) {
blinkGreenLED();
}
else if(sensorValue >= 200) {
blinkRedLED();
}
else if((sensorValue <=50) || (sensorValue > 100)) {
blinkOrangeLED();
}
else {
turnOffLEDs();
}
Looping
Looping is a way to specify repetition in your program without having to write repetitive code. There are two types of loops you may wish to use – the while, and the for. The for loop summarizes some things in the loop statement and so can make your code somewhat more concise. The while loop looks like this:
while(condition is true) {
do stuff;
}
You’ve learned about conditions from if-statements; the ones used by the while loop are of the same structure and can employ the same logical operators.
The for loop is a little trickier:
int counter;
int someValue = 14;
for(counter = 0; counter < someValue; counter++) {
do stuff;
}
The for loop has three elements – first it sets a pre-declared variable to a value, in this case 0. Then it has a conditional statement using that value (in this case, checking if it is less than someValue). Finally, counter++ is a short hand way of saying increment the value of counter by one (equivalent to counter = counter+1;). This is convenient if you wanted to run through some code a set number of times. Just like if statements, for and while loops don’t end in semi-colons.
In our case, all programs you create will have a while loop that executes part of your program so long as the gadget is turned on. This is called an infinite loop. This loop will contain the main elements of your program, and within it you will probably do something like check sensors –> evaluate sensor data with if-statements -> do something with outputs based on sensors. You may also have loops within this infinite loop. A loop within a loop is called a nested loop.
Functions
Functions allow your program to be compartmentalized. For example, you can have a function that reads a sensor, or blinks an LED. By using a function, you only have to write the code once for that function, and you can then call that function in your program as much as you want. All programs have at least one function, called main – this is where your program starts. In main, you can call functions from a library, or functions you’ve written. For each function, you can both send and receive values. Values you send to a function are called arguments, values you receive are returned. Some functions only have arguments and no return, some have just return values and no arguments, some have both, and some have neither.
---
Circuit Board Checklist
Printer-friendly version
Circuit Board Checklist
Purpose
This checklist can be used to minimize errors made when creating the schematic and layout files of a gadget. If any of the checklist items are unclear, email us with your question and put your files on your project page.
Schematic Items
___ The ISP header is in the schematic and the pins are connected to the same I/O pins as in the GadgetCore.sch.
___ There is a connector for the battery/power supply; either a three pin connector for a pack of AA or AAA batteries, or the coin cell holder if running from a coin cell, OR connection to VUSB for usb power.
___ You have used a voltage regulator for 3.3V or are using a coin cell. You are using the medium voltage regulator (same circuit as the +5V, but different value) instead of the tiny one unless you are only running off USB or a coin cell. An additional 5V regulator is required for the humidity, pressure, and sharp IR distance range finders.
___ The voltage regulator has a capacitor between the input voltage and ground, and one between VCC and ground. The value of these capacitors is 1uF and 10uF.
___ The ERC does not produce errors. The only warnings produced are about either missing values on connectors or about Power pins connected to signals. Note: any errors/warnings from the GadgetCore schematic may be approved.
___ There is a capacitor to decouple the VCC and GND signals for every chip (Xmega, Hbridge, sensor chips). The value of this capacitor is 0.1uF.
___ LEDs are connected to signals in series with a resistor.
___ Light sensors and thermistors use a voltage divider to read in the signal.
___ Buttons are not required to have an external pull-up resistor, but if this is the case they must be connected between the input signal and ground or input signal and vcc. You will use PINCTRL to enable internal resistors.
___ Parts used have only come from the GadgetOne.lbr library, or you received special approval.
Layout
___ Decoupling capacitors are placed physically close to the VCC and GND pins on the part they need to decouple. Copper wires between the capacitor and the chip’s pins are as short as possible.
___ Capacitors for the voltage regulator are placed as close as possible to the voltage regulator, with copper wires between the capacitors and the regulator as short as possible.
___ Connectors are placed logically, generally on the outside edges of the board. When everything is plugged in, the connectors will not collide or obstruct one another (this is especially important for the female header of the ISP).
___ The parts are arranged in as tight a space as possible to still allow for routing of the copper wires. Parts can be placed on both sides of the board, but it is strongly recommended that most surface mount parts be placed on the same side.
___ Mounting holes have been placed to mount the board to a housing. You are not required to have any mounting holes if you prefer to use tape or Velcro.
___ The board dimensions (the rectangle that is brought up by default when the .brd file is first created) are moved to where you want the edges of the circuit board to be.
___ The DRC rules are comfortably above the minimum specifications at this site:
___ The Copper/Dimension clearance in the distance tab in the DRC is 20 mil or more
___ The routed board passes the DRC with no errors.
___ Typing 'ratsnest' yields a message saying 'Nothing to do!'
___ Designators have been moved to clearly indicate part names and values.
___ You've run panelize.ulp to move all your tnames and bnames to layers 125/126 (or so).
___ Your name or initials and the gadget name are visible on the board somewhere. This should be in either tvalues/bvalues or layers 125/126 (or what panelize creates).
___ You checked that your board passed
www.freeDFM.com and you checked the plots of the different layers to make sure they looked right.
Handing Things In
___ .brd and .sch are posted on your project page
___ gerbers sent to freeDFM and the response email forwarded to us. Note: It must say No Showstoppers! in the DFM results section, or you need to go back and fix your board!
---
Board Assembly Checklist
Printer-friendly version
You should print out and have this checklist near your board as you go through the steps. For Gadgets One and Two.
- Acquire all parts, stencil, and PCB for your gadget.
- Fix the board and stencil to the table and apply a thin layer of paste.
- Place all surface mount parts on your board.
- Check all parts. Double-check all polarities (dots / notches) of ICs and diodes.
- Place on griddle and heat until all paste is melted and flux dissipated.
- While still hot, visually inspect board and make sure parts are aligned to pads, particularly ICs. Carefully adjust to ensure alignment, but do not worry about bridging or excess solder.
- Allow to cool.
- Double-check all polarities again in case things got moved during griddling.
- If parts are misaligned severely, use hot air gun and flux to adjust individual parts.
- Inspect board for excess solder / solder shorts (bridges). Remove using hot air gun, flux, and copper braid.
- Solder on Through-Hole and/or any missing parts using the soldering iron and solder.
- Verify that all external/offboard parts can attach properly (sensors, servos, battery holders, etc). Do not connect batteries at this time. Attach any essential parts to your power circuit, such as power switches, but do not plug in power.
- Using a multimeter in resistance (or continuity) mode, verify that VCC and GND are not connected. Large resistances are OK (such as 50k, 200k, 3 megaohm) and are probably your circuit elements. Values close to zero indicate that you have a solder bridge, misaligned part, or wrongly placed part (dots not lining up). Go back to #8 and look again.
- Using the multimeter again, verify that VDD and GND are also not connected except through large resistances. Do the same with any other voltage nets you may have (UNREG, VLED, VMOTOR, etc). Go back to step #8 as needed.
- USB: Using a miniUSB cable, plug board in and verify that the device is properly recognized by your computer. This should only take a few moments. Be prepared to remove the device quickly. If it is not recognized and/or the FTDI chip gets hot, remove it and go back to Step #8, taking extra care to inspect the FTDI and USB connector.
- Power Safety Test: Connect your power circuit to a current-limited power supply. Do not use batteries or wall adapters without a very low current fuse. Set the power supply voltage to your normal unregulated voltage. Set the current to 100-200mA. Use alligator clips to connect the power supply in lieu of your normal method - such as to the battery terminals, coax jack, etc.
- Turn on your power switch. Disconnect the power immediately if the current limit maxes out. Go back to Step #8 and look carefully. If nothing bad happens, proceed to the next step.
- Using a multimeter in voltage mode, verify that your VCC to GND potential is 3.3V. Your power led, if any, should be lit up. If VCC is 3.3V, then your LED may be backwards and need to be flipped.
- If nothing seems to be going wrong, observe your board for a minute or two. Ensure that no chips are getting unusually hot.
- Load the bootloader on and try to program on your first program!
---
Gadget Progress Report
Printer-friendly version
Overview:
Completing a self-evaluation of your progress helps us determine how timely your efforts have been and how far along you are. But more importantly it helps you figure out what still needs to be done on your gadget!
Since this is a progress report it is expected that not all tasks will be complete. But that does not mean you can just throw 'did not do yet' on everything! We will be grading on how well-thought out your evaluation is as well as whether you've made reasonable progress in the 2.5 school weeks you've had to work on this.
Submission:
Respond to this questionnaire by March 24th via an email titled 'Gadget One Progress Report' to cmugadgetry@gmail. Please, no pdfs or attachments, simply quote it in email and respond under each relevant section.
Progress Report Sections
Circuit Board & Parts:
The first step in getting your gadget together is making sure your circuit board is assembled and working. You should have all of your parts on the board, and any external sensors and actuators should be mounted and ready to test.
Have you assembled your PCB?
Did you run into any issues completing the Board Assembly Checklist (in Course Documents)?
Have you loaded on the Bootloader?
Do you have all of your external components (if any) attached to your board and ready to test?
Housing:
The housing is a key component - this is what turns yet another green fiberglass rectangle into a human-usable device. This is the what a user will see and this creates the first impression on your gadget's utility. Ideally it is informative and not mysterious.
Have you thought about Assignment 10 and posted your sketches/designs?
Have you assembled your prototype housing? How did it go?
Have you revisited Assignment 10 and completed the self-evaluation section?
Is your housing workable as-is? Or what do you plan on improving before the final demonstration?
Firmware:
Firmware is simply software that is not expected to change much, if at all, over the course of a device's lifetime. For extremely well-engineered (for cost and volume) systems, reprogrammability is not always an option. In our case, however, it gives you flexibility as you fine tune your prototype to perform a desired task, whether it be what you initially planned for or a new, better idea that has come to you.
Since your gadget is designed to 'translate ambient information', we can think of the software not as a bunch of code but as a few simple functions or transformations. While it sounds fancy, all it means is that you wish to take one type of information and convert it to another in a predictable way. If writing code is not your strong suit, having a clear understanding of the desired transformations will make the programming task far more straightforward.
Have you tested your bootloader? This can be done with old assignments such as 'MysteryProgramtoCompile'. You should be able to reliably enter the bootloader and reprogram new programs over and over.
What transformations do you need to achieve? What is your input and what are your outputs? In the case of sensor and actuators, it is important to understand the range of values you anticipate. What values do your inputs vary between? What desired variance do you want from your outputs?
Have you begun writing your Gadget One firmware? You should have a new project - perhaps the 'GadgetOne.zip' skeleton from the 'Gadget One library' section of Course Documents. Pasting in functionality from previous homeworks and AVR drivers is OK!
Plan for Unfinished Work:
Not having everything completed is OK. Not knowing how you'll finish the remainder is not OK. By now you should have a pretty good idea on how to approach the many miscellaneous tasks needed to put a gadget together. If you are having trouble imagining how to complete a few of the remaining sections, then please let us know so we can talk it over or cover additional material in class.
Briefly summarize what you still have left to do.
What do you see as the most difficult aspects? What specifically makes them hard?
Were these aspects covered by any lecture or homeworks? If so, which ones? If not, which ones seem closest?
---
Bootloader and ISP
Printer-friendly version
Gadget Bootloaders
Included here are two bootloader files for Gadgetry Gadgets. We utilize the XBoot, a nice and flexible bootloader from
http://code.google.com/p/avr-xboot/ . It lets you choose miscellaneous options like which port to look for data on and how to enter the program (such as holding the button down on powerup).
The first, dated 1-11-2011, runs at 115200. The second runs at 19200 and is standard on macs and all gadgets from G1 on. The source code for our specific variants is also attached.
Loading Bootloaders
There are two steps in getting a bootloader working. You need to load the bootloader on using an external In-Series Programmer (ISP). Then you need toenable the bootloader reset fuse, also via the ISP.
- Load AVR Studio or equivalent onto your computer. To use the AVR Dragons in the lab, best to use AVR Studio 5 beta. It is already loaded on the REL laptop Lothlorien.
- Open AVR Studio and connect the AVR Dragon via USB.
- Connect the 6-pin cable between your gadget and AVR Dragon and ensure that your gadget is powered on.
- Go to the Menu and select 'Connect to AVR programmer'
- Choose 'AVR Dragon' instead of AVR Simulator.
- Choose ATXMEGA32A4 from the long list of chips.
- Click 'verify voltage'. If it isn't 3.3V, make sure your board is powered up and the 6-pin cable is plugged in the right way. Then try again.
- Click 'read signature' and make sure it reads a valid ID.
- Click 'load program' and choose the xboot-19200.hex from the list and hit program.
- Now, click on the Fuses tab.
- Go through the list and ensure that BOOTRST is selected (other option is Application Reset). If your gadget has had a bootloader before, it should already be selected. If you have a brand new xmega, it defaults to application reset.
Modifying the bootloader
Attached in xboot.zip is our specific configuration of the
xboot bootloader . If you have an ISP and want to modify the behavior (such as changing where the button is, serial uart, etc.) you can make the appropriate changes, recompile it, and load it on using the instructions above.
---
G2 Code Snippets
Submitted by admin on Mon, 04/18/2011 - 12:26
Printer-friendly versionAttached is code to run the accelerometer, the LCD, and SD card. Note that in all cases, you'll need to integrate the provided code into your projects, either by copying and pasting appropriate sections, or by including the .h and .c files.
Attached is some SD card code, courtesy of Vikram R., a Gadgetry '10 student. Here is his comments for it:
I've attached the code for a simple program that will create a file
"hello.txt" and write "Hello World!" to it.
The Xmega specific stuff should be taken care of. You should only need to change the pin defines in sd.h to correspond to the SPI port you are using and/or the pins you are using for card-detect.
If you aren't using card-detect, you'll need to delete references to the
sd_card_present() function, or simply set it to always return true.
Depending on which timer counters you are already using, you may need to
change the timer counters in sd.h and/or rtc.h if there is a conflict.
The rtc.c/h files are used for counting time to use for file timestamps.
Please note that the present method is not accurate. I haven't figured out how to properly configure and use the Xmega's internal 32kHz calibrated RC oscillator to count seconds. If anyone can provide code for this, I would appreciate it.
Documentation for the FAT library is here:
http://elm-chan.org/fsw/ff/00index_e.html
---
Care and Maintenance of Solidoodle Printer
Printer-friendly version
Software Packages
Design: Anything that outputs an STL file. Solidworks recommended, you can also use Trimble Sketchup though you'll need to install a plugin to allow STL output. See the following for a Sketchup tutorial:
http://www.solidoodle.com/how-to-2/how-to-create-a-3d-part/
Printing: Repetier-host is recommended. See the following tutorial for configuring Repetier:
http://solidoodletips.wordpress.com/2012/08/22/setting-up-repetier-host/
In the REL
- Before you print, plug in the big Solidoodle power supply and plug the USB cable into your computer.
- Set the heated bed temperature manually to 85C - it'll take 20 minutes to warm up, so it's useful to do this first.
- Import your STL file into Repetier and generate G-code as documented in the Repetier tutorial.
- Printing will take 1-4 hours (or more), and your laptop needs to stay with the printer. You can wander off, but try to check on the printer every half hour. If something goes wrong, hit the E-stop in the software and decide if you want to/can start over. Email cmugadgetry@gmail.com if the printer broke or did something naughty.
- Once the part is complete, unplug the Solidoodle's power supply but not the USB cable. You'll need to wait for the heated bed to cool to 40C or so (wait 20 minutes); once there it will be possible to remove it just by grabbing it. If it's small, you can use pliers.