question in decimal, what will 169 look
like on the LEDs? Well, good luck on
doing that in your head.
char — The name of this data type
is short for character, and is typically
used to represent a character in the
ASCII character set. Originally, there
were 127 ASCII characters used by
Teletype machines to transmit and
receive data. Remember that in Figure
1 of Workshop 1, you saw Dennis
Ritchie who wrote C standing next to
Ken Thompson who wrote UNIX, working on a Teletype machine. Clunky as
they were (the Teletype, not Ritchie
and Thompson), Teletypes were
light-years ahead of entering data by
individual switches representing each
bit of data. Teletypes send and receive
characters so a lot of C, especially the
standard library, stdio, is character
oriented. The number of bits in a char
is machine dependent, but in all
machines I’ve encountered including
the AVR, a char is an eight-bit byte that
can have 256 bit states. The computer
uses this byte of data as representing a
signed value from -128 to +127.
unsigned — If the modifier
unsigned is used in the definition of a
char variable ‘unsigned char,’ the value
is from 0 to 255. Many C compilers
will have ‘byte’ or ‘Byte’ defined as
equaling unsigned char. The byte
keyword is not part of C, but it is very
convenient, since in microcontrollers
we usually use a lot of numbers, but
not a lot of ‘char’acters.
int — On AVR microcontrollers, int
(short for integer) declares a 16-bit
data variable as having values from
-32768 to +32767. A variable declared
with ‘unsigned int’ will have a value
from 0 to 65535.
The long and short of it —
Everybody else makes that dumb joke
at this point, so why be different? You
can declare variables as ‘short int’ and
‘long int.’ For C, the size is machine
dependent, but on many systems a
short int is the same as an int ( 16 bits),
while a long int is 32 bits.
uint8_t and uint16_t — More
recent C standards use uint8_t for an
eight-bit unsigned char and uint16_t for
unsigned int. This increases portability
between machines and lessens confu-
sion about the size of the
data type we are using.
Operator Name Example
 Array element x[ 6]
. Member selection PORTD.2
A declaration is a text
statement that declares to
the compiler how your
words are to be used.
When you declare
‘unsigned char counter = 0’
you are telling the compiler
that when it encounters the
word ‘counter’ to consider
it as data stored at some
specific address with the
alias name ‘counter’ that
can have values from 0-255,
but in this case, it initially
has a value of 0.
Seventh element of
Bit 2 of port D
Member x of the
-> Member selection pStruct->x structure pointed to
* Indirection *p Contents of memory located at address p
& Address of &x Address of the variable x
TABLE 1. Data access and size operators.
Call wait with an
argument of 10
Type cast (double)x x converted to a double
If x is not 0 evaluate
?: Conditional x?y:z y, otherwise
, Sequential evalution x++,y++ Increment x first, then increment y
TABLE 2. Miscellaneous operators.
The changeable data you are
processing is stored in bytes of RAM
(Random Access Memory) at specific
addresses. Variables are names that
provide an alias for the address being
used. We’ll look at those gory details in
a later Workshop.
they are explained fully in later
Workshops. Then they’ll seem even
stranger. You may already be familiar
with some of these operators, and
rather than take space elaborating
each, we will wait to see how they are
used in context in later Workshops.
We will save the Arithmetic
operators for Workshop 4 and in
Workshop 5 we will look at Logical,
Relational, and Bitwise operators.
Okay, I’m tired of all these words,
let’s play with some hardware!
Literal constants are data that are
not really variables but read-only values
that are textually replaced on the first
pass of compilation. The literal’s name
is traditionally typed in all caps, and
located in a header file or at the start
of the software module. For example,
we might want to use pi in a calculation, so we define as follows:
#define PI 3.1415926
We can then use PI anywhere in
our software and the compiler will
automatically substitute the numerical
value for it (Listing 1).
Port Input and Output
Note: Some of these operators
may seem strange at this point, but
We skimmed over a lot in
Workshops 1 and 2 so that we could
get some LEDs blinking. Let’s now take
a more detailed look at I/O ports.
AVRs are available with from six to
86 I/O pins (ATmega169 has 54 I/O
pins). Most of these pins are organized
into eight-bit ports. Many of the pins
have more than one possible function.
They can be used to input or output
digital logic data, they might be used
for detecting external interrupts, or for
analog-to-digital conversions and so on.
Pins can be set as either Input or
Output. Pins set as outputs can be
driven to Vcc or Gnd. Pins set as inputs
float pieCircumference = 0.0;
float piePanRadius = 2.2;
// sometimes you just gotta have PI.
pieCircumference = PI ( piePanRadius 2 );
October 2008 63
// we don’t know yet
// this we measure so it can vary