<<

4.1

Unit 4

Microcontrollers (Arduino) Overview Digital I/O 4.2

ARDUINO BOARD INTRO 4.3 Intro

• The Arduino Uno is a microcomputer Printed circuit (PC) board with development board based on the processor and other circuits for programming the system and ATmega328P 8-bit processor. interfacing other devices • Most microcomputer manufacturers (Atmel, Freescale, etc.) produce small circuit boards with connectors for other , actuators, etc. that engineers can use to systems before integrating all the components in a system • The software running on the ATmega processor can sense or produce voltages on the connector pins to control the

connected hardware devices http://arduino.cc/en/Main/ArduinoBoardUno

Atmega328P 8-bit Connectors for I/O lines A0-A5, processor D0 – D13. (Can be connected to other HW devices) 4.4 Arduino Uno • Arduino – An Italian company which produces the printed circuit boards that integrate processor, power sources, USB connector, etc. – Hardware and software are open source. – Very popular with hobbyists and engineers, due in a large part to their low cost.

http://arduino.cc/en/Main/Products 4.5 Arduino Uno • What’s on an Arduino Uno board?

Connectors for I/O lines D0 – D13 (Can be connected to other HW devices) Reset button

USB interface

Atmel ATmega328P 16MHz oscillator (i.e. clock signal generator)

Power connector (for use when not connected to USB) Power and I/O lines A0 – A5 ground pins (Can be connected to other HW devices) 4.6 Arduino Uno • Arduino Unos can be stacked with "shield" boards to add additional capabilities (Ethernet, wireless, D/A, LCDs, sensors, motor control, etc.) 4.7 Arduino IDE

• Arduino provides an Integrated Development Environment (IDE) with libraries of code to simplify use of integrated or connected hardware devices • Our goal is for you to learn how to write that code from scratch and how to develop firmware, hardware device drivers, etc.

– Thus, we will not use the IDE but This Photo by Unknown Author is licensed under CC BY-SA the base : avr-gcc 4.8 Flashback to Week 1 • Recall the computer interacts with any input or output (I/O) device by simply doing reads/writes to the memory locations (often called registers) in the I/O interfaces… • The Arduino has many of these I/O interfaces all connected via the data bus

Processor Memory 0 … 3FF A D Video Interface 800 FE may 800 FE FE signify a … WRITE white dot at a particular 01 location Keyboard Interface

Data Bus connecting all components 400 61 4.9 Atmel ATmega328P

• The Arduino Uno is based on an Atmel ATmega328P 8-bit microcontroller, which has Mem. many useful hardware devices

integrated with the processor Processor – 32kb of FLASH ROM – 2048 bytes of RAM – 3 timer/counters – Serial/SPI/I2C interfaces – A/D converter – 23 I/O lines for connecting other

custom components Data Bus 4.10 Arduino Digital I/O • ATmega328P has 23 pins on the that can be connected to other devices (switches, LEDs, motors, etc.) – Other members of the ATmega family may have more or less lines. – The Arduino Uno can make use of only 20 of these lines. • Each pin can be used as a digital input or a digital output – For output pins: Your code determines what value ('1' or '0') appears on the pin and can connect to another component – For input pins: Your code senses/reads what value another device is putting on the pin – A pin can be used as an output on one project and an input on a different project (configurable via software)

Main Point: Individual pins on the Arduino can be used as inputs OR outputs 4.11 Groups (Ports) B, C and D

• The Arduino provides 20 separate digital input/output bits that we can use to interface to external devices • Recall computers don't access individual bits but instead the byte (8-bits) is the smallest unit of access • Thus to deal with our digital inputs we will put the bits into 3 groups: Group B, B Group C, and D –

We often refer to these groups as "ports" D Group but you'll see that "port" is used in multiple C Group places so we'll generally use "group" Software to Arduino Name Mapping Group B bit5-bit0 = DIG13-DIG8 Group C bit5-bit0 = A5-A0 Group D bit7-bit0 = DIG7-DIG0 4.12 Arduino Port/Pin Mapping • Since computers usually deal with groups of 8-bits (a.k.a. a byte), all of the 20 I/O pins are split into three 8-bit I/O groups (B, C and D) – The avr-gcc software (SW) and the Arduino hardware (and software IDE) use different names to refer to the bits within each port SW Arduino SW Arduino SW Arduino PortB, bit0 DIG8 PortC, bit0 AN0 PortD, bit0 DIG0 PortB, bit1 DIG9 PortC, bit1 AN1 PortD, bit1 DIG1 PortB, bit2 DIG10 PortC, bit2 AN2 PortD, bit2 DIG2 PortB, bit3 DIG11 PortC, bit3 AN3 PortD, bit3 DIG3 PortB, bit4 DIG12 PortC, bit4 AN4 PortD, bit4 DIG4 PortB, bit5 DIG13 PortC, bit5 AN5 PortD, bit5 DIG5 PortB, bit6 Clock1 PortC, bit6 Reset PortD, bit6 (don't use) (don't use) DIG6 PortB, bit7 Clock2 PortD, bit7 (don't use) DIG7

Main Point: Each pin has a name the software uses (Portx) and a name used on the Arduino circuit board (Anx or DIGx) 4.13 Using Ports to Interface to HW • The I/O groups (aka ports) are the Code Data intermediaries between your software program and the physical devices connected to the chip. • Your program is responsible for managing these ports (groups of I/O pins) in order to make things happen on the outside

#include int main() { // check input Group C // bit 0 value

// set output Group B // bit 2 to Logic 1=5V Arduino D10  // ... GroupB bit 2 }

Logic 1 = 5V An LED Groups/ Logic 0 = 0V PORTs A button

Arduino A0  GroupC bit 0 4.14

Using software to perform logic on individual (or groups) of bits BIT FIDDLING 4.15 Bit-Fiddling Introduction

• The primary way that software (device drivers, firmware, etc.) controls hardware is by manipulating individual bits in certain hardware registers (memory locations) • Thus, we need to learn how to: – Set a bit to a 1 – Clear a bit to a 0 – Check the value of a given bit (is it 0 or 1) • Because computers do not access anything smaller than a byte (8-bits) we must use logic operations to manipulate individual bits within a byte – These bit manipulations are often referred to as bit fiddling 4.16 Numbers in Other Bases in C/C++

• Suppose we want to place the binary value 00111010 into a char variable, v [i.e. char v;]

– We could convert to decimal on our own (5810) v = 58; – All support hexadecimal using the '0x' prefix v = 0x3a; – Our Arduino compiler supports binary using the '0b' prefix v = 0b00111010; • Important note: Compilers convert EVERYTHING to equivalent binary. The 3 alternatives above are equivalent because the compiler will take all 3 and place 00111010 in memory. – Use whichever base makes the most sense in any given situation – It is your (the 's) choice…the compiler will end up converting to binary once it is compiled 4.17 Modifying Individual Bits

• Suppose we want to change only a single bit (or a few bits) in a variable [i.e. char v;] without changing the other bits ? ? ? ? ? ? ? ? – Set the LSB of v to 1 w/o affecting other bits Original v • Would this work? v = 1; – Set the upper 4 bits of v to 1111 w/o affecting other bits ? ? ? ? ? ? ? 1 • Would this work? v = 0xf0; Desired v – Clear the lower 2 bits of v to 00 w/o affecting other bits (change LSB to 1) • Would this work? v = 0; – No!!! Assignment changes ALL bits in a variable 1 1 1 1 ? ? ? ? • Because the smallest unit of data in computers is usually a Desired v byte, manipulating individual bits requires us to use (change upper 4 bits to BITWISE OPERATIONS. 1111) – Use AND operations to clear individual bits to 0 – Use OR operations to set individual bits to 1 ? ? ? ? ? ? 0 0 – Use XOR operations to invert bits Desired v – Use AND to check a bit(s) value in a register (change lower 2 bits to 00) 4.18 Using Logic to Change Bits • ANDs can be used to control whether a bit passes unchanged or results in a '0' • ORs can be used to control whether a bit passes unchanged or results in a '1' • XORs can be used to control whether a bit passes unchanged or is inverted BitX BitX BitX XOR FZ AND F OR F CtrlY CtrlY CtrlY

Ctrl Bit F Ctrl Bit F Ctrl Bit F

0 0 0 0 0 0 0 0 0

'0'

Force Pass 0 1 0 0 1 1 0 1 1 Pass 1 0 0 1 0 1 1 0 1

1 1 1 1 1 1 '1' 1 1 0

Pass

Invert Force 0 AND x = 0 0 OR x = x 0 XOR x = x 1 AND x = x 1 OR x = 1 1 XOR x = NOT x x AND x = x x OR x = x x XOR x = 0

You already T1 X + 0 = X T1' X • 1 = X knew the above T2 X + 1 = 1 T2' X • 0 = 0 ideas. It is just T1-T3. T3 X + X = X T3' X • X = X 4.19 Bitwise Operations • The C AND, OR, XOR, NOT bitwise operations perform the operation on each pair of bits of 2 numbers

#include // C- 0xF0 1111 0000 // for printf()

AND 0x3C AND 0011 1100 int main() 0x30 0011 0000 { char a = 0xf0; char b = 0x3c;

0xF0 1111 0000 printf("a & b = %x\n", a & b); OR 0x3C OR 0011 1100 printf("a | b = %x\n", a | b); printf("a ^ b = %x\n", a ^ b); 0xFC 1111 1100 printf("~a = %x\n", ~a); return 0; } 0xF0 1111 0000 XOR 0x3C XOR 0011 1100 0xCC 1100 1100 C bitwise operators: & = AND NOT 0xF0 NOT 1111 0000 | = OR 0x0F 0000 1111 ^ = XOR ~ = NOT 4.20 Bitwise Operations & Masking Bit #

• Bitwise operations are often used for "bit 7 6 5 4 3 2 1 0 fiddling" v ? ? ? ? ? ? ? ? – Change the value of a bit in a register w/o affecting other bits & ______• Determine appropriate constant bit patterns v ? ? ? ? ? ? ? 0 (aka masks) that will change some bits while leaving others unchanged • Masks can be written in binary, hex, or even decimal (it v ? ? ? ? ? ? ? ? is the programmer's choice…whatever is easiest) | • Examples (Assume an 8-bit variable, v) ______– Clear the LSB to '0' w/o affecting other bits v 1 ? ? ? ? ? ? ? • v = v & 0xfe; or equivalently • v = v & ~(0x01); v ? ? ? ? ? ? ? ? – Set the MSB to '1' w/o affecting other bits • v = v | 0x80; ^ 0 0 0 0 1 1 1 1 – Flip the LS 4-bits w/o affecting other bits v ? ? ? ? ? ? ? ? • v = v ^ 0x0f; 4.21 Changing Register Bits 7 6 5 4 3 2 1 0

v ? ? ? ? ? ? ? ? • Some practice problems: | ______– Set bit 0 of v to a ‘1’ v = v | 0x01; – Clear the 4 upper bits in v to ‘0’s v ? ? ? ? ? ? ? ? v = v & 0x0f; & ______– Flip bits 4 and 5 in v v = v ^ 0b00110000; v ? ? ? ? ? ? ? ? ^ ______

Note: It is the programmer's choice of writing the "mask" constant in binary, hex, or decimal. However, hex is usually preferable (avoids mistakes of missing a bit in binary and easier than converting to decimal). 4.22 Checking Register Bits 7 6 5 4 3 2 1 0 v • To check for a given set of bits we use a ? ? ? ? ? ? ? ? bitwise-AND to isolate just those bits & 1 0 0 0 0 0 0 0 – The result will then have 0's in the bit locations not of interest – The result will keep the bit values of interest v ? ? ? ? ? ? ? ? • Examples & 0 0 0 0 0 1 0 0 – Check if bit 7 of v = '1' if ( (v & 0x80) == 0x80) { code } or if (v & 0x80) { code } v ? ? ? ? ? ? ? ? – Check if bit 2 of v = '0' & 0 0 0 0 0 1 1 1 if ( (v & 0x04) == 0x00) { code } or if ( ! (v & 0x04) ) { code } – Check if bit 2:0 of v = "101" v ? ? ? ? ? ? ? ? if ( (v & 0b00000111) == 0b00000101) {..} & – Check if bit 5-4 of v = "01" 0 0 1 1 0 0 0 0 if ( (v & 0x30) == 0x10) { code } 4.23 Short Notation for Operations

• In C, assignment statements of the form x = x op y; • Can be shortened to x op= y; • Example: x = x + 1; can be written as x += 1; • The preceding operations can be written as v|= 0x01; v &= 0x0f; v ^= 0b00110000; 4.24 Logical vs. Bitwise Operations

• The C language has two types of logic operations – Logical and Bitwise • Logical Operators (&&, ||, !) – Operate on the logical value of a FULL variable (char, int, etc.) interpreting that value as either True (non-zero) or False (zero) – char x = 1, y = 2, z = x && y; 0000 0001=T • Result is z = 1; Why? && 0000 0010=T T – char x = 1; if(!x) { /* will NOT execute since !x = !true = false */ } • Bitwise Operators (&, |, ^, ~) ! 0000 0001=T F – Operate on the logical value of INDIVIDUAL bits in a variable – char x = 1, y = 2, z = x & y; 0000 0001 • Result is z = 0; Why? & 0000 0010 F = 0000 0000 – char x = 1; if(~x) { /* will execute since ~x = 0xfe = non-zero = true */ } ~ 0000 0001 T = 1111 1110 4.25

Controlling the pins of the Arduino to be digital inputs and outputs ARDUINO DIGITAL I/O 4.26 Overview

• In the next few slides you will learn – What your software needs to do to setup #include the pins for use as digital inputs and/or int main() { // check input Group C outputs // bit 0 value

– To set bits (to 1) and clear bits (to 0) using // set output Group B // bit 2 to Logic 1=5V bitwise operations (AND, OR, NOT) to // ... control individual I/O pins } – How to do it in a readable syntax using shift What is the actual code we would write to operators (<<, >>) accomplish these tasks? • Don't be worried if it doesn't make We'll answer that through the next few sense the first time…listen, try to make slides. sense of it, and ask a lot of questions. 4.27 Controlling I/O Groups/Ports • Each group (B, C, and D) has 3 registers in the µC associated with it that control the operation – Each bit in the register controls something about the corresponding I/O bit. – Data Direction Register (DDRB, DDRC, DDRD) – Port Output Register (PORTB, PORTC, PORTD) – Port Input Register (PINB, PINC, PIND)

• You'll write a program that sets these bits to What you store in the register bits below affect how the pins 1's or 0's as necessary on the chip operates DDRD DDRB

DDRD7 DDRD6 DDRD5 DDRD4 DDRD3 DDRD2 DDRD1 DDRD0 DDRB5 DDRB4 DDRB3 DDRB2 DDRB1 DDRB0

PORTD PORTB

PORT PORT PORT PORT PORT PORT PORT PORT PORT PORT PORT PORT PORT PORT D7 D6 D5 D4 D3 D2 D1 D0 B5 B4 B3 D2 D1 D0

PIND PINB

PIND7 PIND6 PIND5 PIND4 PIND3 PIND2 PIND1 PIND0 PINB5 PINB4 PINB3 PIND2 PIND1 PIND0 4.28 Register 1: Data Direction Register • DDRx (Data direction register) [x=B,C,D…DDRB, DDRC, DDRD] – Controls whether pins on the chip act as inputs or outputs. – Example: If DDRB5 = 0 -> Group B bit 5 = DIG13 pin) will be used as an input – Example: If DDRB5 = 1 -> Group B bit 5) will be used as an output – All I/O lines start out as inputs when the µC is reset or powered up. DDRD DDRB

DDRD7 DDRD6 DDRD5 DDRD4 DDRD3 DDRD2 DDDR1 DDRD0 DDRB5 DDRB4 DDRB3 DDRB2 DDRB1 DDRB0 0 0 0 0 1 1 1 1 1 0 0 0 0 0

PD[7:4] = INPUT PD[3:0] = OUTPUT PB[5] = OUTPUT PB[4:0] = INPUT

Notation: [7:4] means bit7-bit4 Consider a leaf BLOWER / VACCUM. and is shorthand, not C code. There must be a switch to select if you Don't use it in your programs. want it to blow (output) or produce suction (input)…DDR register is that "switch"

http://www.toro.com/en- us/homeowner/yard- tools/blowers- PD[7:4] PD[3:0] PB[5] vacs/pages/series.aspx?sid =gasblowervacsseries 4.29 Register 2: PORT (Pin-Output) Register

• PORTxn (Primarily used if group x, bit n is configured as an output) – When a pin is used as an output (DDRxn = 1), the corresponding bit in PORTxn determines the value/voltage of that pin. – E.g. By placing a '1' in PORTB5, pin 5 of group B will output a high voltage DDRD DDRB

DDRD7 DDRD6 DDRD5 DDRD4 DDRD3 DDRD2 DDRD1 DDRD0 DDRB5 DDRB4 DDRB3 DDRB2 DDRB1 DDRB0 0 0 0 0 1 1 1 1 1 0 0 0 0 0

PORTD PORTB

PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0 PORTB5 PORTB4 PORTB3 PORTB2 PORTB1 PORTB0 1 1 0 0 1 0 0 1 0 0 0 0 1 0

PD[7:4] PD[3:0] PB[5] 1001 0 Main Point: For pins configured as outputs, the values you put in the PORT register will be the output voltages 4.30 Microcontroller Digital I/O Schematic 1

• DDR bit = 1 connects PORT register bit to I/O pin (i.e. output) • DDR bit = 0 connects I/O pin to (i.e. input) • See next slide for illustrations of these 2 cases

uProc. == PINx Address Addr

Data (bit n) 1 = closed == DDRx DDRxn 0 = open Addr

== PORTx Addr PORTxn

I/O Pin AVR Microcontroller 4.31 Microcontroller Digital I/O Schematic 2

• Port bit value controls WHAT voltage is output to the I/O pin

DDR bit = 1, Port bit = 1 DDR bit = 1, Port bit = 0

uProc. uProc. == PINx == PINx Address Addr Address Addr

Data Data (bit n) (bit n)

== DDRx DDRxn == DDRx DDRxn Addr Addr 1 1

== PORTx == PORTx Addr PORTxn 5V Addr PORTxn 0V 1 0 I/O Pin I/O Pin 4.32 Register 3: PIN (Pin-Input) Register

• PINxn (Used if the group x, bit n is configured as an input) – When a bit is an input (DDRxn=0), reading bit n from the register PINx reflects the current value at the corresponding input pin • The program doesn’t have to do anything special to read the digital signals into the PIN register, just use the register name – if(PIND == 0x00) // check if all the signals coming into port D are 0's – char val = PINB; // read and save all 8 signals coming into port B in a variable 'val'. – Referencing PINx produces a snapshot (at the instant the line of code is execute) of the bit values coming in those 8 pins; it does not constantly monitor the input bits • Programs must read the full eight bits in the PIN register, but can then use bitwise logical operations to check individual bits

Main Point: For pins configured as inputs, referencing the PINx register samples the input voltages at all the pins 4.33 Microcontroller Digital I/O Schematic 3

• Reading from PIN "register" allows voltage at input pin to be sent to the microprocessor

DDR bit = 0, DDR bit = 0, External Input = 1 External Input = 0

uProc. uProc. 1 1 == PINx == PINx Address Addr Address Addr

Data Data (bit n) (bit n) Vdd == DDRx Vdd DDRxn == DDRx DDRxn Addr Addr 0 0

== PORTx PORTxn == PORTx Addr Addr PORTxn 0V

I/O Pin I/O Pin 4.34 Review of Accessing Control Registers in C • Control registers have names and act just like variables in a C program • To put values into a control register you can assign to them like any C variable or perform bitwise operations – DDRD = 0xff; // 0b11111111 or 255 – DDRB = 255; – PORTD |= 0xc0; // 0b11000000 or 192 – PORTD |= 0b01110000; • To read the value of a control register you can write expressions with them – unsigned char myvar = PIND; // grabs all 8-inputs on the port D – myvar = PINB & 0x0f; // grabs the lower 4 inputs 4.35 Practice: Changing Register Bits

DDRB ? ? ? ? ? ? ? ? • Use your knowledge of the bitwise | ______operations to change the values of individual bits in registers without affecting the other bits in the register. PORTD ? ? ? ? ? ? ? ? – Set DDRB, bit 3 to a '1' & ______DDRB |= 0b00001000; // DDRB |= 0x08; – Clear the 2 upper bits in PORTD to ‘0’s DDRD ? ? ? ? ? ? ? ? PORTD &= 0x3f; // PORTD &= ~(0b11000000) ^ ______– Flip bits 7 and 1 in DDRD DDRD ^= 0b10000010; // DDRD ^= 0x82; PINC ? ? ? ? ? ? ? ? – Check if PINC, bit 4 = '1' & ______if (PINC & 0x10) { code } 4.36

EXAMPLES 4.37 LED Outputs Review

• Recall we can connect LEDs to the outputs of a digital signal – The digital output value that will turn the LED on varies based on how we wire the LED • Be sure to use a current-limiting resistor (few hundred ohms ~200-500 ohms)

Can be Option 1 Option 2 discrete gate or Arduino output pin

Can be discrete LED is on when LED is on when gate or gate outputs '1' gate outputs '0' Arduino output pin 4.38 Switch & Button Input Review • Recall: Switches/buttons alone do not produce 1's and 0's; they must be connected to voltage sources • Preferred connection: – Connect one side of switch to GND (ground) – Connect other side of switch to digital input AND to a pull-up resistor (around 10Kohms) whose other side is connected to Vdd • Switch/button will produce a: – 0 when pressed – 1 when open (not-pressed) Vdd Rp Arduino SW input model

Vin R ≈ inf. Preferred: Use a pullup resistor

Main Point: Buttons & switches should have GND connected to one side & a pull-up resistor on the other 4.39 Blinking an LED

• Hardware and software to make an LED connected to D7 blink

#include DDRD #include

int main() ? ? ? ? ? ? ? ? { // Init. D7 to output | ______DDRD |= 0x80;

// Repeat forever 1 ? ? ? ? ? ? ? while(1){ // PD7 = 1 (LED on) PORTD PORTD |= 0x80; _delay_ms(500); ? ? ? ? ? ? ? ? // PD7 = 0 (LED off) PORTD &= ~(0x80); | _delay_ms(500); ______} // Never reached 1 ? ? ? ? ? ? ? return 0; } & ______

0 ? ? ? ? ? ? ? 4.40 Turning an LED on/off with PB

• Hardware to turn an LED connected to D7 on/off when pressing a pushbutton connected to D4

Vdd Vdd PB Arduino + V - PD4 PD7

LED

GND 4.41 Turning on an LED from a Button • Note: When the button is pressed a '0' is produced at the PD4 input DDRD #include (starts at 0's on reset)

int main() { 0 0 0 0 0 0 0 0 // Init. D7 to output DDRD |= 0x80; | ______// All pins start as input // on reset, so no need to // clear DDRD bit 4 1 ? ? 0 ? ? ? ?

// Repeat forever PIND while(1){ // Is PD4 pressed? if( (PIND & 0x10) == 0){ ? ? ? ? ? ? ? ? // PD7 = 1 (LED on) PORTD |= 0x80; & } ______else { // PD7 = 0 (LED off) ? ? ? ? ? ? ? ? PORTD &= ~(0x80); } } // Never reached return 0; } 4.42 Pull Up Resistors • Adding and wiring pull-up resistors for input buttons can be time consuming… • Thankfully, each Arduino input bit has an optional internal “pull- up resistor” associated with it. – If the pull-up is enabled, in the absence of an input signal, the input bit will be “pulled” up to a logical one. – The pull-up has no effect on the input if an active signal is attached. This pull-up resistor can be built separately on your circuit board OR there is one on each pin of the Arduino that can be enabled

Arduino Arduino Arduino

1) Built Separately 2) Enabled in the Arduino 4.43 Enabling Pull Up Resistors

• When DDRx bit n is '0' (i.e. a pin is used as input), the value in the PORTx bit n registers determines whether the internal pull-up is enabled – Remember, the PORT register is normally used when a pin is an output, but here its value helps enable the internal pull-up resistor

A pin being used as an input DDRD (DDR bits = 0) whose

DDD7 DDD6 DDD5 DDD4 DDD3 DDD2 DDD1 DDD0 corresponding PORT bit = 1 will 0 0 0 0 1 1 1 1 enable the pull up resistors on the

Inputs Outputs PIN bit PORTD

PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0 1 1 1 1 0 0 1 1

Enable Pull-Up Resistors Actual output values from PD3-0

PIND

PIND7 PIND6 PIND5 PIND4 PIND3 PIND2 PIND1 PIND0 0 1 1 0 ? ? ? ? PD[7:4] PD[3:0] Made-up values read from the push- (connected buttons (which don't require you to to buttons) 0011 wire up external pull-up resistors) 4.44 Microcontroller Digital I/O Schematic 4

• Reading from PIN "register" allows voltage at input pin to be sent to the microprocessor

DDR bit = 0, Port bit = 0 DDR bit = 0, Port bit = 1 No internal pull-up (must Internal Pull-up use external pull-up)

Vdd Vdd uProc. uProc. == PINx == PINx Address Addr Address Addr

0 1 Data Data (bit n) (bit n) Vdd == DDRx DDRxn == DDRx DDRxn Addr Addr 0 0

== PORTx == PORTx Addr PORTxn 5V Addr PORTxn 5V 1 0 I/O Pin I/O Pin 4.45 Using Internal Pull-up Resistors

• Let's simplify our wiring and use the internal pull-up resistors

Arduino Arduino Arduino Enabled in the Arduino Built Separately 4.46 Turning on an LED from a Button • Note: When the button is pressed a '0' is produced at the PD4 input DDRD #include (starts at 0's on reset)

int main() { 0 0 0 0 0 0 0 0 // Init. D7 to output DDRD |= 0x80; | ______// Enable pull-up on PD4 PORTD |= 0x10; 1 ? ? 0 ? ? ? ?

// Repeat forever PORTD while(1){ // Is PD4 pressed? if( (PIND & 0x10) == 0){ ? ? ? ? ? ? ? ? // PD7 = 1 (LED on) PORTD |= 0x80; | } ______else { // PD7 = 0 (LED off) 0 0 0 1 0 0 0 0 PORTD &= ~(0x80); } } // Never reached return 0; } 4.47

Using "good" syntax/style when performing logic operations FIDDLING WITH STYLE! 4.48 Code Read-ability Tip #1

• Try to replace hex and binary constants with shifted constants

#include #include

int main() int main() { { This syntax tells us // Init. D7 to output // Init. D7 to output DDRD |= 0x80; DDRD |= (1 << 7); we are putting a '1' in bit 7 or bit 4… // Enable pull-up on PD4 // Enable pull-up on PD4 PORTD |= 0x10; PORTD |= (1 << 4);

// Repeat forever // Repeat forever while(1){ while(1){ // Is PD4 pressed? // Is PD4 pressed? if( (PIND & 0x10) == 0){ if( (PIND & (1 << 4)) == 0){ // PD7 = 1 (LED on) // PD7 = 1 (LED on) PORTD |= 0x80; PORTD |= (1 << 7); } } else { else { We will teach you // PD7 = 0 (LED off) // PD7 = 0 (LED off) what all this means in PORTD &= ~(0x80); PORTD &= ~(1 << 7); } } the next slides… } } // Never reached // Never reached return 0; return 0; } } 4.49 Shift Operations

• In C, operators '<<' and '>>' are the shift operators << = Left shift >> = Right shift • Format: data << bit_places_to_shift_by • Bits shifted out and dropped on one side • Usually (but not always) 0’s are shifted in on the other side x = x >> 2; x = x << 2; Right Shift by 2 bits: Left Shift by 2 bits: x 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 0 x Original x Original x 0’s shifted in… 0’s shifted in… x 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 0 0 0 x x Shifted by 2 bits x Shifted by 2 bits 4.50 Another Example

• To get a 1 in a particular bit location it is easier to shift the constant 1 some number of places than try to think of the hex or binary constant

0 x 0 1 0 0 0 0 0 0 0 1 = +1

1 << 3 1 << 5

0’s shifted in… 0’s shifted in… 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 x 0 8 0 x 2 0 Suppose we want a 1 in bit Suppose we want a 1 in bit location 3. Just take the value location 5. Shift 1 5 spots to 1 and shift it 3 spots to the left the left. Easier than coming up with 0x20… 4.51 Putting it All Together

• Values for working with bits can be made using the ‘<<‘ shift operator – OK: PORTB |= 0x20; Better: PORTB |= (1 << 5) ; – OK: DDRD |= 0x04; Better: DDRD |= (1 << 2); • This makes the code more readable and your intention easier to understand… • More examples – Set DDRC, bit 5: DDRC |= (1 << 5) – Invert PORTB, bit 2: PORTB ^= (1 << 2) ? ? ? ? ? ? ? ? PORTD – Clear PORTD, bit 3: PORTD &= (1 << 3) & 0 0 0 0 1 0 0 0 • WRONG! Why? 0 0 0 0 ? 0 0 0 ? ? ? ? ? ? ? ? – Clear PORTD, bit 3: PORTD &= (0 << 3) PORTD & 0 0 0 0 0 0 0 0 • WRONG! Why? 0 0 0 0 0 0 0 0 – Clear PORTD, bit 3: PORTD &= ~(1 << 3) ? ? ? ? ? ? ? ? PORTD • RIGHT! Why? & 1 1 1 1 0 1 1 1 ? ? ? ? 0 ? ? ? 4.52 Clearing Bits…A Common Mistake

• When using the ‘&=‘ operation to clear bits, remember to invert the bits. • This won’t work to clear 3 to ‘0’ – PORTD &= (1 << 3); – is the same as – PORTD &= 0b0001000; – which clears everything but bit 3 • Use the ‘~’ operator to complement the bits. – PORTD &= ~(1 << 3); – is the same as – PORTD &= 0b11110111; – and now 3 gets cleared. • And NEVER use a mask of all 0's – PORTD &= (0 << 3); // 0 shifted by any amount is 0 in all bit places 4.53 Setting/Clearing Multiple bits

• Can combine multiple bits into one defined value – PORTB |= ((1 << 3) | (1 << 4) | (1 << 5)); – is the same as PORTB |= 0b00111000

– PORTB &= ~ ((1 << 3) | (1 << 4) | (1 << 5)); – is the same as PORTB &= 0b11000111;

1 << PB3 00001000 1 << PB4 00010000 1 << PB5 | 00100000 00111000 4.54

DEBOUNCING SWITCHES 4.55 Counting Presses

• Consider trying to build a system that #include int main() counted button presses on PC2 { PORTC |= (1 << PC2); (increment once per button press) int cnt = 0; while(1){ • We can write code to check if the char pressed = (PINC & 0x04); if( pressed == 0 ){ button is pressed (==0) and then cnt++; } increment 'cnt' } return 0; • But remember, your code executes } extremely fast…what will happen?

PC2 PC2 Arduino cnt 0 0 1 2 3 3 4.56 Waiting Through a Press

• Consider trying to build a system that #include int main() counted button presses on PC2 { PORTC |= (1 << PC2); (increment once per button press) int cnt = 0; while(1){ • We can write code to check if the char pressed = (PINC & 0x04); if( pressed == 0 ){ button is pressed (==0) and then while( (PINC & 0x04) == 0 ) {} increment 'cnt' cnt++; } • But remember, your code executes } return 0; extremely fast…what will happen? }

if if if while while while if

PC2 PC2 Arduino cnt 0 0 0 0 0 1 1 4.57 Interfacing Mechanical Switches/Buttons

• Mechanical switches and buttons do not make solid, steady contact immediately after being pressed/changed • For a short (few ms) time, “bouncing” will ensue and can cause spurious SW operation (one press of a button may look like multiple presses) • Need to “debounce” switches with your software – Usually waiting around 5 ms from the first detection of a press will get you past the bouncing and into the stable period

Stable Bouncing Stable Bouncing Stable

Arduino Button Button Press Release 4.58 Waiting Through a Press

#include int main() • { Consider trying to build a system that PORTC |= (1 << PC2); int cnt = 0; counted button presses on PC2 while(1){ char pressed = (PINC & 0x04); (increment once per button press) if( pressed == 0 ){ _delay_ms(5); • We can write code to check if the while( (PINC & 0x04) == 0 ) {} button is pressed (==0) and then _delay_ms(5); cnt++; increment 'cnt' } } • But remember, your code executes return 0; } extremely fast…what will happen?

if if while while while while if

PC2

PC2 Arduino bouncing cnt 0 0 0 0 0 bouncing 1 1 4.59 What's Your Function

• Because there is a fair amount of #include char pc2Pressed() work to do just to recognize a button { char pressed = (PINC & 0x04); press, you may want to extract those if( pressed == 0 ){ _delay_ms(5); to functions you can call over and while( (PINC & 0x04) == 0 ) { } _delay_ms(5); over again return 1; } else return 0; } int main() { PORTC |= (1 << PC2); int cnt = 0; while(1){ if( pc2Pressed() ) cnt++; } return 0; } 4.60

SUMMARY AND EXERCISES 4.61 Exercise 1

• We want to use Group C (Port C) bit 5 as an output. Show how you should initialize your program then write a statement to turn the output 'ON' to 5V. 4.62 Exercise 2

• Now turn write a statement to turn that same output ‘OFF’ (i.e. to output 0V) 4.63 Exercise 3

• We want to use Group B (Port B) bit 3 as an input connected to a switch. You have no separate resistors available to you. Show how you should initialize your program and then write an if statement to check if the input voltage is HIGH (5V). 4.64 Common Mistakes

// Clearing a bit to 0 // Wrong • Don't make these mistakes PORTD &= (0 << 3); PORTD |= (0 << 3);

// Right • Instead remember: PORTD &= ~(1 << 3); – Never shift a 0 when trying to // Checking a bit // Wrong do an AND or OR (e.g. 0 << x) if(PIND & (1 << 3) == 0) – // Right Correctly parenthesize your if( (PIND & (1 << 3)) == 0)

comparisons // Checking if a bit is 1 // Wrong – To check if a bit is 1, check if if( (PIND & (1 << 3)) == 1) // Right the result of the ANDing is if( (PIND & (1 << 3)) != 0) not-equal to 0 4.65 Summary – Cheat Sheet

Digital I/O 16-bit Timer and Pulse Width Modulation (PWM) 7 6 5 4 3 2 1 0 PORTB / PINB PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 TCCR1A COM1A1COM1A0COM1B1 COM1B0 WGM11 WGM10 (output / input)

7 6 5 4 3 2 1 0 PORTC / PINC • PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0 TCCR1B WGM13 WGM12 CS12 CS11 CS10 Refer to the cheat sheet (output / input) 7 6 5 4 3 2 1 0 PORTD / PIND PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0 TIMSK1 OCIE1B OCIE1A (output / input)

15 14 13 12 11 10 9 8 DDRB / DDRC / DDB7 DDB6 DDB5 DDB4 DDB3 DDB2 DDB1 DDB0 OCR1A DDRD DDC7 DDC6 DDC5 DDC4 DDC3 DDC2 DDC1 DDC0 (16-bit value) 7 6 5 4 3 2 1 0 DDD7 DDD6 DDD5 DDD4 DDD3 DDD2 DDD1 DDD0 Timer MAX in your lecture notes or PWM Set Pin as Set Pin as DDRB |= (1 << DDB4); DDRB &= ~(1 << DDB4); 15 14 13 12 11 10 9 8 Output Input OCR1B Set Output Check Pin PORTB |= (1 << PB4); (PINB & (1 << PB4)) != 0 (16-bit value) 7 6 5 4 3 2 1 0 Value to 1 is 1 PWM Clear Output Check Pin PORTB &= ~(1 << PB4); (PINB & (1 << PB4)) == 0 15 14 13 12 11 10 9 8 Value to 0 is 0 TCNT1 Analog to Digital Conversion (16-bit current 7 6 5 4 3 2 1 0 count value) • Below are the methods to 7 6 5 4 3 2 1 0 ADMUX REFS1 REFS0 ADLAR unused MUX3 MUX2 MUX1 MUX0 8-bit Timers and Pulse Width Modulation (PWM) 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 TCCR0A COM0A1COM0A0COM0B1 COM0B0 WGM01 WGM00 ADCSRA ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0 TCCR2A COM2A1COM2A0COM2B1 COM2B0 WGM21 WGM20

7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 TCCR0B ADCH WGM03 WGM02 CS02 CS01 CS00 TCCR2B WGM23 WGM22 CS22 CS21 CS20 accomplish the 6 basic (8-bit ADC res.) 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 TIMSK0 OCIE0B OCIE0A OCIE2B OCIE2A ADC 0 0 0 0 0 0 TIMSK2 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 (10-bit ADC res. / OCR0A / OCR2A 16-bit value) (8-bit value) Timer MAX or PWM After ADCSRA |= (1 << ADSC); 7 6 5 4 3 2 1 0 I/O tasks initialization, while( (ADCSRA & (1 << ADSC)) != 0 ) { } OCR0B / OCR2B start, poll, unsigned char result = ADCH; (8-bit value) for PWM capture // if 10-bit result (ADLAR = 0) use this 7 6 5 4 3 2 1 0 TCNT0 / TCNT2 result // unsigned int result = ADC; (8-bit current count Serial (UART / RS-232) Comm. value)

7 6 5 4 3 2 1 0 Pin Change Interrupts – Memorize these, practice UCSR0A RXC0 UDRE0 PCICR PCIE2 PCIE1 PCIE0 7 6 5 4 3 2 1 0 Int. Enables (D) (C) (B) UCSR0B RXEN0 TXEN0 PCMSK0 PCINT7 PCINT6 PCINT5 PCINT4 PCINT3 PCINT2 PCINT1 PCINT0 7 6 5 4 3 2 1 0 (for Port B) (PB7) (PB6) (PB5) (PB4) (PB3) (PB2) (PB1) (PB0) UCSR0C UCSZ01 UCSZ00 these, recite these!!! PCMSK1 PCINT14 PCINT13 PCINT12 PCINT11 PCINT10 PCINT9 PCINT8 7 6 5 4 3 2 1 0 (for Port C) (PC6) (PC5) (PC4) (PC3) (PC2) (PC1) (PC0) UDR0 (RX & TX Data) PCMSK2 PCINT23 PCINT22 PCINT21 PCINT20 PCINT19 PCINT18 PCINT17 PCINT16 (for Port D) (PD7) (PD6) (PD5) (PD4) (PD3) (PD2) (PD1) (PD0) 15 14 13 12 11 10 9 8 0 0 0 0 UBRR0 7 6 5 4 3 2 1 0 (Baud Rate) Helpful C-Library Functions Set Pin as Set Pin as snprintf(char* buf, int max, char* frmt, ...); DDRB |= (1 << DDB4); DDRB &= ~(1 << DDB4); Helpful Arduino Library Functions Example: Output Input char buf[9]; // Val= max 4-digits + null All register and bit position int val; definitions // val set to some integer snprintf(buf, 5, Val=%d val); _delay_ms(10); // delay 10 milli(m)-sec Set Output Check Pin _delay_us(10); // delay 10 micro(u)-sec // to ensure fixed space (num. digits) for val PORTB |= (1 << PB4); (PINB & (1 << PB4)) != 0 snprintf(buf, 5, Val=%4d val); sei(); // turn on global interrupt enable Value to 1 is 1 cli(); // turn off global interrupt enable Clear Output Check Pin PORTB &= ~(1 << PB4); (PINB & (1 << PB4)) == 0 Value to 0 is 0