Lecture 7
Introduction to ‘C’ Programming
for Microcontrollers
Start
• int main(void) // start
{
while (1) // repeat nothing to
//infinity
{
}
}
Super Loop
• int main(void) // program starts here
{
Initialize(); // executed once
// Superloop starts here
// These tasks will be executed repetitively
while (1)
{
Task1(); // say read temperature
Task2(); // say process temperature
Task3(); // say display temperature
}
}
• Microcontrollers repeat their operation so we use “super loop architecture”.
• Internal or external interrupts produce an event that causes a routine to be
executed at the triggering time, then normal execution goes on.
• The super loop architecture is used for tasks of low (and medium)
complexity.
LED
• LEDs require about 20mA.
• When 20mA current flows
forward into the LED, the
voltage across it is around 2V.
• The rest 3V are across the
resistor.
• For setting the current to
20mA, R1 should be
3V/20mA=150ohms.
• Less means excessive current
and more means maximum
brightness.
• 20mA is maximum so we
choose less about 180ohms.
• 0 for on and 1 for off.
• Pin as output.
Button
• Configure pin as input.
• When not pressed the pin stays at
logic 1.
• If pressed, current flows through
the button and the port pin is
grounded, logic 0.
• The current flowing is about 1mA
and there is no reason for having
more than that, even the internal
50k pull-up could be used instead.
• 1 for not pressed and 0 for
pressed.
• The capacitor will smooth things
out, it acts as a low pass filter
preventing fast voltage changes
when button bounces
Switch it on
• #include <avr/io.h> // header file
int main(void) // program starts here
{
DDRB = 255; // set port B for output
PORTB = 0; // set port B pins to 0
return (0); // return something
}
typedef
• typedef is a keyword in the C and C++ • Consider this code:
programming languages. int coxes;
• The purpose of typedef is to assign char jaffa;
alternative names to existing types,
most often those whose standard ...
declaration is cumbersome, potentially coxes++;
confusing, or likely to vary from one ...
implementation to another. if (jaffa == 'c')
• Both sections of code do the same ...
thing. The use of typedef in the second • Now consider this:
example makes it easier to
comprehend what is going on, namely, typedef int Apple;
that one variable contains information typedef char Orange;
about apples while the other contains Apple coxes;
information about oranges.
Orange jaffa;
... coxes++;
...
if (jaffa == 'c')
...
C Language Bit Operators
• | bit OR
& bit AND
~ bit NOT
^ bit EXLUSIVE OR (XOR)
<< bit LEFT SHIFT
>> bit RIGHT SHIFT
• These operators work on the individual
bits inside the byte.
Bit Setting
• Code:
unsigned char foo = 0;
To set bit 0 in foo and then store the result back into foo:
Code:
foo = foo | 0x01;
Shorter one:
Code:
foo |= 0x01;
Bit Clearing
• Code:
foo = foo & ~0x01;
Shorter one:
• Code:
foo &= ~0x01;
Bit Testing
• To see if a bit is set or clear just requires
the AND operator, but with no assignment.
• Code:
if(foo & 0x80)
{
}
• The condition will be NON-ZERO when
the bit is set.
Bit Inversion
• Code:
foo = foo ^ 0x01;
Or
• Code:
foo ^= 0x01;
Creating Bit Mask
• The way to build a bit mask with only a bit
number is to LEFT SHIFT a bit by the bit
number.
• To build a bit mask that has bit number 2 set:
Code: (0x01 << 2)
• To build a bit mask that has bit number 7 set:
Code: (0x01 << 7)
• To build a bit mask that has bit number 0 set:
Code: (0x01 << 0)
Macros
• It provides a fast way of understanding what is
happening when reading the code, or it provides
additional functionality.
• Macros are replaced with actual code upon compilation.
• Code:
• #define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 <<
(x))
Macro Examples
• To set a bit:
Code:
bit_set(foo, 0x01);
• To set bit number 5:
Code:
bit_set(foo, BIT(5));
• To clear bit number 6 with a bit mask:
Code:
bit_clear(foo, 0x40);
• To flip bit number 0:
Code:
bit_flip(foo, BIT(0));
Macro Examples
• To check bit number 3:
Code:
if(bit_get(foo, BIT(3)))
{
}
• To set or clear a bit based on bit number 4:
Code:
if(bit_get(foo, BIT(4)))
{
bit_set(bar, BIT(0));
}
else
{
bit_clear(bar, BIT(0));
}
• To do it with a macro:
Code:
bit_write(bit_get(foo, BIT(4)), bar, BIT(0));
Blinking LED
#include <avr/io.h> int main(void)
{
/// Typedefs ////////// InitPorts();
typedef unsigned char u8;
typedef unsigned int u16; while (forever)
typedef unsigned long u32; {
LEDON; Delay(20000);
/// Defines /////////// LEDOFF; Delay(20000);
#define forever 117 }
#define LEDOFF PORTB |= }
(1<<4)
#define LEDON PORTB &= void InitPorts(void)
~(1<<4) {
DDRB |= 1<<DDB4;
/// Prototypes //////// }
void InitPorts (void);
void Delay (u32 count); void Delay(u32 count)
{
while(count--);
}
Blink with button
• int main(void)
{
u8 btnState;
InitPorts();
LEDOFF;
while (forever)
{
// button pin reading
btnState = ~PINB & (1<<3);
// action
if (btnState)
{
LEDON; Delay(5000);
LEDOFF; Delay(5000);
}
}
}
Blinky
#include <avr/io.h>
#include <avr/delay.h>
int main (void)
{
// set PORTD for output
DDRD = 0xFF;
while(1) {
for(int i = 1; i <= 128; i = i*2)
{
PORTD = i;
_delay_loop_2(30000);
}
for(int i = 128; i > 1; i -= i/2)
{
PORTD = i;
_delay_loop_2(30000);
}
}
return 1;
}