4CCE1PHC
1 Introduction
in §2.
2 Preparation
Materials
Make sure you have everything you need to com- plete this lab.
The hardware items should be included in your lab kit.
Ensure that you have the Arduino documentation (e.g., ATmega328P Datasheet, Arduino Schematic Pinout Diagram) to hand.
Item Qty
1 USBTypeA-Bcable 1 Breadboard 1 LEDs 4 330 Ohm resistors 4 Jumper wires 5
Digital Input & Output
November 8, 2021
This lab introduces you to embedded programming in C using the Arduino development board. It will (i) introduce you to writing C programs for embedded systems, (ii) introduce you to build process for the Arduino, (iii) familiarise you with using digital input and output as a simple hardware interface.
At the end of the lab, you should be able to:
• Configure microcontroller pins as outputs and turn them on/off.
• Configure microcontroller pins as inputs and read their state.
Before starting work you should read through this document and complete the preparatory tasks detailed
Ensure that you have the following software in-
stalled on your computer: (i) a terminal program
(e.g., xterm or similar on Linux/Mac OS, cygwin
on Windows), (ii) a text editor (e.g., gedit or similar on Linux/Mac OS, notepad++ on
(iii) avr-libc (including avr-gcc, avr-objcopy and avrdude) (iv) the arduino IDE (optional), and (v) scopy.
Self-study
Read §3 below and read up on any new material (in textbooks and/or online) that you need to, to accomplish the tasks. Remember to make notes of where you get any information, so that you can quickly go there again if something does not work as expected.
Dr Matthew Howard 1 Deparment of Engineering © 2020 King’s College London
Windows),
4CCE1PHC
The development board contains an in-built LED. Using the above annotated image locate the in-built LED on your board. In §3.2 of this lab you will turn this LED on. If you look at the pinout diagram1of the development board you can see that the LED is in fact connected to the pin labelled PB5 on the ATmega328 microcontroller. PB5 corresponds to bit 5 of the ATmega328’s PORTB (n.b., PB is shorthand for PORTB).
Take another look at the pinout diagram of the board, you will see that the ATmega328’s PORTB is also connected to the external Digital pins on the board (i.e., D0 through D13).
Answer the following questions with reference to the Arduino board:
1.
2.
3.
3
3.1
Using the Arduino documentation, write down which external Digital pins are connected to bits 0-3 of PORTB.
PORTB bit Atmega328 Pin Board Digital Pin
0 PB0 D8 1 PB1 D9
2 PB2 D 10
3 PB3 D 11
Look at the Atmega328P data sheet and write down the size of (i.e., number of bits in) registers PORTB and DDRB. How would you write an initialiser that set bit 5 of DDRB register to one and all other bits to zero? Give your answer in binary and hexadecimal. There are 8 bits in PORTB and DDRB. To set the fifth bit to be zero we need to assign it the value 00100000, i.e., DDRB = 0b00100000. Alternatively, we can use the hexadecimal representation (00100000 = 20), so DDRB = 0x20. Look up the frequency of the Atmega328P CPU on the development board and write down its value in Hertz. Look up the documentation of the util/delay.h library from avr-libc and write down the names of any functions you can use to introduce delays in your program.
The CPU frequency is 16MHz.
Looking at util/delay.h, we see that _delay_ms() and _delay_us() can be used to introduce delays in milliseconds and microseconds, respectively.
Laboratory Work
Set Up
To set up your work environment, take the following steps:
1. Open a terminal and create a new folder to store your work in.
2. Download the file hello_arduino.c from KEATS and open it using a text editor.
3. The build process for the Arduino is a little different to what we’ve encountered so far. Instead of
using gcc, we use avr-gcc, a part of the AVR Libc tool set. To compile the program, enter the
1https://content.arduino.cc/assets/Pinout-UNOrev3_latest.pdf
Dr Matthew Howard 2 Deparment of Engineering © 2020 King’s College London
4CCE1PHC
1 /* hello_arduino.c */
2 /* The Arduino equivalent of “hello world”. */ 3
4 #define SUCCESS 0
5
6 int main(void) {
7
8
9}
return SUCCESS;
4.
Listing 1: hello_arduino.c.
following command in the terminal and hit return:
avr-gcc -mmcu=atmega328p hello_arduino.c -o hello_arduino.elf
Think: Why do we include the options -mmcu and -o?
-mmcu specifies the microcontroller (we are working with the Atmega328P). -o specifies the output file name (just like with gcc).
The result of the call to avr-gcc is a file hello_arduino.elf. This must be compiled into machine code and uploaded to the development board. To create the machine code use the command:
avr-objcopy -O ihex hello_arduino.elf out.hex
To upload the program to the development board, use the command:
avrdude -p atmega328p -c arduino -P COM8 -b 115200 -D -U flash:w:out.hex:i
Hint: This assumes that your board is connected to the COM8 USB port on a Windows machine, and the port is configured to a baud rate of 115200. You may need to adjust the options -P, -b to get this to work for your set up. Ask for help if you need it.
Digital Output
3.2
In this part of the lab, you will create an interface to display data through LEDs. Specifically, you will write a program to allow the microprocessor to communicate through the PORTB I/O interface, using LEDs to tell whether the pins on that interface, each representing a bit of information, are high or low (1 or 0). To complete this exercise, take the following steps:
1. Make a backup of the file hello_arduino.c and open it up in a text editor.
2. Our first step is to include the necessary libary functions for digital I/O. Modify hello_arduino.c
to include the avr/io.h header.
Think: What do you think the header avr/io.h is for?This includes the I/O library for the develop- ment board.
3. The pins of PORTB can be used either to communicate incoming data (input mode) or outgoing data (output mode). This means we need to specify the direction of data flow for I/O on PORTB. In the Atmega328, a special register called the data direction register is provided for this. Each port on the Atmega328 has a corresponding data direction register (the one for PORTB is called DDRB). In data direction registers, a bit set to 1 means that the corresponding bit of the port is in output mode. If the corresponding bit is unset (i.e., set to 0), then the corresponding bit of the port is in input mode. Each bit in PORTB has a corresponding input or output mode bit in DDRB, so that in order to use bit 5 of PORTB as an output, for example, we need to set bit 5 of DDRB. Modify hello_arduino.c so
Dr Matthew Howard 3 Deparment of Engineering © 2020 King’s College London
4CCE1PHC
1 /* hello_arduino.c */
2 /* The Arduino equivalent of “hello world”. */
3
4 #include
6 #define SUCCESS 0
7
8 int main(void) {
9 DDRB = 0b00100000; /*
Set bit 5 of DDRB to 1, i.e., configure bit 5 of PORTB to be an output. */
Set bit 5 of DDRB to 1, i.e., set that bit to be HIGH , which switches on the LED. */
10
11
12 PORTB = 0b00100000; /* 13
14
15 return SUCCESS;
16 }
Listing 2: hello_arduino.c modified to switch the internal LED on.
that the first statement in main() sets bit 5 of PORTB to output mode.
Hint: DDRB is declared in the header files so you can manipulate its value as if it were a global variable. 4. We can now use the PORTB register to switch on the LED. For this, we simply need to set bit 5 of
PORTB. Modify hello_arduino.c so that the second statement in main() switches the LED on. An example implementation for the exercise up until this point is given in Listing 2.
Think: Observe the behaviour of the development board. Does your program run as expected? Think: What value would you write to PORTB in order to turn the LED off? Experiment with this.You need to set PORTB=0b00000000.
Dr Matthew Howard 4 Deparment of Engineering © 2020 King’s College London
4CCE1PHC
5. We are now ready to create a rudimentary display by connecting 4 external LEDs to PORTB. Here is an illustration of the circuit you will be building:
Before starting, disconnect the USB cable from the development board. (You do not want to be
building the circuit with the board connected and powered by the PC.)
6. Unpack the necessary items from your lab kit, and construct the circuit illustrated above. Connect
the LEDs to pins D8-D11, and via a 330Ω (resistor colour code: Orange-Orange-Black-Black-Brown) resistor to ground. When you are satisfied that your circuit is correct, connect the development board back to your PC with the USB cable.
Hint: Take care that the pins all lie on separate lines of the breadboard! Remember that the long leg of the LED is the positive (+) connector! Ensure the development board and the LEDs are connected to a common ground!
Think: Which pins of PORTB are you now able to display? You can now display bits 0 to 3 of PORTB.
7. Wired this way, PORTB can be used to display numbers in binary format up to fifteen (i.e., 0x0F or 0b00001111). Modify your program to initialises the display to zero and then increments the number
every second. When it reaches fifteen it should wrap around to zero and continue counting.
Hint: You can introduce delays using the _delay_ms() function from util/delay.h. To use this library, you need to define the CPU frequency as a macro F_CPU.
An example implementation for the exercise up until this point is given in Listing 3.
Dr Matthew Howard 5 Deparment of Engineering © 2020 King’s College London
4CCE1PHC
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/* Couning to 15 using a bank of 4 LEDS. */
#ifndef F_CPU
#define F_CPU 16000000UL /*
#endif
#include
#define SUCCESS 0
Specify the CPU frequency
to 16MHz (= 16,000,000 Hz). */
Include delay library */ Include I/O library. */
Set the first four bits of DDRB, i.e., configure bits 0-4 of
PORTB to be outputs. */
Unset all bits in PORTB initialliy (i.e., switch off all the LEDs) so that we start counting from zero. */
int
main(void) {
DDRB = 0b00001111; /*
PORTB = 0b00000000; /*
while(1) /* Repeat forever. */ {
if (PORTB>=0x0F) /* If we’ve made it to fifteen… */ {
PORTB=0x00; /* … reset PORTB to zero. */ }
else
{
PORTB++; /* Otherwise, add one to PORTB. */
}
_delay_ms(1000); /* Delay (i.e., wait) 1000 milliseconds
}
return SUCCESS; }
= 1 second. */
Listing 3: hello_arduino.c modified to count up to fifteen with a one second delay.
Dr Matthew Howard 6 Deparment of Engineering © 2020 King’s College London
4CCE1PHC
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#include
/* Include I/O library. */
int
main(void) {
DDRB = 0b00100000; /*
PORTB = 0b00000000; /*
DDRD = 0b00000000; /* PORTD = 0b11111111; /*
Set bit 5 of DDRB to 1, i.e., configure bit 5 of PORTB to
be an output. */
Set bit 5 of DDRB to 0, i.e., set that bit to be HIGH ,
which switches off the LED. */ Set PORTD pins as inputs by setting them all to zero. */ Switch on pull -up resistors for all PORTD pins by setting them all to one. */
while(1) /* Repeat forever. */ {
if(PIND & 0b10000000) /* If bit 7 of PORTD is one (i.e., high) */
{
PORTB = 0b00100000; /* Turn LED on */
}
else
{
PORTB = 0b00000000; /* Otherwise turn LED off */
} }
return SUCCESS; }
Listing 4: Sample code to toggle the internal LED depending on the state of bit 7 of PORTD.
Digital Input
3.3
In this part of the lab, you will create an interface to input data through the digital pins. To complete this exercise, take the following steps:
1. Take your previous program and modify it so that pin D7 is configured as an input. Implement a program so that when pin D7 is high (i.e., connected to a 5V source) the internal LED on the Arduino board lights up, and when it is low (i.e., connected to ground) the LED goes out.
An example implementation for the exercise up until this point is given in Listing 4.
Hint: You will need to check the documentation to determine the corresponding port and pin of the
microcontroller.
2. Build a simple circuit to test your program as follows. First, disconnect the USB cable from the
development board. Then, connect the 5V pin from the development board to the + rail of the breadboard, and the ground pin to the − rail. Finally use a jumper cable to connect pin D7 to the + rail. The circuit should look like this:
Dr Matthew Howard 7 Deparment of Engineering © 2020 King’s College London
4CCE1PHC
3.
4 4.1
Think: What behaviour do you expect from your program when it encounters this circuit?
Compile and upload your program to the development board and verify it works as expected. Repeat the experiment (i) with a connection between pin D7 and the − rail (but NOT the + rail), and (ii) with the connection between pin D7 and either rail removed.
Think: Observe the behaviour of the development board. Does your program run as expected?
Optional Additional Work Displaying the state of PORTD
Modify your program to use pins D4-D7 as digital inputs and pins D8-D11 as outputs. Program the development board so that when the input on pins D4, D5, D6 or D7 is high, respectively, the output on pin D8, D9, D10 or D11, is set high, respectively. Wire up a circuit to test your program and verify that it works as expected.
4.2 De-bouncing
Mechanical switches are not ideal and often the contacts will bounce which can cause programs to see multiple changes on the input when only one was intended. To address this issue the input should be de-bounced – this can be achieved in hardware or in software. Read up on this issue and modify your program from §3.3 to debounce the switch.
Dr Matthew Howard 8 Deparment of Engineering © 2020 King’s College London