Sunteți pe pagina 1din 258

SI STEME CU MI CROPROCESOARE 2013 2014

Texte ajutatoare



CUPRI NS TEMATI C

A. Arhitectura si performantele Sistemelor cu Microprocesoare (SM). Definitia SM. Discutie pe
baza SM simplu PIPIN si SM pe placa Arduino UNO cu mC Atmel AVR ATmega328p sau
placa Arduino Mega cu mC Atmel AVR ATmega2560. Masina Turing. Arhitectura Von
Neuman, Harvard si Nehalem. CISC, RISC. Paralelismul pipeline si structural
B. Arhitectura microprocesoarelor si microcontrolerelor ARM. Arduino Due
C. Sistem de dezvoltare software a Sistemelor cu Microprocesoare in assembler. AVRstudio4 si
STK500. Proteus. Macrou, Subrutina, Intrerupere, Control Unit (CU), Data Path (ALU) si
FSM. Instructiuni si directive assembler. Stiva
D. Platforma Experimentala Hack. Sistem de dezvoltare software GCC C/C++ si CodeVision a
Sistemelor cu Microprocesoare. AVRStudio4 si STK500. Proteus
E. Sistem de dezvoltare software si hardware pentru placile SM Arduino. Getting Started
Arduino. Driver. Bootloader. Configurare. Proteus si Simulator for Arduino (SfA). Exemple
si biblioteci. Limbajul de programare Processing
F. Proiectarea Sistemelor cu Microprocesoare. Sisteme cu microprocesoare incorporate. Real
Time Operating System RTOS. Robot. Programarea Sistemelor cu Microprocesoare pe
baza de modele FSM si State chart. Arduino, Matlab/Simulink si RTOS/QP. A Very Simple
Task Manager in C++
G. Asamblarea, Compilarea, Depanarea si Programarea SM cu AVRStudio4 si STK500.
Cosimularea cu Proteus si SfA. Compilarea si Programarea cu placa Arduino. JTAG, OCR,
ISP. Configurarea cu ajutorul Vrajitorului CodeVision .Fuzibile. Fritzing
H. Realizari constructive. Automat Programabil. Sistem de securitate la efractie si siguranta la
incediu. RTOS. Task manager. Sistem domotic. Sleeping Arduino. Watchdog




Cuprins
1. INTRODUCERE ....................................................................................................................................................... 4
2. ARHITECTURA FPGA .............................................................................................................................................. 4
3. ARHITECTURA SISTEMELOR CU PROCESOARE DE UZ GENERAL .............................................................................. 4
4. ARHITECTURA SISTEMELOR CU PROCESOARE DEDICATE UNUI SINGUR SCOP ....................................................... 4
5. ARHITECTURA SISTEMELOR CU PROCESOARE SPECIFICE APLICATIEI ..................................................................... 4
6. ARHITECTURA MICROPROCESOARELOR ARM ....................................................................................................... 4
7. ARHITECTURA MICROCONTROLERELOR ARM V7-M CORTEX ................................................................................. 4
8. METODE DE PROIECTARE A SISTEMELOR CU MICROCONTROLERE ........................................................................ 4
9. SISTEME DE DEZVOLTARE HARDWARE .................................................................................................................. 4
10. SISTEME DE DEZVOLTARE SOFTWARE - ASSEMBLER .......................................................................................... 4
11. SISTEME DE DEZVOLTARE SOFTWARE - C/C++ .................................................................................................. 4
11.1. AVRSTUDIO 4.18 SI WINAVR (AVR-GCC, AVR-LIBC, AVR-DUDE) ............................................................................... 4
11.2. COMPILAREA CU AVRSTUDIO 4.18 A UNUI PROGRAM ARDUINO ..................................................................................... 4
11.3. PROGRAMAREA DRIVERELOR I/O .............................................................................................................................. 6
11.3.1. Drivere I/O pentru mC AVR Atmega 32 ......................................................................................................... 6
11.3.2. Instructiuni I/O assembler orientate spre byte ........................................................................................... 10
11.3.3. Instructiuni assembler I/O orientate spre bit .............................................................................................. 12
11.3.4. Program assembler citire/scriere a unui byte ............................................................................................. 13
11.3.5. Subrutina delay ........................................................................................................................................... 16
11.3.6. Program assembler citire/scriere a unui singur bit ..................................................................................... 17
11.4. GETTING STARTED WITH GCC AND AVRSTUDIO 4.18 ................................................................................................. 18
11.4.1. Exemple ....................................................................................................................................................... 19
11.4.2. Clever code .............................................................................................................................................. 23
11.4.3. Programare in C / ATmega 16 .................................................................................................................... 24
11.4.4. Intrari si iesiri la nivel de bit ........................................................................................................................ 39
11.4.5. Proiectul struct ............................................................................................................................................ 40
11.4.6. Macro, depanare si desasamblare proiect bitop ........................................................................................ 42
11.4.7. Comunicatii seriale ...................................................................................................................................... 46
11.4.8. Program assembler pentru receptia transmisia seriala ........................................................................... 64
11.4.9. Polling vs Interrupts .................................................................................................................................... 69
11.4.10. Timers ..................................................................................................................................................... 79
11.4.11. PWM Pulse Width Modulator .............................................................................................................. 90
11.4.12. ADC Analogue to Digital Converter ....................................................................................................... 106
11.5. DEBUGGING C PROGRAM USING SIMULATOR ........................................................................................................... 125
11.6. ARDUINO PROGRAMMING NOTEBOOK ................................................................................................................... 128
11.6.1. structure .................................................................................................................................................... 133
11.6.2. variables .................................................................................................................................................... 136
11.6.3. Datatypes .................................................................................................................................................. 138
11.6.4. arithmetic.................................................................................................................................................. 140
11.6.5. constants ................................................................................................................................................... 142
11.6.6. Flow control .............................................................................................................................................. 143
11.6.7. Digital I/O.................................................................................................................................................. 147
11.6.8. Analog I/O ................................................................................................................................................. 149
11.6.9. Time .......................................................................................................................................................... 150
11.6.10. Serial ..................................................................................................................................................... 152
11.6.11. Exemple ................................................................................................................................................. 154
11.7. SABLOANE ........................................................................................................................................................ 163
11.7.1. s1Write.ino ................................................................................................................................................ 163
11.7.2. s2BlinkDelay.ino ........................................................................................................................................ 163
11.7.3. s3BlinkRead.ino ......................................................................................................................................... 163
11.7.4. s4BlinkMillis.ino ........................................................................................................................................ 163
11.7.5. s5IfReadWriteSerial.ino ............................................................................................................................ 164

11.7.6. s6FsmAnalogReadSerial.ino ...................................................................................................................... 164
11.7.7. s7InterruptsExtLed.ino .............................................................................................................................. 165
11.7.8. s8ForFadingLed.ino ................................................................................................................................... 166
11.7.9. s9CandleLightRandom.ino ........................................................................................................................ 167
11.7.10. s10SerialReadBlink.ino .......................................................................................................................... 167
11.7.11. s11SerialReadNBlink.ino ....................................................................................................................... 167
11.7.12. s12SwitchCase....................................................................................................................................... 169
11.7.13. s13 Switch statement with serial input ................................................................................................. 171
11.8. AVR TOOLS ...................................................................................................................................................... 174
11.8.1. Avr_head ................................................................................................................................................... 174
11.8.2. Avr fuses .................................................................................................................................................... 175
11.8.3. AVRstudio 4.18 tool chain ......................................................................................................................... 178
11.8.4. Atmel Studio 6.2 ........................................................................................................................................ 180
11.8.5. ASF Introduction........................................................................................................................................ 181
11.8.6. ASF Architecture ........................................................................................................................................ 182
11.8.7. Structura modulelor ASF (Atmel Software Framework) ............................................................................ 183
11.8.8. JTAGICE, STK500 si Pololu ......................................................................................................................... 184
11.8.9. Arduino bootloader ................................................................................................................................... 186
11.9. AVRSTUDIO4 SI CODEVISIONAVR ........................................................................................................................ 191
11.10. PROIECTAREA SW CU WINAVR, AVRSTUDIO4.18 SI PLACA ARDUINO UNO ................................................................ 202
11.10.1. Sablonul de pornire, exemplu blinkAVRstudio4 .................................................................................... 202
11.10.2. Operatii logice si matematice orientate spre bit .................................................................................. 205
11.10.3. Operatii I/O ........................................................................................................................................... 210
11.10.4. Comunicatii seriale UART ...................................................................................................................... 216
11.10.5. Timers ................................................................................................................................................... 223
11.10.6. Convertorul analog numeric (ADC) ....................................................................................................... 231
11.10.7. Introducere in modulatia impulsurilor in durata (PWM) ...................................................................... 244
12. GETTING STARTED ARDUINO ......................................................................................................................... 258
13. SISTEME CU MP INCORPORATE . RTOS .......................................................................................................... 258
14. INTRODUCERE IN MP ATMEGA 328P SI ARDUINO ......................................................................................... 258
15. APLICATII ARDUINO IDE 22 ............................................................................................................................ 258
16. APLICATII ATMEGA 16 SI STK500 ................................................................................................................... 258
17. APLICATII CODEVISION .................................................................................................................................. 258
18. AVR - GCC ...................................................................................................................................................... 258
19. APLICATII STK500 CODEVISION ...................................................................................................................... 258
20. APLICATII CODEVISION .................................................................................................................................. 258
21. REALIZARI CONSTRUCTIVE ............................................................................................................................. 258
22. COMPLEMENTE DE PROGRAMARE IN C ......................................................................................................... 258
23. BIBLIOGRAFIE ................................................................................................................................................ 258





1. Introducere
2. Arhitectura FPGA
3. Arhitectura sistemelor cu procesoare de uz general
4. Arhitectura sistemelor cu procesoare dedicate unui singur scop
5. Arhitectura sistemelor cu procesoare specifice aplicatiei
6. Arhitectura microprocesoarelor ARM
7. Arhitectura microcontrolerelor ARM V7-M Cortex
8. Metode de proiectare a sistemelor cu microcontrolere
9. Sisteme de dezvoltare hardware
10. Sisteme de dezvoltare software - assembler
11. Sisteme de dezvoltare software - C/C++
11.1. AVRstudio 4.18 si WinAVR (AVR-GCC, AVR-Libc, Avr-dude)
GCC = GNU Compiler Colection
Avrdude este un program care se executa pe PC si care transfera programul .HEX al mC din PC in
memoriile mC.
In prezent (2014) exista ATMELstudio5.1 si ATMELstudio6.2

11.2. Compilarea cu AVRstudio 4.18 a unui program Arduino

Se instaleaz la nceput AVRstudio4 si apoi WinAVR
Un proiect nou se incepe cu New/AVR GCC/Project name/Atmega328P si AVT simulator.
Se configureaza cu Project/Configuration Option/General/Create Hex File



Fig. 11.1 Mediul de dezvoltare AVRstudio4 cu proiectul Arduino blinkproiect




11.3. Programarea driverelor I/O
11.3.1. Drivere I/O pentru mC AVR Atmega 32




x designates port (A,B,S,D,); n designates pin number (0..7)
DDRx = 0 DDRx = 1
PORTx = 0 Read to PINX (tri-state) Pin output 0
PORTx = 1 Read to PINx with pull-up Pin outputs 1








http://users.utcluj.ro/~tmarita/PMP/Lecture/

(PUD in SFIOR)
(Pull Up Disable in Special Function Input Output Register)

PUD Pull Up Disable GLOBAL
Value 1 of bit 2 from SFIOR deactivates all pull-up resistors



To set (PUD=1)
in r17, SFIOR
ori r17, 0b00000100
out SFIOR, r17




To clear (PUD=0)
in r17, SFIOR
andi r17, 0b11111011
out SFIOR, r17











11.3.2. Instructiuni I/O assembler orientate spre byte









11.3.3. Instructiuni assembler I/O orientate spre bit





11.3.4. Program assembler citire/scriere a unui byte
;
; ********************************************
; * [Add Project title here] *
; * [Add more info on software version here] *
; * (C)20xx by [Add Copyright Info here] *
; ********************************************
;
; Included header file for target AVR type
.NOLIST
.INCLUDE "m328Pdef.inc" ; Header for ATMEGA328P
.LIST
;
;
; ============================================
; H A R D W A R E I N F O R M A T I O N
; ============================================
;
; [Add all hardware information here]
;
; ============================================
; P O R T S A N D P I N S
; ============================================
;
; [Add names for hardware ports and pins here]
; Format: .EQU Controlportout = PORTA
; .EQU Controlportin = PINA
; .EQU LedOutputPin = PORTA2
;
; ============================================
; C O N S T A N T S T O C H A N G E
; ============================================
;
; [Add all constants here that can be subject
; to change by the user]
; Format: .EQU const = $ABCD
;
; ============================================
; F I X + D E R I V E D C O N S T A N T S
; ============================================
;
; [Add all constants here that are not subject
; to change or calculated from constants]
; Format: .EQU const = $ABCD
;
; ============================================
; R E G I S T E R D E F I N I T I O N S
; ============================================
;
; [Add all register names here, include info on
; all used registers without specific names]
; Format: .DEF rmp = R16
.DEF rmp = R16 ; Multipurpose register

;
; ============================================
; S R A M D E F I N I T I O N S
; ============================================
;
.DSEG
.ORG 0X0100
; Format: Label: .BYTE N ; reserve N Bytes from Label:
;
; ============================================
; R E S E T A N D I N T V E C T O R S
; ============================================
;
.CSEG
.ORG $0000
jmp Main ; Reset vector
reti ; Int vector 1
nop

;
; ============================================
; I N T E R R U P T S E R V I C E S
; ============================================
;
; [Add all interrupt service routines here]
;
; ============================================
; M A I N P R O G R A M I N I T
; ============================================
;
Main:
; Init stack
ldi rmp, HIGH(RAMEND) ; Init MSB stack
out SPH,rmp
ldi rmp, LOW(RAMEND) ; Init LSB stack
out SPL,rmp
; Init Port B
ldi rmp,(0<<DDB7)|(0<<DDB0)|(1<<DDB1) ; Direction Port B
out DDRB,rmp
sbi PORTB,7 ; intrare cu pull-up
; [Add all other init routines here]
ldi rmp,1<<SE ; enable sleep
out MCUCR,rmp
sei
;
; ============================================
; P R O G R A M L O O P
; ============================================
;
Loop:
;sleep ; go to sleep
call Delay
in rmp, PINB

nop ;sincronizare intrare
out PORTB, rmp
rjmp loop ; go back to loop
;
Delay:
nop
nop
nop
ret
; End of source code
;





11.3.5. Subrutina delay




11.3.6. Program assembler citire/scriere a unui singur bit



11.4. Getting started with GCC and AVRstudio 4.18

Ferguson D., Software Development for Real-Time Systems, University John Hopkins, 2005
http://www.apl.jhu.edu/~doug/RealTimeSystems/SWDevForRTSys.htm
Hands-on handout.doc
AVR-GCC Plug IN.ppt
C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\university john hopkins Ferguson D\AVR-GCC_Plug-In_Hands-On\AVR-GCC Plug-In
Hands-On

C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\university john hopkins Ferguson D\picopowerlabs\TempDirforGcc trening/Getting started
with GCC and AVRstudio

#include <avr/io.h>
volatile int MyCounter;

int main()
{
DDRB = 0xFF; /* Set PORTB as output */

while(1)
{
PORTB = MyCounter++; /* Increment MyCounter and */
} /* put it out on PORTB */
}








11.4.1. Exemple
Vezi Ferguson D., Software Development for Real-Time Systems, 2005
http://www.apl.jhu.edu/~doug/RealTimeSystems/SWDevForRTSys.htm

C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\university john hopkins Ferguson D\picopowerlabs\TempDirforGcc trening/Lab2-Basic Gcc/
si Lab1 Basic tool flow and assembly si Lab3 Basic interupt

/* Demo GCC project */

#include<avr/io.h>
// function prototype
void wait(void);
volatile int MyCounter;

int main()
{
DDRB = 0XFF; /* Set PORTB as Output */

while(1)
{
PORTB = MyCounter++; /* Increment Mycounter and */
/* put it on port B */
wait();
}
}
//Delay function
void wait()
{
unsigned char i,j;

for(i=0;i<5;i++) for(j=0;j<255;j++);
}




; STK 200 LEDS and SWITCH demonstration
;.include "M8def.inc"
; .include "M163def.inc"
;.include "M128def.inc"
.include "M32def.inc"
;.include "2313def.inc"
;.include "8515def.inc"
;Variable definitions

.def Temp = R16 ;Temporary register
.def Delay = R17 ; Delay register 1
.def Delay2 = R18 ; Delay register 2

;initialization

RESET:

ser temp
;sey temp ;error for demo purposes
out DDRB,temp ; set port B to output
ldi temp,0xEE ; set a pattern into the LED's


LOOP:

out PORTB, temp ; update leds

sbis PIND, 0x00 ; if port D, pin 0 = 0
inc Temp ; then count leds one down

sbis PIND, 0x01 ; if port D, pin 1 = 0
dec Temp ; then count leds one up

sbis PIND, 0x02 ; if port D, pin 2 = 0
ror Temp ; then rotate leds one right

sbis PIND, 0x03 ; if port D, pin 3 = 0
rol Temp ; then rotate leds one left

sbis PIND, 0x04 ; if port D, pin 4 = 0
com Temp ; then invert all leds

sbis PIND, 0x05 ; if port D, pin 5 = 0
neg Temp ; then invert all leds and add 1

sbis PIND, 0x06 ; if port D, pin 6 = 0
swap Temp ; then swap nibbles of leds

;**** Delay to make leds visible




DLY:
dec Delay
brne DLY
dec Delay2
brne DLY

rjmp LOOP ; repeat loop forever.





#include <avr/io.h>
#include <avr/interrupt.h>

unsigned char led;

int main(void)
{
DDRB = 0xFF; /* use all pins on PortB for output */

TIMSK = (1<<TOIE0); /* enable TCNT0 overflow */
TCNT0 = 0; /* reset counter to get this interrupt again */
TCCR0 = (1<<CS02)|(0<<CS01)|(1<<CS00);/* count with cpu clock/1024 */

led = 9; /* init variable representing the LED state */

sei(); /* enable interrupts */
for (;;) {} /* loop forever */
}

/* Here's the ISR */

SIGNAL(SIG_OVERFLOW0) /* signal handler for tcnt0 overflow interrupt */
{
PORTB = ~led; /* invert the output since a zero means: LED on */
led <<= 1; /* move to next LED */
if (!led) /* overflow: start with Port B0 again */
led = 1;
TCNT0 = 0; /* reset counter to get this interrupt again */
}







11.4.2. Clever code

C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\university john hopkins Ferguson D\picopowerlabs\TempDirforGcc
trening\AVRTraining07.ppt







11.4.3. Programare in C / ATmega 16

C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\university Wollogong 2011\ECTE333-Lecture-07
http://www.elec.uow.edu.au/avr/microcontroller.php
















http://www.elec.uow.edu.au/avr/microcontroller.php


































































































http://www.elec.uow.edu.au/avr/microcontroller.php


















11.4.4. Intrari si iesiri la nivel de bit

One sets individual bits standard C conformal by means of more logically (bit) operations.
With the expression:
X |= (1 << Bitnumber); // a bit in x is set
X &= ~(1 << Bitnumber) ; // a bit is deleted in x
The least significant bit (for 1) of a byte has the bit number 0, the most significant (for 128) the number
7.
Example:
#include <avr/io.h>
...
#define MyBIT 2
...
PORTA |= (1 << MyBIT); /* sets bit 2 at PortA on 1 * /
PORTA &= ~(1 << MyBIT); /* deletes bit 2 at PortA */
With this method also several bits of a register can be at the same time set and reset.
Example:
#include <avr/io.h>
...
DDRA &= ~( (1<<PA0) | (1<<PA3) ); /* PA0 and PA3 as inputs */
PORTA |= (1<<PA0) | (1<<PA3); /* internal Pull UP for both switch on */
In source codes, which were developed for older version that of the avr GCC/avr libc, individual bits are
set and/or reset by means of the functions sbi and cbi. Both functions are not necessary any longer.




11.4.5. Proiectul struct

Bitul ca variabila in maniera CodeVision

#include <avr/io.h>

typedef struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} _io_reg;

#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt


#define BUTTON_PIN REGISTER_BIT(PINB,3)
#define LED_PORT REGISTER_BIT(PORTB,4)

#define BUTTON_DIR REGISTER_BIT(DDRB,3)
#define LED_DIR REGISTER_BIT(DDRB,4)

main() {
uint8_t is_button = BUTTON_PIN;

LED_DIR = 1;
BUTTON_DIR = 0;

while (1) {
LED_PORT = BUTTON_PIN;
}
}




We define a macro that will allow us to define our single bit variable:
Code:
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
The above macro works like this:

#defineis the start of a macro definition

REGI STER_BI T is the name of the macro


(tg,bt) are the parameters to the macro

The C keyword volatileis accurately described in the AVR-libc Manual Frequently Asked
Questions, in the FAQ item #1. It is also described in the article Introduction to the "Volatile"
Keyword.

_io_reg is the struct type that is typedef'ed right above the macro, and thus
_io_reg* is a pointer to such a struct, and so
(volatile _io_reg*) is a typecast to "a volatile pointer to a _io_reg struct"

& is the "address of" operator, and thus
&rg is the address of rg, ie the address of the first parameter to the macro

The ->is the "member by pointer operator", in other words it "refers" to one of the fields in the struct
that the pointer points to.

##is the token pasting operator (of the C preprocessor). The preprocessor concatenates the two
operands together so that the compiler sees one token, in this case "bit" and whatever value the bt
parameter to the macro has.

So, if you do
Code:
REGISTER_BIT(PORTB,4)
this is expanded by the C preprocessor to
Code:
((volatile _io_reg*)&PORTB)->bit4
By the way, PORTB is a macro, too. It is defined in a header file, based on your processor type. For
example, in an ATmega128, PORTB is defined as
Code:
#define PORTB _SFR_IO8(0x18)
You would be right if you guessed that _SFR_I O8 is also a macro

In the main routine, set up the LED to be an output:
Code:
LED_DIR = 1;
which after the preprocessor looks like:
Code:
((volatile _io_reg*)&DDRB)->bit4 = 1;
Similar to the description of is_button before, this translates to: Take the address of the DDRB
register. Treat that address as a pointer to a _io_reg struct. Dereference that pointer, and get the
member with the name "bit4". Set that bit to a 1.




11.4.6. Macro, depanare si desasamblare proiect bitop








/*
* bitop.c
*
* Created: 4/24/2014 7:10:07 PM
* Author: larionescu
*/


#include <avr/io.h>

#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))

int main(void){
unsigned char i; // temporary variable

DDRA = 0x00; // set PORTA for input
DDRB = 0xFF; // set PORTB for output
bit_set(DDRC,BIT(0));
//DDRC = 1<< 0;

PORTB = 0x00; // turn ON all LEDs initially

while(1){
// Read input from PORTA.
// This port will be connected to the 8 switches
i = PINA;

// Send output to PORTB.
// This port will be connected to the 8 LEDs
PORTB = i;
bit_flip(PORTC,BIT(0));
}
return 1;
}




Desasamblarea

00000000 JMP 0x0000002A Jump
00000002 JMP 0x0000003C Jump
00000004 JMP 0x0000003C Jump
00000006 JMP 0x0000003C Jump
00000008 JMP 0x0000003C Jump
0000000A JMP 0x0000003C Jump
0000000C JMP 0x0000003C Jump
0000000E JMP 0x0000003C Jump
00000010 JMP 0x0000003C Jump
00000012 JMP 0x0000003C Jump
00000014 JMP 0x0000003C Jump
00000016 JMP 0x0000003C Jump
00000018 JMP 0x0000003C Jump
0000001A JMP 0x0000003C Jump
0000001C JMP 0x0000003C Jump
0000001E JMP 0x0000003C Jump
00000020 JMP 0x0000003C Jump
00000022 JMP 0x0000003C Jump
00000024 JMP 0x0000003C Jump
00000026 JMP 0x0000003C Jump
00000028 JMP 0x0000003C Jump
0000002A CLR R1 Clear Register
0000002B OUT 0x3F,R1 Out to I/O location
0000002C LDI R28,0x5F Load immediate
0000002D LDI R29,0x08 Load immediate
0000002E OUT 0x3E,R29 Out to I/O location
0000002F OUT 0x3D,R28 Out to I/O location
00000030 LDI R18,0x00 Load immediate
00000031 LDI R26,0x60 Load immediate
00000032 LDI R27,0x00 Load immediate
00000033 RJMP PC+0x0002 Relative jump
00000034 ST X+,R1 Store indirect and postincrement
00000035 CPI R26,0x61 Compare with immediate
00000036 CPC R27,R18 Compare with carry
00000037 BRNE PC-0x03 Branch if not equal
00000038 CALL 0x0000003E Call subroutine
0000003A JMP 0x00000047 Jump
0000003C JMP 0x00000000 Jump
--- C:\ATMEL62\bitop\bitop\Debug/.././bitop.c ----------------------------------
{


bit_set(DDRB,BIT(0));
0000003E SBI 0x17,0 Set bit in I/O register
bit_set(PORTB,BIT(0));
0000003F SBI 0x18,0 Set bit in I/O register
bit_clear(PORTB,BIT(0));
00000040 CBI 0x18,0 Clear bit in I/O register
i=i+1;

00000041 LDS R24,0x0060 Load direct from data space
00000043 SUBI R24,0xFF Subtract immediate
00000044 STS 0x0060,R24 Store direct to data space
00000046 RJMP PC-0x0007 Relative jump
--- No source file -------------------------------------------------------------
00000047 CLI Global Interrupt Disable
00000048 RJMP PC-0x0000 Relative jump
00000049 NOP Undefined
0000004A NOP Undefined








11.4.7. Comunicatii seriale

http://www.elec.uow.edu.au/avr/microcontroller.php




Pan miscare pe orizontala
Tilt miscare pe verticala

Null modem is a communication method to connect two DTEs (computer, terminal, printer etc.)
directly using an RS-232 serial cable. The name stems from the historical use of the RS-232 cable to
connect two teleprinter devices to modems in order to communicate with one another; null modem
communication was possible by instead using RS-232 to connect the teleprinters directly to one
another.

























































































































11.4.8. Program assembler pentru receptia transmisia seriala






























11.4.9. Polling vs Interrupts




















































































11.4.10. Timers


















































































11.4.11. PWM Pulse Width Modulator















































































































11.4.12. ADC Analogue to Digital Converter






















































































































































11.5. Debugging C program using simulator

C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\university Wollogong 2011/Debugging C program using simulator.pdf





















11.6. Arduino Programming Notebook

C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\1_arduino programming\0_carti bune\Arduino Programming Notebook.pdf

Written and compiled by Brian W. Evans
With information or inspiration taken from:
http://www.arduino.cc
http://www.wiring.org.co
http://www.arduino.cc/en/Booklet/HomePage
http://cslibrary.stanford.edu/101/
Including material written by:
Paul Badger
Massimo Banzi
Hernando Barragn
David Cuartielles
Tom Igoe
Daniel Jolliffe
Todd Kurt
David Mellis
and others
Published:
First Edition August 2007
Second Edition September 2008

This work is licensed under the Creative Commons
Attribution-Share Alike 2.5 License.
To view a copy of this license, visit:
http://creativecommons.org/licenses/by-sa/2.5/
Or send a letter to:
Creative Commons
171 Second Street, Suite 300
San Francisco, California, 94105, USA

contents
structure
structure
setup()
loop()
functions
{} curly braces
; semicolon
/* */ block comments
// line comments
variables
variables
variable declaration
variable scope
datatypes
byte
int
long
float
arrays
arithmetic
arithmetic
compound assignments
comparison operators
logical operators
constants
constants
true/false
high/low
input/output

























flow control
if
if else
for
while
do while
digital i/o
pinMode(pin, mode)
digitalRead(pin)
digitalWrite(pin, value)
analog i/o
analogRead(pin)
analogWrite(pin, value)
time
delay(ms)
millis()
math
min(x, y)
max(x, y)
random
randomSeed(seed)
random(min, max)
serial
Serial.begin(rate)
Serial.println(data)
appendix
digital output
digital input
high current output
pwm output
potentiometer input
variable resistor input
servo output


























preface
This notebook serves as a convenient, easy to use programming reference for the
command structure and basic syntax of the Arduino microcontroller. To keep it
simple, certain exclusions were made that make this a beginners reference best
used as a secondary source alongside other websites, books, workshops, or classes.
This decision has lead to a slight emphasis on using the Arduino for standalone
purposes and, for example, excludes the more complex uses of arrays or advanced
forms of serial communication.
Beginning with the basic structure of Arduino's C derived programming language, this
notebook continues on to describe the syntax of the most common elements of the
language and illustrates their usage with examples and code fragments. This includes
many functions of the core library followed by an appendix with sample schematics
and starter programs. The overall format compliments OSullivan and Igoes Physical
Computing where possible.
For an introduction to the Arduino and interactive design, refer to Banzis Getting
Started with Arduino, aka the Arduino Booklet. For the brave few interested in the
intricacies of programming in C, Kernighan and Ritchies The C Programming
Language, second edition, as well as Prinz and Crawfords C in a Nutshell, provide
some insight into the original programming syntax.
Above all else, this notebook would not have been possible without the great
community of makers and shear mass of original material to be found at the Arduino
website, playground, and forum at http://www.arduino.cc.


11.6.1. structure
The basic structure of the Arduino programming language is fairly simple and runs in
at least two parts. These two required parts, or functions, enclose blocks of
statements.
void setup()
{
statements;
}
void loop()
{
statements;
}
Where setup() is the preparation, loop() is the execution. Both functions are required
for the program to work.
The setup function should follow the declaration of any variables at the very
beginning of the program. It is the first function to run in the program, is run only
once, and is used to set pinMode or initialize serial communication.
The loop function follows next and includes the code to be executed continuously
reading inputs, triggering outputs, etc. This function is the core of all Arduino
programs and does the bulk of the work.
setup()
The setup() function is called once when your program starts. Use it to initialize pin
modes, or begin serial. It must be included in a program even if there are no
statements to run.
void setup()
{
pinMode(pin, OUTPUT);
}
// sets the 'pin' as output
loop()
After calling the setup() function, the loop() function does precisely what its name
suggests, and loops consecutively, allowing the program to change, respond, and
control the Arduino board.
void loop()
{
digitalWrite(pin, HIGH);
delay(1000);
digitalWrite(pin, LOW);
delay(1000);
}
//
//
//
//
turns 'pin' on
pauses for one second
turns 'pin' off
pauses for one second
structure | 7

functions
A function is a block of code that has a name and a block of statements that are
executed when the function is called. The functions void setup() and void loop() have
already been discussed and other built-in functions will be discussed later.
Custom functions can be written to perform repetitive tasks and reduce clutter in a
program. Functions are declared by first declaring the function type. This is the type
of value to be returned by the function such as 'int' for an integer type function. If no
value is to be returned the function type would be void. After type, declare the name
given to the function and in parenthesis any parameters being passed to the function.
type functionName(parameters)
{
statements;
}
The following integer type function delayVal() is used to set a delay value in a
program by reading the value of a potentiometer. It first declares a local variable v,
sets v to the value of the potentiometer which gives a number between 0-1023, then
divides that value by 4 for a final value between 0-255, and finally returns that value
back to the main program.
int delayVal()
{
int v;
v = analogRead(pot);
v /= 4;
return v;
}
//
//
//
//
create temporary variable 'v'
read potentiometer value
converts 0-1023 to 0-255
return final value
{} curly braces
Curly braces (also referred to as just "braces" or "curly brackets") define the
beginning and end of function blocks and statement blocks such as the void loop()
function and the for and if statements.
type function()
{
statements;
}
An opening curly brace { must always be followed by a closing curly brace }. This is
often referred to as the braces being balanced. Unbalanced braces can often lead to
cryptic, impenetrable compiler errors that can sometimes be hard to track down in a
large program.
The Arduino environment includes a convenient feature to check the balance of curly
braces. Just select a brace, or even click the insertion point immediately following a
brace, and its logical companion will be highlighted.
8 | structure

; semicolon
A semicolon must be used to end a statement and separate elements of the program.
A semicolon is also used to separate elements in a for loop.
int x = 13; // declares variable 'x' as the integer 13
Note: Forgetting to end a line in a semicolon will result in a compiler error. The error
text may be obvious, and refer to a missing semicolon, or it may not. If an
impenetrable or seemingly illogical compiler error comes up, one of the first things to
check is a missing semicolon, near the line where the compiler complained.
/* */ block comments
Block comments, or multi-line comments, are areas of text ignored by the program
and are used for large text descriptions of code or comments that help others
understand parts of the program. They begin with /* and end with */ and can span
multiple lines.
/*
*/
Because comments are ignored by the program and take no memory space they
should be used generously and can also be used to comment out blocks of code for
debugging purposes.
Note: While it is possible to enclose single line comments within a block comment,
enclosing a second block comment is not allowed.
this is an enclosed block comment
dont forget the closing comment -
they have to be balanced!
// line comments
Single line comments begin with // and end with the next line of code. Like block
comments, they are ignored by the program and take no memory space.
// this is a single line comment
Single line comments are often used after a valid statement to provide more
information about what the statement accomplishes or to provide a future reminder.
structure | 9

11.6.2. variables
A variable is a way of naming and storing a numerical value for later use by the
program. As their namesake suggests, variables are numbers that can be continually
changed as opposed to constants whose value never changes. A variable needs to
be declared and optionally assigned to the value needing to be stored. The following
code declares a variable called inputVariable and then assigns it the value obtained
on analog input pin 2:
//
//
inputVariable = analogRead(2); //
//
int inputVariable = 0; declares a variable and
assigns value of 0
set variable to value of
analog pin 2
inputVariable is the variable itself. The first line declares that it will contain an int,
short for integer. The second line sets the variable to the value at analog pin 2. This
makes the value of pin 2 accessible elsewhere in the code.
Once a variable has been assigned, or re-assigned, you can test its value to see if it
meets certain conditions, or you can use its value directly. As an example to illustrate
three useful operations with variables, the following code tests whether the
inputVariable is less than 100, if true it assigns the value 100 to inputVariable, and
then sets a delay based on inputVariable which is now a minimum of 100:
if (inputVariable < 100) // tests variable if less than 100
{
inputVariable = 100;// if true assigns value of 100
}
delay(inputVariable);// uses variable as delay
Note: Variables should be given descriptive names, to make the code more readable.
Variable names like tiltSensor or pushButton help the programmer and anyone else
reading the code to understand what the variable represents. Variable names like var
or value, on the other hand, do little to make the code readable and are only used
here as examples. A variable can be named any word that is not already one of the
keywords in the Arduino language.
variable declaration
All variables have to be declared before they can be used. Declaring a variable
means defining its value type, as in int, long, float, etc., setting a specified name, and
optionally assigning an initial value. This only needs to be done once in a program but
the value can be changed at any time using arithmetic and various assignments.
The following example declares that inputVariable is an int, or integer type, and that
its initial value equals zero. This is called a simple assignment.
int inputVariable = 0;
A variable can be declared in a number of locations throughout the program and
where this definition takes place determines what parts of the program can use the
variable.
10 | variables

variable scope
A variable can be declared at the beginning of the program before void setup(),
locally inside of functions, and sometimes within a statement block such as for loops.
Where the variable is declared determines the variable scope, or the ability of certain
parts of a program to make use of the variable.
A global variable is one that can be seen and used by every function and statement in
a program. This variable is declared at the beginning of the program, before the
setup() function.
A local variable is one that is defined inside a function or as part of a for loop. It is
only visible and can only be used inside the function in which it was declared. It is
therefore possible to have two or more variables of the same name in different parts
of the same program that contain different values. Ensuring that only one function has
access to its variables simplifies the program and reduces the potential for
programming errors.
The following example shows how to declare a few different types of variables and
demonstrates each variables visibility:
int value;
void setup()
{
// no setup needed
}
void loop()
{
for (int i=0; i<20;)
{
i++;
}
float f;
}
// 'value' is visible
// to any function
// 'i' is only visible
// inside the for-loop
// 'f' is only visible
// inside loop
variables | 11

11.6.3. Datatypes

byte
Byte stores an 8-bit numerical value without decimal points. They have a range of 0-
255.
byte someVariable = 180; // declares 'someVariable'
// as a byte type
int
Integers are the primary datatype for storage of numbers without decimal points and
store a 16-bit value with a range of 32,767 to -32,768.
int someVariable = 1500; // declares 'someVariable'
// as an integer type
Note: Integer variables will roll over if forced past their maximum or minimum values
by an assignment or comparison. For example, if x = 32767 and a subsequent
statement adds 1 to x, x = x + 1 or x++, x will then rollover and equal -32,768.
long
Extended size datatype for long integers, without decimal points, stored in a 32-bit
value with a range of 2,147,483,647 to -2,147,483,648.
long someVariable = 90000; // declares 'someVariable'
// as a long type
float
A datatype for floating-point numbers, or numbers that have a decimal point. Floating-
point numbers have greater resolution than integers and are stored as a 32-bit value
with a range of 3.4028235E+38 to -3.4028235E+38.
float someVariable = 3.14; // declares 'someVariable'
// as a floating-point type
Note: Floating-point numbers are not exact, and may yield strange results when
compared. Floating point math is also much slower than integer math in performing
calculations, so should be avoided if possible.
12 | datatypes

arrays
An array is a collection of values that are accessed with an index number. Any value
in the array may be called upon by calling the name of the array and the index
number of the value. Arrays are zero indexed, with the first value in the array
beginning at index number 0. An array needs to be declared and optionally assigned
values before they can be used.
int myArray[] = {value0, value1, value2...}
Likewise it is possible to declare an array by declaring the array type and size and
later assign values to an index position:
int myArray[5];
myArray[3] = 10;
// declares integer array w/ 6 positions
// assigns the 4th index the value 10
To retrieve a value from an array, assign a variable to the array and index position:
x = myArray[3]; // x now equals 10
Arrays are often used in for loops, where the increment counter is also used as the
index position for each array value. The following example uses an array to flicker an
LED. Using a for loop, the counter begins at 0, writes the value contained at index
position 0 in the array flicker[], in this case 180, to the PWM pin 10, pauses for
200ms, then moves to the next index position.
int ledPin = 10;// LED on pin 10
byte flicker[] = {180, 30, 255, 200, 10, 90, 150, 60};
// above array of 8
void setup()// different values
{
pinMode(ledPin, OUTPUT);// sets OUTPUT pin
}
void loop()
{
for(int i=0; i<7; i++)
{
analogWrite(ledPin, flicker[i]);
delay(200);
}
}
//
//
//
//
loop equals number
of values in array
write index value
pause 200ms
datatypes | 13

11.6.4. arithmetic
Arithmetic operators include addition, subtraction, multiplication, and division. They
return the sum, difference, product, or quotient (respectively) of two operands.
y
x
i
r
=
=
=
=
y
x
j
r
+
-
*
/
3;
7;
6;
5;
The operation is conducted using the data type of the operands, so, for example, 9 / 4
results in 2 instead of 2.25 since 9 and 4 are ints and are incapable of using decimal
points. This also means that the operation can overflow if the result is larger than
what can be stored in the data type.
If the operands are of different types, the larger type is used for the calculation. For
example, if one of the numbers (operands) are of the type float and the other of type
integer, floating point math will be used for the calculation.
Choose variable sizes that are large enough to hold the largest results from your
calculations. Know at what point your variable will rollover and also what happens in
the other direction e.g. (0 - 1) OR (0 - - 32768). For math that requires fractions, use
float variables, but be aware of their drawbacks: large size and slow computation
speeds.
Note: Use the cast operator e.g. (int)myFloat to convert one variable type to another
on the fly. For example, i = (int)3.6 will set i equal to 3.
compound assignments
Compound assignments combine an arithmetic operation with a variable assignment.
These are commonly found in for loops as described later. The most common
compound assignments include:
x
x
x
x
x
x
++
--
+=
-=
*=
/=
// same as x = x + 1, or increments x by +1
// same as x = x - 1, or decrements x by -1
// same as x = x + y, or increments x by +y
// same as x = x - y, or decrements x by -y
// same as x = x * y, or multiplies x by y
// same as x = x / y, or divides x by y
y
y
y
y
Note: For example, x *= 3 would triple the old value of x and re-assign the resulting
value to x.
14 | arithmetic

comparison operators
Comparisons of one variable or constant against another are often used in if
statements to test if a specified condition is true. In the examples found on the
following pages, ?? is used to indicate any of the following conditions:
x
x
x
x
x
x
==
!=
<
>
<=
>=
y
y
y
y
y
y
//
//
//
//
//
//
x
x
x
x
x
x
is
is
is
is
is
is
equal to y
not equal to
less than y
greater than
less than or
greater than
y
y
equal to y
or equal to y
logical operators
Logical operators are usually a way to compare two expressions and return a TRUE
or FALSE depending on the operator. There are three logical operators, AND, OR,
and NOT, that are often used in if statements:
Logical AND:
if (x > 0 && x < 5)
Logical OR:
if (x > 0 || y > 0)
Logical NOT:
if (!x > 0)
// true only if both
// expressions are true
// true if either
// expression is true
// true only if
// expression is false
arithmetic | 15

11.6.5. constants
The Arduino language has a few predefined values, which are called constants. They
are used to make the programs easier to read. Constants are classified in groups.
true/false
These are Boolean constants that define logic levels. FALSE is easily defined as 0
(zero) while TRUE is often defined as 1, but can also be anything else except zero.
So in a Boolean sense, -1, 2, and -200 are all also defined as TRUE.
if (b == TRUE);
{
doSomething;
}
high/low
These constants define pin levels as HIGH or LOW and are used when reading or
writing to digital pins. HIGH is defined as logic level 1, ON, or 5 volts while LOW is
logic level 0, OFF, or 0 volts.
digitalWrite(13, HIGH);
input/output
Constants used with the pinMode() function to define the mode of a digital pin as
either INPUT or OUTPUT.
pinMode(13, OUTPUT);
16 | constants

11.6.6. Flow control

if
if statements test whether a certain condition has been reached, such as an analog
value being above a certain number, and executes any statements inside the
brackets if the statement is true. If false the program skips over the statement. The
format for an if test is:
if (someVariable ?? value)
{
doSomething;
}
The above example compares someVariable to another value, which can be either a
variable or constant. If the comparison, or condition in parentheses is true, the
statements inside the brackets are run. If not, the program skips over them and
continues on after the brackets.
Note: Beware of accidentally using =, as in if(x=10), while technically valid,
defines the variable x to the value of 10 and is as a result always true. Instead use
==, as in if(x==10), which only tests whether x happens to equal the value 10 or
not. Think of = as equals opposed to == being is equal to.
flow control | 17

if else
if else allows for either-or decisions to be made. For example, if you wanted to test
a digital input, and do one thing if the input went HIGH or instead do another thing if
the input was LOW, you would write that this way:
if (inputPin == HIGH)
{
doThingA;
}
else
{
doThingB;
}
else can also precede another if test, so that multiple, mutually exclusive tests can be
run at the same time. It is even possible to have an unlimited number of these else
branches. Remember though, only one set of statements will be run depending on
the condition tests:
if (inputPin < 500)
{
doThingA;
}
else if (inputPin >= 1000)
{
doThingB;
}
else
{
doThingC;
}
Note: An if statement simply tests whether the condition inside the parenthesis is true
or false. This statement can be any valid C statement as in the first example, if
(inputPin == HIGH). In this example, the if statement only checks to see if
indeed the specified input is at logic level high, or +5v.
18 | flow control

for
The for statement is used to repeat a block of statements enclosed in curly braces a
specified number of times. An increment counter is often used to increment and
terminate the loop. There are three parts, separated by semicolons (;), to the for loop
header:
for (initialization; condition; expression)
{
doSomething;
}
The initialization of a local variable, or increment counter, happens first and only
once. Each time through the loop, the following condition is tested. If the condition
remains true, the following statements and expression are executed and the condition
is tested again. When the condition becomes false, the loop ends.
The following example starts the integer i at 0, tests to see if i is still less than 20 and
if true, increments i by 1 and executes the enclosed statements:
for (int i=0; i<20; i++)
{
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
}
//
//
//
//
//
//
declares i, tests if less
than 20, increments i by 1
turns pin 13 on
pauses for 1/4 second
turns pin 13 off
pauses for 1/4 second
Note: The C for loop is much more flexible than for loops found in some other
computer languages, including BASIC. Any or all of the three header elements may
be omitted, although the semicolons are required. Also the statements for
initialization, condition, and expression can be any valid C statements with unrelated
variables. These types of unusual for statements may provide solutions to some rare
programming problems.
flow control | 19

while
while loops will loop continuously, and infinitely, until the expression inside the
parenthesis becomes false. Something must change the tested variable, or the while
loop will never exit. This could be in your code, such as an incremented variable, or
an external condition, such as testing a sensor.
while (someVariable ?? value)
{
doSomething;
}
The following example tests whether someVariable is less than 200 and if true
executes the statements inside the brackets and will continue looping until
someVariable is no longer less than 200.
while (someVariable < 200) // tests if less than 200
{
doSomething;// executes enclosed statements
someVariable++;// increments variable by 1
}
do while
The do loop is a bottom driven loop that works in the same manner as the while loop,
with the exception that the condition is tested at the end of the loop, so the do loop
will always run at least once.
do
{
doSomething;
} while (someVariable ?? value);
The following example assigns readSensors() to the variable x, pauses for 50
milliseconds, then loops indefinitely until x is no longer less than 100:
do
{
x = readSensors();
delay (50);
} while (x < 100);
// assigns the value of
// readSensors() to x
// pauses 50 milliseconds
// loops if x is less than 100
20 | flow control

11.6.7. Digital I/O

pinMode(pin, mode)
Used in void setup() to configure a specified pin to behave either as an INPUT or
an OUTPUT.
pinMode(pin, OUTPUT); // sets pin to output
Arduino digital pins default to inputs, so they don't need to be explicitly declared as
inputs with pinMode(). Pins configured as INPUT are said to be in a high-impedance
state.
There are also convenient 20K pullup resistors built into the Atmega chip that can
be accessed from software. These built-in pullup resistors are accessed in the
following manner:
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
// set pin to input
// turn on pullup resistors
Pullup resistors would normally be used for connecting inputs like switches. Notice in
the above example it does not convert pin to an output, it is merely a method for
activating the internal pull-ups.
Pins configured as OUTPUT are said to be in a low-impedance state and can provide
40 mA (milliamps) of current to other devices/circuits. This is enough current to
brightly light up an LED (don't forget the series resistor), but not enough current to run
most relays, solenoids, or motors.
Short circuits on Arduino pins and excessive current can damage or destroy the
output pin, or damage the entire Atmega chip. It is often a good idea to connect an
OUTPUT pin to an external device in series with a 470 or 1K resistor.
digital i/o | 21

digitalRead(pin)
Reads the value from a specified digital pin with the result either HIGH or LOW. The
pin can be specified as either a variable or constant (0-13).
value = digitalRead(Pin); // sets 'value' equal to
// the input pin
digitalWrite(pin, value)
Outputs either logic level HIGH or LOW at (turns on or off) a specified digital pin. The
pin can be specified as either a variable or constant (0-13).
digitalWrite(pin, HIGH); // sets 'pin' to high
The following example reads a pushbutton connected to a digital input and turns on
an LED connected to a digital output when the button has been pressed:
int led= 13;
int pin= 7;
int value = 0;
// connect LED to pin 13
// connect pushbutton to pin 7
// variable to store the read value
void setup()
{
pinMode(led, OUTPUT);
pinMode(pin, INPUT);
}
// sets pin 13 as output
// sets pin 7 as input
void loop()
{
value = digitalRead(pin);
digitalWrite(led, value);
}
//
//
//
//
sets 'value' equal to
the input pin
sets 'led' to the
button's value
22 | digital i/o



11.6.8. Analog I/O

analogRead(pin)
Reads the value from a specified analog pin with a 10-bit resolution. This function
only works on the analog in pins (0-5). The resulting integer values range from 0 to
1023.
value = analogRead(pin); // sets 'value' equal to 'pin'
Note: Analog pins unlike digital ones, do not need to be first declared as INPUT nor
OUTPUT.
analogWrite(pin, value)
Writes a pseudo-analog value using hardware enabled pulse width modulation
(PWM) to an output pin marked PWM. On newer Arduinos with the ATmega168 chip,
this function works on pins 3, 5, 6, 9, 10, and 11. Older Arduinos with an ATmega8
only support pins 9, 10, and 11. The value can be specified as a variable or constant
with a value from 0-255.
analogWrite(pin, value); // writes 'value' to analog 'pin'
A value of 0 generates a steady 0 volts output at the specified pin; a value of 255
generates a steady 5 volts output at the specified pin. For values in between 0 and
255, the pin rapidly alternates between 0 and 5 volts - the higher the value, the more
often the pin is HIGH (5 volts). For example, a value of 64 will be 0 volts three-
quarters of the time, and 5 volts one quarter of the time; a value of 128 will be at 0
half the time and 255 half the time; and a value of 192 will be 0 volts one quarter of
the time and 5 volts three-quarters of the time.
Because this is a hardware function, the pin will generate a steady wave after a call to
analogWrite in the background until the next call to analogWrite (or a call to
digitalRead or digitalWrite on the same pin).
Note: Analog pins unlike digital ones, do not need to be first declared as INPUT nor
OUTPUT.
The following example reads an analog value from an analog input pin, converts the
value by dividing by 4, and outputs a PWM signal on a PWM pin:
int led = 10;
int pin = 0;
int value;
void setup(){}
// LED with 220 resistor on pin 10
// potentiometer on analog pin 0
// value for reading
// no setup needed
void loop()
{
value = analogRead(pin);
value /= 4;
analogWrite(led, value);
}
// sets 'value' equal to 'pin'
// converts 0-1023 to 0-255
// outputs PWM signal to led
analog i/o | 23



11.6.9. Time


delay(ms)
Pauses a program for the amount of time as specified in milliseconds, where 1000
equals 1 second.
delay(1000); // waits for one second
millis()
Returns the number of milliseconds since the Arduino board began running the
current program as an unsigned long value.
value = millis(); // sets value equal to millis()
Note: This number will overflow (reset back to zero), after approximately 9 hours.
min(x, y)
Calculates the minimum of two numbers of any data type and returns the smaller
number.
value = min(value, 100); // sets 'value' to the smaller of
// 'value' or 100, ensuring that
// it never gets above 100.
max(x, y)
Calculates the maximum of two numbers of any data type and returns the larger
number.
value = max(value, 100); // sets 'value' to the larger of
// 'value' or 100, ensuring that
// it is at least 100.
24 | time and math

randomSeed(seed)
Sets a value, or seed, as the starting point for the random() function.
randomSeed(value); // sets value as the random seed
Because the Arduino is unable to create a truly random number, randomSeed allows
you to place a variable, constant, or other function into the random function, which
helps to generate more random "random numbers. There are a variety of different
seeds, or functions, that can be used in this function including millis() or even
analogRead() to read electrical noise through an analog pin.
random(max)
random(min, max)
The random function allows you to return pseudo-random numbers within a range
specified by min and max values.
value = random(100, 200); // sets 'value' to a random
// number between 100-200
Note: Use this after using the randomSeed() function.
The following example creates a random value between 0-255 and outputs a PWM
signal on a PWM pin equal to the random value:
int randNumber;
int led = 10;
void setup() {}
// variable to store the random value
// LED with 220 resistor on pin 10
// no setup needed
void loop()
{
randomSeed(millis());
randNumber = random(255);
analogWrite(led, randNumber);
delay(500);
}
//
//
//
//
sets millis() as seed
random number from 0-255
outputs PWM signal
pauses for half a second
random | 25


11.6.10. Serial

Serial.begin(rate)
Opens serial port and sets the baud rate for serial data transmission. The typical
baud rate for communicating with the computer is 9600 although other speeds are
supported.
void setup()
{
Serial.begin(9600);
}
// opens serial port
// sets data rate to 9600 bps
Note: When using serial communication, digital pins 0 (RX) and 1 (TX) cannot be
used at the same time.
Serial.println(data)
Prints data to the serial port, followed by an automatic carriage return and line feed.
This command takes the same form as Serial.print(), but is easier for reading data on
the Serial Monitor.
Serial.println(analogValue); // sends the value of
// 'analogValue'
Note: For more information on the various permutations of the Serial.println() and
Serial.print() functions please refer to the Arduino website.
The following simple example takes a reading from analog pin0 and sends this data
to the computer every 1 second.
void setup()
{
Serial.begin(9600);
}
// sets serial to 9600bps
void loop()
{
Serial.println(analogRead(0)); // sends analog value
delay(1000);// pauses for 1 second
}
26 | serial


11.6.11. Exemple

digital output
This is the basic hello world program used to simply turn something on or off. In this
example, an LED is connected to pin13, and is blinked every second. The resistor
may be omitted on this pin since the Arduino has one built in.
int ledPin = 13;
void setup()
{
pinMode(ledPin, OUTPUT);
}
void loop()
{
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
// LED on digital pin 13
// run once
// sets pin 13 as output
// run over and over again
//
//
//
//
turns the LED on
pauses for 1 second
turns the LED off
pauses for 1 second
appendix | 29

digital input
This is the simplest form of input with only two possible states: on or off. This
example reads a simple switch or pushbutton connected to pin2. When the switch is
closed the input pin will read HIGH and turn on an LED.
int ledPin = 13;
int inPin = 2;
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(inPin, INPUT);
}
// output pin for the LED
// input pin (for a switch)
// declare LED as output
// declare switch as input
void loop()
{
if (digitalRead(inPin) == HIGH)
{
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
}
// check if input is HIGH
//
//
//
//
turns
pause
turns
pause
the
for
the
for
LED on
1 second
LED off
1 second
30 | appendix

high current output
Sometimes it is necessary to control more than 40ma from the Arduino. In this case a
MOSFET or transistor could be used to switch higher current loads. The following
example quickly turns on and off the MOSFET 5 times every second.
Note: The schematic shows a motor and protection diode but other non-inductive
loads could be used without the diode.
int outPin = 5; // output pin for the MOSFET
void setup()
{
pinMode(outPin, OUTPUT);
}
void loop()
{
for (int i=0; i<=5; i++)
{
digitalWrite(outPin, HIGH);
delay(250);
digitalWrite(outPin, LOW);
delay(250);
}
delay(1000);
}
// sets pin5 as output
// loops 5 times
//
//
//
//
turns MOSFET on
pauses 1/4 second
turns MOSFET off
pauses 1/4 second
// pauses 1 second
appendix | 31

pwm output
Pulsewidth Modulation (PWM) is a way to fake an analog output by pulsing the
output. This could be used to dim and brighten an LED or later to control a servo
motor. The following example slowly brightens and dims an LED using for loops.
int ledPin = 9; // PWM pin for the LED
// no setup needed void setup(){}
void loop()
{
for (int i=0; i<=255;
{
analogWrite(ledPin,
delay(100);
}
for (int i=255; i>=0;
{
analogWrite(ledPin,
delay(100);
}
}
i++)
i);
i--)
i);
// ascending value for i
// sets brightess level to i
// pauses for 100ms
// descending value for i
// sets brightess level to i
// pauses for 100ms
32 | appendix

potentiometer input
Using a potentiometer and one of the Arduinos analog-to-digital conversion (ADC)
pins it is possible to read analog values from 0-1024. The following example uses a
potentiometer to control an LEDs rate of blinking.
int potPin = 0;
int ledPin = 13;
// input pin for the potentiometer
// output pin for the LED
void setup()
{
pinMode(ledPin, OUTPUT);
}
// declare ledPin as OUTPUT
void loop()
{
digitalWrite(ledPin, HIGH);
delay(analogRead(potPin));
digitalWrite(ledPin, LOW);
delay(analogRead(potPin));
}
//
//
//
//
turns
pause
turns
pause
ledPin on
program
ledPin off
program
appendix | 33

variable resistor input
Variable resistors include CdS light sensors, thermistors, flex sensors, and so on.
This example makes use of a function to read the analog value and set a delay time.
This controls the speed at which an LED brightens and dims.
int ledPin=
int analogPin =
void setup(){}
9;
0;
// PWM pin for the LED
// variable resistor on analog pin 0
// no setup needed
void loop()
{
for (int i=0; i<=255;
{
analogWrite(ledPin,
delay(delayVal());
}
for (int i=255; i>=0;
{
analogWrite(ledPin,
delay(delayVal());
}
}
i++)
i);
i--)
i);
// ascending value for i
// sets brightess level to i
// gets time value and pauses
// descending value for i
// sets brightess level to i
// gets time value and pauses
int delayVal()
{
int v;
v = analogRead(analogPin);
v /= 8;
return v;
}
//
//
//
//
create temporary variable
read analog value
convert 0-1024 to 0-128
returns final value
34 | appendix

servo output
Hobby servos are a type of self-contained motor that can move in a 180 arc. All that
is needed is a pulse sent every 20ms. This example uses a servoPulse function to
move the servo from 10 -170 and back again.
int servoPin = 2;
int myAngle;
int pulseWidth;
// servo connected to digital pin 2
// angle of the servo roughly 0-180
// servoPulse function variable
void setup()
{
pinMode(servoPin, OUTPUT);
}
// sets pin 2 as output
void servoPulse(int servoPin, int myAngle)
{
pulseWidth = (myAngle * 10) + 600; // determines delay
digitalWrite(servoPin, HIGH);// set servo high
delayMicroseconds(pulseWidth);// microsecond pause
digitalWrite(servoPin, LOW);// set servo low
}
void loop()
{
// servo starts at 10 deg and rotates to 170 deg
for (myAngle=10; myAngle<=170; myAngle++)
{
servoPulse(servoPin, myAngle);// send pin and angle
delay(20);// refresh cycle
}
// servo starts at 170 deg and rotates to 10 deg
for (myAngle=170; myAngle>=10; myAngle--)
{
servoPulse(servoPin, myAngle);// send pin and angle
delay(20);// refresh cycle
}
}
appendix | 35





11.7. Sabloane
http://arduino.cc/en/Tutorial/HomePage

11.7.1. s1Write.ino
void setup()
{
pinMode(13, OUTPUT);
}

void loop()
{
digitalWrite(13, HIGH);
}

11.7.2. s2BlinkDelay.ino
void setup()
{
pinMode(13, OUTPUT);
}

void loop()
{
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
}

11.7.3. s3BlinkRead.ino
void setup()
{
pinMode(13, OUTPUT);
}

void loop()
{
digitalWrite(13, !digitalRead(13));
delay(1000);

}

11.7.4. s4BlinkMillis.ino
long pre = 0;
long now = 0;
int del = 1;
int ledState = LOW;

void setup()
{
pinMode(13, OUTPUT);
}


void loop()
{
now = millis();

if(now - pre >= del) {
// save the last time you blinked the LED
pre = now;

// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;

// set the LED with the ledState of the variable:
digitalWrite(13, ledState);
}
}

11.7.5. s5IfReadWriteSerial.ino
int x=0;

void setup() {
pinMode(2, INPUT);
pinMode(13, OUTPUT);
Serial.begin(9600);
}


void loop() {
x = digitalRead(2);
if (x==1) {
digitalWrite(13, High)
}
else {
digitalWrite(13, LOW)
}
delay(1000);

}

11.7.6. s6FsmAnalogReadSerial.ino
int x=0;
int range=0;
int min=0;
int Max=600;

void setup() {
Serial.begin(9600);
}

void loop() {
x=analogRead(A0);
range=map(x, min, Max, 0, 3);
switch(range) {
case 0:
Serial.println("dark");
break;

case 1:
Serial.println("dim");
break;
case 2:
Serial.println("medium");
break;
case 3:
Serial.println("bright");
break;
}
}
11.7.7. s7InterruptsExtLed.ino
C:\Users\larionescu\Documents\107c SM Sisteme cu microprocesoare\0_
Simulator for Arduino 099\sabloane\s7_InterruptsExtLed


volatile int state = LOW;

void setup() {
pinMode(2, INPUT);
pinMode(13, OUTPUT);
attachInterrupt(0, blink, CHANGE);
}

void loop() {
digitalWrite(13, state);
}

void blink()
{
state = !state;
}



11.7.8. s8ForFadingLed.ino
http://arduino.cc/en/Tutorial/Fading
int ledPin = 13; // LED connected to digital pin 13

void setup() {
// nothing happens in setup
}

void loop() {
// fade in from min to max in increments of 5 points:
for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) {
// sets the value (range from 0 to 255):
analogWrite(ledPin, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}

// fade out from max to min in increments of 5 points:
for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) {
// sets the value (range from 0 to 255):
analogWrite(ledPin, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}


11.7.9. s9CandleLightRandom.ino
/*
* Use random numbers to emulate a flickering candle with a PWM'd LED
*
*/

int ledPin = 13; // select the pin for the LED
int val = 0; // variable that holds the current LED brightness
int delayval = 0; // variable that holds the current delay time

void setup() {
randomSeed(0); // initialize the random number generator
pinMode(ledPin, OUTPUT); // declare the ledPin as an OUTPUT
}

void loop() {
val = random(100,255); // pick a random number between 100 and 255
analogWrite(ledPin, val); // set the LED brightness

delayval = random(50,150); // pick a random number between 30 and 100
delay(delayval); // delay that many milliseconds
}


11.7.10. s10SerialReadBlink.ino
/*
* Blink the pin 13 LED if an 'H' is received over the serial port
*
*/
int ledPin = 13; // select the pin for the LED
int val = 0; // variable to store the data from the serial port

void setup() {
pinMode(ledPin,OUTPUT); // declare the LED's pin as output
Serial.begin(9600); // connect to the serial port
}

void loop () {
// Serial.available() is a way to see if there's serial data
// without pausing your code
if( Serial.available()>0 ) {
val = Serial.read(); // read the serial port
if( val == 'H' ) { // if it's an 'H', blink the light
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
}
}

}






11.7.11. s11SerialReadNBlink.ino

/* -----------------
* Turns on and off a light emitting diode(LED) connected to digital
* pin 13. The LED will blink the number of times given by a
* single-digit ASCII number read from the serial port.
*
* Created 18 October 2006
* copyleft 2006 Tod E. Kurt <tod@todbot.com>
* http://todbot.com/
*
* based on "serial_read_advanced" example
*/

int ledPin = 13; // select the pin for the LED
int val = 0; // variable to store the data from the serial port

void setup() {
pinMode(ledPin,OUTPUT); // declare the LED's pin as output
Serial.begin(19200); // connect to the serial port
Serial.println("Welcome to SerialReadBlink!");
}

void loop () {
val = Serial.read(); // read the serial port

// if the stored value is a single-digit number, blink the LED that
number
if (val > '0' && val <= '9' ) {
val = val - '0'; // convert from character to number
for(int i=0; i<val; i++) {
Serial.println("blink!");
digitalWrite(ledPin,HIGH);
delay(150);
digitalWrite(ledPin, LOW);
delay(150);
}
}
}



11.7.12. s12SwitchCase
http://arduino.cc/en/Tutorial/SwitchCase




/*
Switch statement

Demonstrates the use of a switch statement. The switch
statement allows you to choose from among a set of discrete values
of a variable. It's like a series of if statements.

To see this sketch in action, but the board and sensor in a well-lit
room, open the serial monitor, and and move your hand gradually
down over the sensor.

The circuit:
* photoresistor from analog in 0 to +5V
* 10K resistor from analog in 0 to ground

created 1 Jul 2009
modified 9 Apr 2012
by Tom Igoe

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/SwitchCase
*/

// these constants won't change. They are the
// lowest and highest readings you get from your sensor:
const int sensorMin = 0; // sensor minimum, discovered through
experiment

const int sensorMax = 600; // sensor maximum, discovered through
experiment

void setup() {
// initialize serial communication:
Serial.begin(9600);
}

void loop() {
// read the sensor:
int sensorReading = analogRead(A0);
// map the sensor range to a range of four options:
int range = map(sensorReading, sensorMin, sensorMax, 0, 3);

// do something different depending on the
// range value:
switch (range) {
case 0: // your hand is on the sensor
Serial.println("dark");
break;
case 1: // your hand is close to the sensor
Serial.println("dim");
break;
case 2: // your hand is a few inches from the sensor
Serial.println("medium");
break;
case 3: // your hand is nowhere near the sensor
Serial.println("bright");
break;
}
delay(1); // delay in between reads for stability
}




11.7.13. s13 Switch statement with serial input
http://arduino.cc/en/Tutorial/SwitchCase2



/*
Switch statement with serial input

Demonstrates the use of a switch statement. The switch
statement allows you to choose from among a set of discrete values
of a variable. It's like a series of if statements.

To see this sketch in action, open the Serial monitor and send any
character.
The characters a, b, c, d, and e, will turn on LEDs. Any other character
will turn
the LEDs off.

The circuit:
* 5 LEDs attached to digital pins 2 through 6 through 220-ohm resistors

created 1 Jul 2009
by Tom Igoe

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/SwitchCase2
*/

void setup() {
// initialize serial communication:
Serial.begin(9600);
// initialize the LED pins:
for (int thisPin = 2; thisPin < 7; thisPin++) {

pinMode(thisPin, OUTPUT);
}
}

void loop() {
// read the sensor:
if (Serial.available() > 0) {
int inByte = Serial.read();
// do something different depending on the character received.
// The switch statement expects single number values for each case;
// in this exmaple, though, you're using single quotes to tell
// the controller to get the ASCII value for the character. For
// example 'a' = 97, 'b' = 98, and so forth:

switch (inByte) {
case 'a':
digitalWrite(2, HIGH);
break;
case 'b':
digitalWrite(3, HIGH);
break;
case 'c':
digitalWrite(4, HIGH);
break;
case 'd':
digitalWrite(5, HIGH);
break;
case 'e':
digitalWrite(6, HIGH);
break;
default:
// turn all the LEDs off:
for (int thisPin = 2; thisPin < 7; thisPin++) {
digitalWrite(thisPin, LOW);
}
}
}
}






C:\Users\REMUS\Matco C My Documents\87gSM Sisteme cu microprocesoare 2011-
2012\university john hopkins Ferguson D\picopowerlabs\TempDirforGcc trening/Getting
started with GCC and AVRstudio

Getting started with GCC and AVR Studio





11.8. AVR tools

11.8.1. Avr_head





11.8.2. Avr fuses

http://www.engbedded.com/fusecalc














http://code.google.com/p/arduino/wiki/Platforms
uno.name=Arduino Uno
uno.upload.protocol=arduino
uno.upload.maximum_size=32256
uno.upload.speed=115200
uno.bootloader.low_fuses=0xff
uno.bootloader.high_fuses=0xde
uno.bootloader.extended_fuses=0x05
uno.bootloader.path=optiboot
uno.bootloader.file=optiboot_atmega328.hex
uno.bootloader.unlock_bits=0x3F
uno.bootloader.lock_bits=0x0F
uno.build.mcu=atmega328p
uno.build.f_cpu=16000000L
uno.build.core=arduino
uno.build.variant=standard

Here are the default fuse settings for each Arduino from the boards.txt included with the
Arduino development software.
To understand more about the fuse settings for your microcontroller, visit Engbeddeds AVR
Fuse Calculator
.
Arduino uno
Low Fuse

0xFF
High Fuse 0xDE
Extended Fuse 005






11.8.3. AVRstudio 4.18 tool chain

Tool chain bazat pe WinAVR in versiunea AVRstudio 4.18














11.8.4. Atmel Studio 6.2



AVR Studio 4.18 / Tool Chain WinAVR (GCC C/C++ compiler, biblioteca avr libc, programatorul avrdude)
AVR Studio 4.19 / Tool Chain Atmel
Atmel Studio 5.1
Atmel Studio 6.2 /AVR & ARM mC / GCC C/C++, CV Wizard, ASF Wizard









http://asf.atmel.com/docs/latest/architecture.html

11.8.5. ASF Introduction
The intention of ASF is to provide a rich set of proven drivers and code modules developed
by Atmel experts to reduce customer design-time. It simplifies the usage of microcontrollers,
providing an abstraction to the hardware and high-value middlewares.
ASF is a free and open-source code library designed to be used for evaluation, prototyping,
design and production phases.


ASF is code-size-optimized:
Multiple ANSI-C compilers supported.
Architecture-optimized by Atmel experts.

ASF is performance-optimized:
DMA for communication.
Interrupt-driven drivers.
Chip-specific features in stacks.

ASF is low-power-optimized:
Clock masking API, Sleep management API.
Support for hardware SleepWalking Event controller.
Dynamic frequency and voltage scaling.




11.8.6. ASF Architecture


ASF consists of source code modules and applications demonstrating the use of these.
Drivers is composed of a driver.c and driver.h file that provides low level register
interface functions to access a peripheral or device specific feature. The services and
components will interface the drivers.
Services is a module type which provides more application oriented software such as
a USB classes, FAT file system, architecture optimized DSP library, graphical library,
etc.
Components is a module type which provides software drivers to access external
hardware components such as memory (e.g. Atmel DataFlash, SDRAM, SRAM,
and NAND flash), displays, sensors, wireless, etc.
Boards contains mapping of all digital and analog peripheral to each I/O pin of
Atmel's development kits.





11.8.7. Structura modulelor ASF (Atmel Software Framework)








11.8.8. JTAGICE, STK500 si Pololu












11.8.9. Arduino bootloader







https://learn.sparkfun.com/tutorials/installing-an-arduino-bootloader/all

The bootloader is basically a .hex file that runs when you turn on the board. It is very similar
to the BIOS that runs on your PC. It does two things. First, it looks around to see if the
computer is trying to program it. If it is, it grabs the program from the computer and uploads
it into the ICs memory (in a specific location so as not to overwrite the bootloader). That is
why when you try to upload code, the Arduino IDE resets the chip. This basically turns the
IC off and back on again so the bootloader can start running again. If the computer isnt
trying to upload code, it tells the chip to run the code thats already stored in memory. Once it
locates and runs your program, the Arduino continuously loops through the program and does
so as long as the board has power



Here we have the Arduino Uno R3. It has two ICSP headers: one for the ATmega16U2 and
one for the ATmega328. To reflash the bootloader on this board, you would use just the ICSP
header for the ATmega328.






Heres a table to help clarify which connections go where.
Arduino as ISP AVR Programmer ISP Header ATmega328 ATmega32U4
Vcc/5V 5V Pin 2 Vcc Vcc
GND GND Pin 6 GND GND
MOSI/D11 MOSI Pin 4 D11 D16
MISO/D12 MISO Pin 1 D12 D14
SCK/D13 SCK Pin 3 D13 D15
D10 Reset Pin 5 Reset Reset







If you are using a programmer such as the MKII or the Pocket Programmer, your setup
should look something like this:











11.9. AVRstudio4 si CodeVisionAVR



11.2 Mediul de dezvoltare integrat CodeVisionAVR cu prima parte a sablonului generat
automat





Fig. 11.3 Ultima parte a sablonului generat automat






Fig. 11.4


Fig. 11.5




Fig. 11.6







Fig. 11.7


Fig. 11.8



Fig. 11.9





Fig. 11.10





Fig. 11.11





Fig. 11.12





Fig. 11.13







Fig. 11.14





Fig. 11.15 Mediul de dezvoltare CodeVision dupa includerea in proiect si program a
fisierului DELAY.H
Code Navigator/Other Files/Click dreapta/Open director in care se gaseste fisierul si
in program se introduce #include <DELAY.H>
Dupa compilare apare proiectul de mai sus





11.10. Proiectarea SW cu WinAVR, AVRstudio4.18 si placa Arduino UNO
Extras comentat de la siteul:
http://hekilledmywire.wordpress.com/2010/12/04/22/

11.10.1. Sablonul de pornire, exemplu blinkAVRstudio4

Now we can just start writing down our code, but first lets do it using pseudo-code:
1
2
3
4
5
Infinite loop
Turn led on
wait 500ms
turn led off
wait 500ms
Pretty simple hey?
Now lets start to turn this into real code.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <avr/io.h> //This contains definitions for all the registers
locations and some other things, must always be included
#define F_CPU 16000000UL //F_CPU tells the compiler that our crystal
is an 16Mhz one so it can generate an accurate delay, must be declared
above delay so delay knows what is the value of F_CPU
#include <util/delay.h> //Contains some delay functions that will
generate accurate delays of ms and us

int main(void){ //In ANSI C, the main function as always an
int return and using void will give you an warning
while(1){ //This gives us an infinite loop, there should
always be an infinite loop in your code, because micro-controllers cant
return from main to anywhere and that will give you bad results and
unpredicted behaviour
PORTB |= (1<<PB5); //Turn led on, this is the led included in the
arduino(digital pin 13)
_delay_ms(1000); //Wait 1 second
PORTB &= ~(1<<PB5); //Turn led off
_delay_ms(1000); //Wait another second
}
return 1;
}

You can see in this image how to map the pins nomenclature used by arduino to real port
names/values using this image:

There is yet one thing to do, can you see whats missing in the code?
Well, we need to tell to our avr if the pin is an output or an input, using direct port access and
the like, this is done using DDRx, where x is the port name(A,B,C or more if you have avrs
with many legs), in our case and as seen above we are using PORTB pin number 5, so the
code will be:
1
DDRB |= (1<<PB5);
And our final code will be something just like this:
#blink, Sorin Larionescu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <avr/io.h> //This contains definitions for all the registers
locations and some other things, must always be included
#define F_CPU 16000000UL //F_CPU tells the compiler that our crystal
is an 16Mhz one so it can generate an accurate delay, must be declared
above delay so delay knows what is the value of F_CPU
#include <util/delay.h> //Contains some delay functions that will
generate accurate delays of ms and us

int main(void){ //In ANSI C, the main function as always an
int return and using void will give you an warning
DDRB |= (1<<PB5); //Define digital pin13/PORTB5 as an output so we
can blink our led
while(1){ //This gives us an infinite loop, there should
always be an infinite loop in your code, because micro-controllers cant
return from main to anywhere and that will give you bad results and
unpredicted behaviour
PORTB |= (1<<PB5); //Turn led on, this is the led included in the
arduino(digital pin 13)
_delay_ms(1000); //Wait 1 second
PORTB &= ~(1<<PB5); //Turn led off

_delay_ms(1000); //Wait another second
}
return 1;
}
Now you can just type in or copy and paste this code inside the AvrStudio text editor and
press F7 that is the button that compiles/builds your code, this should compile without any
error or warning, and as you can see in the bottom of the IDE this blinky only uses 172bytes
of Flash memory, a lot less than the blinky generated by the arduino IDE.

Next will be about bitwise operators, so the |=, &=, << and other operators will soon be
explained in great detail as they are very handy when you are making some embedded
programming




11.10.2. Operatii logice si matematice orientate spre bit

Lets start, first I will show what is the correspondent operator for each logic function:
1
2
3
4
5
6
AND &
OR |
NOT ~
XOR ^
Shift left <<
Shift right >>
To help us understand what each logic operator does, there are some little things called truth
tables, those are tables/arrays that have all the possible input combinations for each logic
operator and the result that each combination produces, to simplify the truth tables they are
always shown with only 1 bit input parameters, because for the logic operator it doesnt
matter if we are dealing with 1bit or with 128bits.
But wait, what is all that bitwise here, bitwise there?!
Bitwise means that we are performing operations to lets say a 8bits variable like a char or an
uint8_t and working bit by bit, after this tables are shown I think that you will understand this
a bit better, if not, just leave a comment ;)
Here are the truth tables for all the logic operator that I will talk about today:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Truth table for AND:
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

Truth table for OR:
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1

Truth table for XOR:
0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0

Truth table for NOT:
NOT 0 = 1
NOT 1 = 0

Truth table for Shift left using an 8 bits variable:
0x01<<0 = 0b00000001
0x01<<1 = 0b00000010
0x01<<2 = 0b00000100
0x01<<3 = 0b00001000
0x01<<4 = 0b00010000
0x01<<5 = 0b00100000

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
0x01<<6 = 0b01000000
0x01<<7 = 0b10000000

Truth table for Shift left using an 8 bits variable:
0x80>>0 = 0b10000000
0x80>>1 = 0b01000000
0x80>>2 = 0b00100000
0x80>>3 = 0b00010000
0x80>>4 = 0b00001000
0x80>>5 = 0b00000100
0x80>>6 = 0b00000010
0x80>>7 = 0b00000001

Table with decimal, binary and hexadecimal conversion:
Binary Hexadecimal Decimal
0000 = 0 = 0
0001 = 1 = 1
0010 = 2 = 2
0011 = 3 = 3
0100 = 4 = 4
0101 = 5 = 5
0110 = 6 = 6
0111 = 7 = 7
1000 = 8 = 8
1001 = 9 = 9
1010 = A = 10
1011 = B = 11
1100 = C = 12
1101 = D = 13
1110 = E = 14
1111 = F = 15
Bit numbering of an 8bits variable:
0b00000000
...||||||||
...|||||||bit0
...||||||bit1
...|||||bit2
...||||bit3
...|||bit4
...||bit5
...|bit6
...bit7
Please note that the shift left and shift right truth tables where done using only two different
values, but you can use this logic operators with what ever value you want, but I will talk

about this two operator a little more ahead with more depth.
There is a lot of doubts when dealing with binary and hexadecimal number and how to
convert between those numbering bases and decimal, so I will show you how to convert a
simple 8bits variable from binary to hexa and from that to decimal.
Lets say that you have this 0b10101001, first you remove the 0b part because thats there
only to say to the compiler that that number is in a binary representation, then you split the
8bits in two pairs of 4bits each, so now you have 1010 and 1001, now using the table that I
provided you can see that 1010 in hexadecimal is A and 1001 is 9, so the result is 0xA9,
again the 0x part is a indicator to the compiler(and people) that this is a hexadecimal
represented number, now its much easier to convert to decimal, and 0xA9 is 10 (10 is the A
in decimal) plus 9, so 010101001 is equal to 0xA9 which is equal to 19, with a bit of
practice you will memory all this and its great if you want to make some patterns with leds,
or led matrices, or led cubes, and a lot other things!
If you look with some care to the above tables, you can see that there are some similarities
between the logic operators and the basic maths operators, and in fact you can use this little
idea that I used to distinguish/memorize this operators when I learn about then. The AND is
like a multiplication, its not the same as the * operator, because it does it work for each
individual bit and not for a full variable at once, the OR is like an addition, and the XOR is
like a simple difference detector, because its 1 when its inputs are different and 0 when its
inputs are equal, the shift left works as a real multiplier but it can only multiply in powers of
2(this means that we can multiply by 2,4,8,16,32,64,128,256, etc), because its a logic
operator, and shift right works as a divisor, again it only divides in powers of 2 and only
returns the integer part of a division.
Lets dive a bit more into this bitwise world, now with a more practical side.
In a micro-controller its usual that we need to configure peripherals, and those have registers
where we either set or clear bits to enable or disable certain functions of the said peripheral,
or to turn an led on or off, so first here is what we can do using the OR function, lets say that
we want to set bit 0 of PORTB without affect the other bits that might be set or clear:
1
PORTB = PORTB | 0x01;
Or in a more compact way that does exactly the same, the |= is called a compound operator,
its a faster way of writing the same that is done above but its shorter, the generated assembly
code is the same, but we dont need to type so much, use whatever you like more:
1
2
3
4
5
6
7
8
PORTB |= 0x01;
[/sourcode]

Now lets say that we want to clear the bit 0 that we have just set, for
that we need two logic operator, the AND and the NOT:
1
PORTB = PORTB & ~0x01;
//or the short version
PORTB &= ~0x01;
This one is a little bit more complex to understand so I will show you why do we need the
NOT to clear a bit:
1 //0x01 in binary is 0b00000001

2
3
4
5
//if we AND this value with the PORTB value it would clear all the bits
and only mantain the original value in bit 0
//So we negate the 0x01 first
// NOT 0x01 is NOT 0b00000001 that is 0b11111110
//Now doing the AND of this will give us the desired result of clearing
only the first bit and maintaining all the other bits unchanged
Another use for the AND operator is to detect if a bit is 1 or 0 for example in an if()
statement, lets imagine that we have a switch wired in PORTB 3 and we want to detect that:
1
2
3
if(PORTB & (1<<PB3)){
//do some stuff
}
Be aware that the result of PORTB & (1<<PB3) is either 0 or different from 0 and not 0 or 1,
in fact the result is 0 or 008(0b00001000 in binary or 8 in decimal) if you dont use any ==
with this statement with will work perfectly but if you do ==1 it will not work because the
result will never be 1 it is only either 0 or 008.
Now lets talk about XOR, its not a very common operator and its use might seem limited, but
its great to toggle output pins in a very fast and clean way, you want to toggle a led each
second for example you could use those usual if() chains were the current state is tested and
then changed for the contrary state, using XOR you do that in only one line and way faster
than using the if() chains or ever worse, case: chains, or even more stranger ways of doing
what is so simple.
Lets toggle for example the PB5 led included in the Arduino board:
1
2
3
PORTB = PORTB ^ (1<<PB5);
//And the short way
PORTB ^= (1<<PB5);
It is really easy and the code is much cleaner, it like XOR a lot!
You might have already heard about bit masks, but what are they and what are they purpose?
A bit masks is a variable that is used with the logic operators, I have been using then in this
tutorial, for example (1<<PB5) is a bit-mask that is useful in the XOR example to toggle the
value of PORTB5, those masks might be like this one, simple about what they do, but you
might have programs that are more complex, and imagine that you use PORTB0,1,2,3 as
inputs and PORTB4 and 5 as outputs, you could write
(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3) every time you wanted to check if all the inputs
where high or low, or you could define a bit-mask in the begin of your program and just use
that instead of writing that small train of letter and symbols every-time.
1
2
3
4
5
6
7
#define MASK (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)
//This define is together with all the other
//includes in the begin of your program

if(PORTB & MASK){
//do some stuff when all your inputs are high
}

They are handy and the name that you give them will probably make more sense that just
seeing that train of letters.
Finally lets head over the shift left/right operators, Im already using them, the << is the shift
left and is very handy to set bits when dealing with the digital PORTS and registers, the
PB0,1,2,3 are just defined values in the <avr/io.h> that have the 0,1,2,3 decimal values, they
are just small wrappers that show us in a visual manner with port and pin we are dealing with,
so as you can this operators are useful when setting bit-masks, lets say that you want to set
bit7 of some variable or a bit-mask, using a shift left its easy to do, and because the values are
know at compile time this values will all be calculated by the compiler and not in our micro-
controller at run-time:
1
2
3
#define myMask (1<<7)
//latter in the program
myVar |= myMask;
And how about multiplying and dividing with the shift operator?
Lets start with the shift left operator that let us do multiplications by powers of 2, for
example:
1
2
3
4
2<<1 = 4 //But how?
//2 in binary is 0b00000010
0b00000010 << 1 is 0b00000100
0b00000100 in decimal is 4
The value was shifted to the left one position and doing that it was multiplied by 2, the sift
left is the same as multiplying by 2^n where n is the amount of shifts applied to the original
variable, always keep in mind that when using an 8 bits variable and doing <<8 will return
you an empty variable because the shift inserts 0s when shifting the original value, and well
putting eight 0s in an 8 bits variable leaves it clean.
Another heads-up when using an 8bits variable every bit shifted after the bit7 is lost, this is
called an overflow, to prevent that when using the shift operator you can use an int/uint16_t
or an even bigger uint32_t.
The divide is done using the shift right and works exactly in the same way as the shift right,
but instead of multiplying you are dividing by 2^n, and with an added limitation, this operator
only allows us to do integer divisions, the fractional part of the result is lost, for example 7/2
is 3.5, lets see what is the output of using the shift right:
1
2
3
7 in binary is 0b00000111
0b00000111 >> 1 = 0b00000011
0b00000011 in decimal is 3
Our fractional part was lost, because any bit shifted beyond bit0 is lost because our 8 bits
variable cant old it, in fact not even a bigger variable will ever give us back the lost fractional
part, but integer divisions are also widely used and using right shifts is a major speed-up than
using an division routine, of course it only works when you are dividing in powers of 2.



11.10.3. Operatii I/O

Our micro-controller, the Atmega328p has registers, those registers are associated with the
input/output ports, each port as a specific name and the associated registers, in fact our
atmega as port B,C and D, and each port as a different number of pins(this is a restriction of
the 28 pins PDIP package and not from the micro-controller, because an 40 pins PDIP for
example has 4 ports with the full 8 bits each one), the only port that has the full 8 input/output
pins is PORTD.
As you may already know, each pin can have multiple functions, like pwm generation, or
ADC capabilities, the pins 7 and 7 from PORTB are also the input pins for the crystal
oscillator, and pin 6 from PORTC is the reset button.
In this image you can see all the alternative functions that each pin can have, the chip in
question is the Atmega328p.
And here is the mapping between arduino port names and their real name:


So, how can we interact with our digital pins?
Well, to begin there is a dedicated register for each PORT that defines if each pin is a input or
an output, that register is the DDRx, where x is the letter from the PORT that we want to
configure, in the case of the Arduino there is DDRB, DDRC and DDRD. As every logic
value, each bit in the DDRx registers can be either 1 or 0, being that putting a specific bit of
DDRx at 1 configures the pin as output and putting it at 0 will configure the pin as an input,
lets see a small example that configures pins 0,1,2,3 as digital inputs and pins 4,5,6,7 as
digital outputs:
1 DDRD = 0b11110000;
And all pins as outputs:
1
DDRD = 0b11111111;
And if you need all outputs? Try it yourself, or wait a few days and I will release my bit-
manipulation tutorial.
There should be some care when using PORTD and Serial/USART because pins 0 and 1
from the PORTD are the ones used by the USART and if you put both of them as inputs or
outputs the USART may be unable to read or write data in those pins.
We can already say to the Atmega how the pins should be handled, but we want to know how
to read an write data to those said pins, so to write data to a given port, we use the PORTx
register, this one is easy to remember, where x is the port name, after configuration a pin as
an output its just a matter of putting 0 or 1 in the PORTx register to drive that pin low or high
respectively, lets see some code for it:
1 DDRD = 0b11111111; //All pins in PORTD are outputs

2
PORTD = 0b11111111; //All pins in PORTD are high

1
2
DDRD = 0b11111111; //All pins in PORTD are outputs
PORTD = 0b00000000; //All pins in PORTD are low
And how about a pattern of on,off,on,..?
1
2
DDRD = 0b11111111; //All pins in PORTD are outputs
PORTD = 0b10101010; //The small on,off,on,.. pattern
Now, the only thing left is how to read on pin so we can read data from sensors or even the
mighty push-button, to read the state of a digital pin configured as input, we will used a third
register called PINx, where again x is the port name of where the pin is located, so first using
DDRx we say to the micro-controller that we want some pins as digital inputs, then using
PINx we read their values, seems easy right, so lets dig into the code:
1
2
3
DDRD = 0b00000000; //All pins in PORTD are inputs
char my_var = 0; //Create a variable to store the data read from PORTD
my_var = PIND; //Read the PORTD and put the values in the variable
Its as easy as it can be, and when compared with the Arduino digitalWrite and Read
functions, using direct port access you save space in flash and also win a lot of speed,
because the Arduino functions can take more than 40 clock cycles to read or write a single bit
in a port and the same time to read another single bit, and the code is pretty complex with a
load of lines that occupy at least some 40 bytes, it might be a small save in flash but its a
huge steep to speed up any program, but they are easy to use by the people that dont
understand a lot about programming/micro-controllers, so every implementation as its
advantages and drawbacks, but lets continue.
Its a bit uncommon that you need to read or write a full port at each time, for example if you
want to light a led, or to read a button we only need to use one pin, and writing all those bits
one by one every time that we want to change a value in a PORT is a boring task, but the
AVR lib-c as some little nice defined Px0..7 words where x is again the port that we want
to use and 0..7 is the value of the individual pin of the said port, so to light a led we would do
something like this:
1
2
DDRD = (1<<PD2); //Pin 2 of portd is an output
PORTD = (1<<PD2); //Pin 2 of portd as now the logic value 1
Or reading a button value:
1
2
3
DDRD = 0b11111101; //Pin 1 of PORTD is an input, all others are
outputs
char my_var = 0; //Create a variable to store the data read from
PORTD
my_var = (PIND & (1<<PD1)); //Read the PORTD pin 1 value and put it in
the variable

We can also use this Px0..7 thing multiple times in a statement, for example in this piece of
code, there will be some code executed only if two buttons are pressed at the same time:
1
2
3
4
DDRD = 0b11111100; //Portd pins 0 and 1 are inputs, all the others
are outputs
if(PIND & ((1<<PD0) | (1<<PD1))){
//Code inside the if() statement will be executed when both buttons are
high
}
I think that you are getting the point, but the bit manipulation tutorial will help a bit about this
subjects
There is yet some more things that we can do with our input and output pins/ports that is very
useful for i2c interfaces, and for example to use buttons, Im talking about the pull-ups that
our micro-controller and inside it and I will show you how you can enable them and why
should you use them when using push-buttons.
When you have a push-button it can have two states, one is disconnected, and when you push
it it will make the connection between the micro-controller pin and lets say, ground, but when
it is disconnected there is nothing forcing a stable value in the input pin, to the untrained eye
we could assume that the pin will be reading 1, because when we press the button it read 0,
but the fact is that the pin can read either 1s or 0s because the pin is very sensitive to electro-
magnetic noise, much like a little antenna, so we can solve this problem in two similar ways,
one is to attach a resistor of 10Kohms or more between the Vcc(+5v) and the input pin, or
just save some pennies and use the integrated pull-ups that our micro-controller as to offer, it
also makes our circuits a bit simpler and thats also a good thing.
To enable the pull-ups we need to do something that may seem a bit strange at the first
look,because there is no dedicated register to enable or disable the pull-ups, their are enabled
or disabled writing respectively 1 or 0 to the PORTx register when the DDRx register is
configured as inputs, lets see some code to clarify this:
1
2
3
4
DDRD = 0b00000000; //All pins in PORTD are inputs
PORTD = 0b00001111; //Pull-ups enabled in the pins 0,1,2 and 3 and
pull-ups disabled in pins 4,5,6 and 7
char my_var = 0; //Create a variable to store the data read from
PORTD
my_var = PIND; //Read the PORTD and put the values in the variable
If you execute this code with nothing attached to PORTD, the four high bits of the my_var
variable may have 1s or 0s or any possible combination of them because they are
floating(acting like little antennas), but the four lower bits will read all 1s because the pull-
ups impose a weak 5v signal that is read as a 1 logic value.
In a basic sense this is all you need to know to master the direct port manipulation but the bit
manipulation tutorial will teach you more things about nifty things like bitmasks, AND,OR,
NOT and XOR operations and how to set and clearer bits in a register and some nice tricks
about the shift left and shift right operations, all good things to know as they can speed up
your program and are handy when using the digital ports.
Lets now make a small test program that will take use of the digital inputs and outputs and
also the pull-ups, because this has been a very theoretical tutorial its nice to come to the end

and blink some leds!
This is the pseudo-code for our program, its intent is to read a switch and every-time that the
switch is read it will toggle a led, so you press ounce and the led lights up, press again and the
led goes off, and again from the start, this could be done using some ifs conditions but can
be done in a single line using the powerful XOR(^) operator.
1
2
3
4
5
6
7
8
Main{
Configure the pins, in this example code, I will use PORTD
Infinite loop{
Read button value
If led is on and button==1 turn led off
If led is off and button==1 turn led on
}
}
Just one more thing(I know Im always going a bit off-topic, but this one is important) when
we use a button wired to a digital input we must be aware that a push-button doesnt give a
nice and clean transition from 0 to 1 of from 1 to 0, but instead the signal as some ringing and
bouncing, this is due to the mechanical proprieties of the button and not a design flaw, the
button as small metallic reed inside, and when we press it the reed closes and close the circuit
between its input and output but this reed will oscillate a bit until it rests firmly in its stop, so
we must take care of this, and as usual there are two ways, using a small capacitor near the
button to debounce the value, or make this very same debouncing in code, which is easier to
do when we have a lot of buttons and again is cheaper than adding a lot of caps to our circuit.
If you google the terms button debouncing you will find a great variety of ways to debounce
buttons in code, the way that I will use here is the simplest of all, its just a small delay
inserted between consecutive reads of the button, this is of course a blocking method because
our micro-controller will just stop and sit there delaying for some miliseconds, there are
smarter ways that use timers and other smart tricks but for 2-3 buttons and projects that dont
need super precise timing this is a commonly used method.
To do this delay I will use the built-in delay routines provided by the AVR lib-c.
So lets start coding, all the code is straight forward if you understood everything that was
written above.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <avr/io.h> //This is our usual include
#define F_CPU 16000000UL //This says to the compiler at what frequency
our Atmega is running, in this case its 16Mhz
#include <util/delay.h> //The delay functions/routines

uint8_t readButton(void); //Declaration of the readButton function

int main(void){
DDRD &= ~(1<<PD2); //Configure PORTD pin 2 as an input
PORTD |= (1<<PD2); //Activate pull-ups in PORTD pin 2
DDRB |= (1<<PB5); //Configure PORTB pin 5 an output, this is the
digital 13 in the Arduino that as the built-in led

while(1){ //Infinite loop
if(readButton()==1){ //Verify the button state
PORTB ^=(1<<PB5); //This is the above mentioned XOR that toggles the
led

15
16
17
18
19
20
21
22
23
24
25
26
27
28
}
_delay_ms(250); //Delay between consecutive button presses
}
}

uint8_t readButton(void){
if((PIND & (1<<PD2)) == 0){ //If the button was pressed
_delay_ms(25); } //Debounce the read value
if((PIND & (1<<PD2)) == 0){ //Verify that the value is the same
that what was read
return 1; } //If it is still 0 its because we had a button
press
else{ //If the value is different the press is
invalid
return 0; }

}

Here is the code in an Avr Studio project ready to compile and upload:
http://code.google.com/p/avr-tutorials/downloads/detail?name=port.zip






11.10.4. Comunicatii seriale UART

USART(or UART in other avr models), give us the possibility to have a serial port, and that
is a pretty nice thing to have, because it can be used for example to upload programs to our
Arduino(via bootloader), to have a communication channel between our micro-controller and
our computer, or to talk to some sensors/chips, the most used ones are serial backpacks for
lcds and graphical lcds and GPS modules that use almost always an serial interface.
The serial protocol is a fairly old protocol created many years ago it was used by Teletypes
and terminals, its also a robust protocol(at least when we use the RS-232 standard that
involves +12v and -12v or more so its immune to noise and can cope with long transmission
lines), the serial protocol uses 2 wires, one to receive data and other to send data, and of
course you must have a shared ground between your arduino/micro-controller and the other
device. The serial interface sends the data in little blocks of one byte with one start bit and
one stop bit, the USART does all the job about the setting of the start and stop bits. The clock
signal of the serial protocol is implicit, this means that is is joined with the data stream and
there is no need to have a separate wire to transmit the clock from one device to another, we
only need to say to the USART which clock speed we want to use(this is the baud rate) and
again the USART module will do all the heavy lifting.
If you want to know a bit more about the RS-232 protocol read this Wikipedia page, its also
good to know a bit more about the protocol, but not mandatory:
http://en.wikipedia.org/wiki/RS-232
Also, its always good to have the datasheet of the atmega328p in hand as it as all the
information that we will need, link here:
http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf
And we can also create a small stub program, this will be our base program that we use every
time that we start a new project in AvrStudio, it as the basic includes and the main function:
1
2
3
4
5
6
7
8
9
#define F_CPU 16000000UL //Says to the compiler which is our clock frequency,
permits the delay functions to be very accurate
#include <avr/io.h> /General definitions of the registers values
#include <util/delay.h> //This is where the delay functions are located

int main(void){ //The begin of our main function
//This is where our code goes

return 0; //As usual all non-void functions must have a return
}
This is a little but handy stub and it also saves us the time to write is every time we start a
new project.

Now talking specifically about the USART module and how to create a program to use it. In
this tutorial instead of just putting all the code together in the main function I will instead
create some basic functions, so if you want to use serial comm in another project you just
have to copy the functions and call then where they are needed.
So, in pseudo-code this is what we need to do:
1
2
3
4
Start and setup of the USART
Create a function to send a byte/char
Create a function to receive a byte/char
Make a simple echo program in our main function
Now we know what we want to do, but how? Well we open the datasheet and we start to read
it, luckily the datasheet is ordered by chapters so we can jump to the USART chapter(page
177, section 19) and there we can see that there is even some sample code in C and assembly
so our work here is a bit easier than we though, so lets start with the initialization code:
1
2
3
4
5
6
7
void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01));
}
Lets explain what all those strange names mean, UBRR0H and UBRR0L are the registers
where we set the baudrate, but not directly, in this two registers we put a value that is
dependent of the baudrate that we want to use(for example 9600) and the cpu(crystal)
frequency, and to arrive to that value there are two ways, one is to read the tables provided by
the datasheet(in the USART section, near the end) or use the little formula that was used to
generate those values present in the datasheet, the last option is better, because we can just
use the #define directive and have the compiler do all the maths, and we can just change the
baudrate and re-compile the code, so we dont have to go read the datasheet everytime we
want to change the baudrate or if we use a different cristal with different frequency than the
16Mhz, so here is the formula:
1
2
#define BAUD 9600 //The baudrate that we want to use
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1) //The formula
that does all the required maths
Now about the UCSR0B is the register that control if the Rx(receive, this is the one activated
by the RXEN0 bit) and Tx(transmit/send, this is the one activated by the TXEN0 bit) pins(in
Arduino those are the digital 0 and 1) are activated or not, also this is where we can enable
the interrupts associated with the USART, but we will not use those for now. And the
UCSR0C is the register that as some more configuration bits, this one is a bit more protocol
specific, this is where we configure the data bits lenght, parity check and number of stop bits,
I have chosen the 8N1 settings because its the most common settings for serial comm, and the
meaning of the UCSZ00 and UCZS01 bits I leave to the reader as a simple exercise to motive
the reading of the datasheet.

To initialize our USART we just need to call the USART_init() function and its done(I said it
was easy). Lets see the code that we need to use to send one char from the Arduino, this code
is again provided by the datasheet, and here it is:
1
2
3
4
5
6
void USART_send( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}
The first line is a bit odd, but it as its reasons, that line is checking if there is space in the
Atmega send buffer(the atmega chip as a small 3 byte hardware buffer in the TX/send
channel) to put a new char/byte, if yes the char/byte is loaded into the UDR0 register which
makes part of the USART hardware and if something is loaded into that register it will be
sent by the USART, again this is very simple, with only 2 lines we can already send data
using the serial port!
And finally the function used to receive one char is also present in the datasheet and is again
a two lines solution:
1
2
3
4
5
6
unsigned char USART_receive(void){

while(!(UCSR0A & (1<<RXC0)));
return UDR0;

}
In the first line the while loop is used to pool the receive register, and if there is new data in
that register we return the data, as you can see its pretty simple. As an extra not shown in the
datasheet I will show how to send one string via the serial comm, this is a useful function
because there are plenty of situations where we need to send much more than one byte/char
so lets build an USART_putstring function to help us, this functions takes advantage of the
fact that in C every string is terminated with a null character, this means that the last char is
always 0, so using this and our USART_send function here is the USART_putstring function:
1
2
3
4
5
6
7
void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){ //Here we check if there is still more chars to send, this is done
checking the actual char and see if it is different from the null char
USART_send(*StringPtr); //Using the simple send function we send one char at a time
StringPtr++;} //We increment the pointer so we can read the next char

}
Now we have all the necessary functions to have a simple yet usable serial interface between
the Arduino and a computer or other sensor, so lets evolve to a more glorious Hello world!!
program, the only thing left is a Serial Terminal so we can see what the Arduino is saying and
we can also send it some commands, I recommend this simple to use Serial Terminal:
http://www.smileymicros.com/download/term20040714.zip?&MMN_position=42:42

As far as I know it is made by an AvrFreaks member and its easy to use and its only a single
file, no install required, just download and open.
Lets grab in our stub code and our functions and put then all together:
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
36
37
38
39
40

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

//Declaration of our functions
void USART_init(void);
unsigned char USART_receive(void);
void USART_send( unsigned char data);
void USART_putstring(char* StringPtr);

char String[]="Hello world!!"; //String[] is in fact an array but when we put the
text between the " " symbols the compiler threats it as a String and automatically
puts the null termination character in the end of the text

int main(void){
USART_init(); //Call the USART initialization code

while(1){ //Infinite loop
USART_putstring(String); //Pass the string to the USART_putstring function and
sends it over the serial
_delay_ms(5000); //Delay for 5 seconds so it will re-send the string every 5
seconds
}

return 0;
}

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

unsigned char USART_receive(void){

while(!(UCSR0A & (1<<RXC0)));
return UDR0;

}

void USART_send( unsigned char data){


while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}

}
And thats it, using this we can send data via the USART/serial port, so lets open AvrStudio
and create a new project called USART.
Then in the next window we can verify that the project will be created inside our AVR folder,
so just fill the Project Name with USART and font forget to choose the Avr-gcc as the
compiler.


After pressing Next choose your Avr model, for the Arduino UNO/duemilanove its
Atmega328p.


And finally press Finish and copy and paste the code given here to the editor, and to compile
you can press F7 or click in the button marked in green in this image:

As you can see this code will compile with any errors or warnings and we can upload the
program to the Arduino board, that as the code compiled and ready to be programmed in the
And here is the code ready to open in Avr Studio 4, hosted by the great Google Code:
http://code.google.com/p/avr-tutorials/downloads/detail?name=serial.zip




11.10.5. Timers

Timers are super useful and usually they give a lot of headaches to the newbies and the not so
newbie user. Timers are used to count time, and can be used to generate precise delays, make
a stable heart-beat to our application or can be used to generate pwm signals, all handy
stuff that we can use.
Timers have the advantage of being implemented in hardware so they can run asynchronous
from our code, this is like a very simplified multi-tasking, but permits us to off-load some
work from the processor to the timers hardware, the Atmega328p present in the Arduino as 3
timers, timer 0, timer 1 and timer 2, they have a fundamental difference between them, timer
0 and timer 2 are 8 bits timers, this means that they can count up to 255, instead timer 1 is a
16 bits timer and can count up to 65535. Timers are also very complex and have lots of
registers that can be configured in many ways so when using them its mandatory to open the
datasheet.
The clock source of the timers is always tied to the frequency that our AVR runs, in the
Arduino case they have a base frequency of 16Mhz, but we can use prescalers (a piece of
hardware that can divide the source clock), and in the case of the timers this prescaler can be
either 1, 8, 64, 256 or 1024. Having this wide range of prescallers permits us to have a ratter
big range of frequencies and thats always a good thing to ear.
The timers have different operating modes, the 4 major ones are phase correct PWM, fast
PWM, CTC(Clear Timer on Compare Match) and normal mode, that is well acting as a
simple counter, then depending if we are using 8 or 16 bits timer there are sub-modes but
they all do the same, but in different ways. All timers have associated with them three
registers, TOP, BOTTOM and MAX that can be used for example to change the frequency
when in PWM mode, but I will talk about that latter. TOP defines the maximum value that
the timer can count, it can be either the maximum value or other user defined value, varies
with the selected mode, BOTTOM is the minimum value and its always 0(zero), we can
change BOTTOM instead of TOP but that as some limitations so we just leave BOTTOM
untouched, and MAX is always the maximum value that a timer can count to, in the 16 bits
timer its 65535 and in the 8bits timers its 255.
I will divide this tutorial in two parts, in this first part I will talk about the normal and the
CTC modes, and in the second part I will aboard the PWM modes and how to control some
leds and servos with it.
Lets dive into the normal and CTC modes then, so lets do something simple and easy like
another blinky but this time we will use the timers and not any sort of software delays like
_delay_ms(), as we are using timers, we need to do some maths first to setup our timers so
they will count up to where we want. In this example I will not even use interrupts, I will just
poll the timer register and see when the desired elapsed time is meet and then just toggle the
led and do it all over again.
We will toggle the led at a rate of 2Hz, this means that the led will be on for 500ms and off
for another 500ms, as our system clock is 16Mhz, and the biggest timer that we have can only
count up to 65535 this means that we could only measure up to:

1
2
1/16Mhz = 0,0000000625s //This is our timer resolution
0,0000000625 * 65535 = 0,0040959375s, a little bit more than 4ms
As you can see the 16Mhz clock is too fast so we must use the prescalers to reduce the clock
that is feed to the timer, so lets do a little table to see what are the possible timer resolutions
when using all the available prescaler values:
1
2
3
4
5
6
7
8
9
10
Timer resolution = (Prescaler / Input frequency)
Prescaler values can be 1, 8, 64, 256 or 1024
And the input frequency is 16Mhz.

Prescaler valuer | Timer resolution
1 | 0,0000000625s = 62,5 nS
8 | 0,0000005s = 0,5uS
64 | 0,000004s = 4uS
256 | 0,000016s = 16us
1024 | 0,000064s = 64uS
So using prescalers we have a much larger choice of frequencies, now lets see what value do
we need to put in our timer to have an exact delay of 500ms(2Hz) to do our new blinky, to do
that we will use a little handy formula that can be easily derived from the datasheet:
1
2
3
4
5
6
7
8
9
10
11
Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)

Input frequency is 16Mhz
Target frequency is 2Hz

Prescaler value | Target timer count
1 | 7999999
8 | 999999
64 | 124999
256 | 31249
1024 | 7811,5
As the maximum value that the 16 bits timer can handle is 65535 the first three values can be
discarded as they will not fit in the 16bits register, also the last value is fractional so although
it can be used it will drift over timer and accumulate large errors, this leaves us with the forth
value that in conjunction with the 256 prescaler will give us a perfect 2hz delay, so lets start
with the pseudo-code to make this new timer based blinky!
1
2
3
4
5
6
7
8
9
10
#include <avr/io.h>

int main(void){

//Set led as output
//Configure timer

for(;;){
//Read timer value and act according with it
}

11
12
13

return 0;
}
As we are doing all the maths for a 16 bits timer, this means that we have to use
Timer/Counter 1 of the Atmega, all the information about this timer is in page 114 and
followings in the datasheet.
As I already said, one thing that we need to configure is to put our timer in normal mode,
then select the prescaler values and then turn the timer on.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <avr/io.h>

int main(void){

DDRB = (1<<PB5); //Set PB5 as output

//Configure timer
TCCR1B = (1<<CS12); //1:256 prescaler

for(;;){
//Read timer value and act according with it
if(TCNT1 >= 31249){ //Our pre-calculated timer count
PORTB ^= (1<<PB5); //Toggle the led state
TCNT1 = 0; //Reset the timer value
}
}

return 0;
}
And thats it, using a timer in normal mode is very very easy, all we need to do is to set up
the pre-calculated prescaler value that permits us to get the desired frequency and then we
just read the timer value until it gets up to our desired count, do what we want to do and reset
the timer to have a stable time base.
The prescalers value are set using the bits CS12, CS11 and CS10 in the TCCR1B register,
those are related to the prescaler values like this:
1
2
3
4
5
6
7
CS12 CS11 CS10 Prescaler
0 0 0 Timer off/no clock source
0 0 1 1:1 prescaler/this is the same as not having prescaler
0 1 0 1:8 prescaler
0 1 1 1:64 prescaler
1 0 0 1:256 prescaler
1 0 1 1:1024 prescaler
So, the desired prescaler was 256 so we only need to set the CS12 bit and leave the rest
untouched. As usual and because our micro-controller as an 8 bits architecture we cant really
read or write a 16 bits value like we are doing to read the actual timer value and to reset it, in
fact TCNT1 is not a real register, instead it is a short-cut that the AVR Lib-C provides us,
and when we read this register we are in fact reading the real TCNT1H and TCNT1L

registers, those are the high and low registers that form the 16 bit word that is the timer count,
its like the ADCW short-cut and is handy to write cleaner code.
Now I will explain how to use another way to use timers, in this way we will use interrupts
instead of constantly polling(reading) the timer count to decide what to do. Interrupts are a
nice capability of most micro-controllers. An interrupt is a signal that is generated for
example when our timer reaches the desired count and when the micro-controller gets that
signal it stops what it was doing, services the interrupt and then go back to what he was doing
before the interrupt, this can be saw as a multi-tasking behaviour, as our micro-controller can
execute a big and heavy main loop and then service interrupts to (for example) refresh an lcd
at a desired frame-rate or to do multiplexing of displays or leds, and mantain constant refresh
times, and many other uses.
The interrupt is served/attended in a special function called interrupt service routine, this
functions is not called by us coders in our code, but by signals generated inside the micro-
controller, so we just create the special function, configure the timer and our micro-controller
will handle the rest. There are some caveats about using interrupts that you should know right
now, one NEVER uses delays inside interrupts, interrupts are supposed to be fast and clean,
delaying inside an interrupt means that you are doing it in the wrong way, also, it is good
practice to not call functions inside interrupts, due to the overhead introduced by the called
functions, so remember, interrupts should be kept clean. If you want to have a complex
program that works say every 10ms, it is better set a flag in the interrupt service routine and
then use the flag in the main loop to know if the interrupt as already fired or not, and last but
not least EVERY variable that is shared between interrupts and any other functions must be
declared as volatile, for example:
1
2
int variable1 = 0; //This is not a volatile variable and should no be used as a shared
variable
volatile int variable2 = 0; //This is a volatile variable as you can see by the means of the
volatile keyword
To create an interrupt function there is also a special method to do them, they are declared
using a special keyword and they accept as argument the interrupt vector/name, the vector
names can be found in the section 11 of the manual, page 58, called Interrupts, to the
provided vector names in the table we need to add the _vect keyword and replace all the
spaces by _, let me show you how to do it, also interrupt service routines dont have any
return so if you need information back from an interrupt use a global variable declared as
volatile, or use pointers:
1
2
3
ISR(TIMER0_COMPA_vect){ //This is an interrupt service routine for the TIMER0
COMPA vector
//Put your code here
}
To finalize this crash-course about interrupts, you need to configure them, as usual, because
almost every peripheral of our micro-controller can generate interrupts, so, things like all the
3 timers, the ADC, the USART, the SPI interface, the I2C interface, external interrupts from
IO pins and some other things can all generate interruptions, and we also need to enable
global interrupts, this is like a switch in the micro-controller that says if we can service the
generated interrupts or not.

We will now use our timer in CTC mode, in this mode the timer counts up to a pre-
programmed value, and then it generates an interrupt, resets itself and starts again counting
from 0, all this is done in hardware so this frees up our micro to do more important tasks
than setting a timer back to 0 again. Again we will be doing the blinky program with the
same 2hz frequency as the one made using the timer in normal mode.
Lets start with the pseudo-code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <avr/io.h>

int main(void){

//Configure led pin
//Configure timer in CTC mode
//Enable global interrupts, so our interrupt service routine can be called
//Enable timer interrupts

for(;;){
//Our infinite loop, this will remain clean, everything is done in the interrupt
}

return 0;
}

ISR(){ //This is our interrupt service routine

//Toggle led state
}
As the led stuff is trivial, lets talk a bit more about how to put the timer in CTC mode, the
various modes of operation of the timer 1(and for reference, also timer 0 and timer 2 work in
this same way) are set by 4 bits, 2 in the TCCR1A and 2 in the TCCR1B register, this 3 bits,
called WGM13, WGM12, WGM11 and WGM10 define the mode of the timer and are
described in table 15.4 (waveform generation mode), in page 137 of the Atmega328P
datasheet, as we want CTC mode, we only need to set the WGM12 bit in the TCCR1B
register and them instead of comparing the desired count in the timer count register, we set
our desired count in one of the two compare registers of timer 1, this registers accept a 16 bits
value, and does the hardware compare with the actual timer count, and when they are equal
they call the interrupt and clear the timer count, as the TCNT1 register they can also be
accessed via 2 registers called OCR1AH and OCR1AL, OCR1BH and OCR1BL, or by the
handy OCR1A and OCR1B short-cuts.
We also need to enable timer interrupts, this is like a local switch that says to our micro-
controller if and which parts of our timer can generate interrupts, in this example we only
need to set one bit of this register, the OCIE1A, this bit says that we want interrupts when
there is a compare match with the value saved in the OCR1A register, and we set this bit in
the TIMSK1 (Timer1 Interrupt mask register) register.
Lets then put this information in the code:
1
2
3
#include <avr/io.h>

int main(void){

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

DDRB = (1<<PB5); //Configure led pin

//Configure timer in CTC mode
TCCR1B = (1<<WGM12)|(1<<CS12); //Enable CTC mode, and set prescaler to 1:256
//Enable timer interrupts

//Enable global interrupts, so our interrupt service routine can be called

for(;;){
//Our infinite loop, this will remain clean, everything is done in the interrupt
}

return 0;
}

ISR(){ //This is our interrupt service routine

PORTB ^= (1<<PB5); //Toggle led state
}
As we are using the CTC mode this means that we must put our desired count in the OCR1A
register, this is shown in the waveform generation mode table, and thus our interrupt service
routine will be the one related to this register, and is called TIMER1_COMPA_vect, COMPA
because its the OCR1A register.
To enable the interrupts we just need to call sei() or cli() to respectively enable interrupts(sei
means set interrupts) and disable interrupts(cli means clear interrupts), those are functions
that are defined in the interrupts library and thats why we need to include it, so lets complete
the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void){

DDRB = (1<<PB5); //Configure led pin

//Configure timer in CTC mode
TCCR1B = (1<<WGM12)|(1<<CS12); //Enable CTC mode, and set prescaler to 1:256
OCR1A = 31249; //sets the desired count to generate the 2Hz signal
TIMSK1 = (1<<OCIE1A); //Enable timer interrupts

sei(); //Enable global interrupts, so our interrupt service routine can be called

for(;;){
//Our infinite loop, this will remain clean, everything is done in the interrupt
}

return 0;

20
21
22
23
24
25
}

ISR(TIMER1_COMPA_vect){ //This is our interrupt service routine

PORTB ^= (1<<PB5); //Toggle led state
}
Now its just a matter of compiling the code, and to upload it to your board and see the led
blinking.
I will now show even another way to do our blinky by creating the useful milis functionality
provided by the Arduino, this is also a way to show how to use variables shared in the main
program and by an interrupt service routine, and also how to use another timer. I will use
timer 0 for this, because I want a 1 mili-second signal, this means a frequency of 1Khz so,
there is no need to waste the 16 bits timer when an 8 bits timer is enough to this job, so lets
calculate what will be our timer and count value.
1
2
3
4
5
6
7
8
9
10
11
Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)

Input frequency is 16Mhz
Target frequency is 1000Hz or 1Khz

Prescaler value | Target timer count
1 | 15999
8 | 1999
64 | 249
256 | 61,5
1024 | 14,625
As you can see only the 1:64 prescaler gives us an integer value, the 1:256 and 1:1024 both
gives us fractional values and those will accumulate errors with time, so its better to avoid
them, so lets use the 1:64 prescaler and use 249 as the compare value, we will again use the
timer in CTC mode, due to its clean work. So lets jump to the timer 0 section of the datasheet
and see how to put our timer in the CTC mode.
The 8 bit timer 0 section is number 14, and starts at page 98, from there we go to subsection 9
where all the registers are explained bit by bit (literally), and just like timer 1 there is also a
waveform generation table but this is one is much smaller, this is because well the timer is
also smaller, and again we only need to set one bit to enable CTC mode, in this case its the
WGM01 in the TCCR0A register, the prescaler will be set to 1:64 by setting both CS01 and
CS00 in the TCCR0B register, the desired compare count will be stored in OCR0A register,
and then we need to again enable compare match interrupts, but now its the OCIE0A bit that
needs to be set in the TIMSK0 register because we are working now with the timer 0, finally
the interrupt vector name is TIMER0_COMPA_vect, lets get all this together!
1
2
3
4
5
#include <avr/io.h>
#include <avr/interrupt.h>

void timer0_init(void); //Function prototype


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
volatile unsigned long milis = 0; //This is our shared volatile variable that will be used as
the milis count
unsigned long now = 0;

int main(void){

DDRB = (1<<PB5); //Set the pin as an output
timer0_init();

for(;;){
if(milis-now >= 500){
now = milis;
PORTB ^= (1<<PB5); //Toggle the led at every 500ms/0.5s/2hz
}
}
return 0;
}

void timer0_init(void){

TCCR0A = (1<<WGM01); //Timer in CTC mode
TCCR0B = ((1<<CS01)|(1<<CS00)); //1:64 prescaler
OCR0A = 249; //Value to have an compare at every 1ms
TIMSK0 = (1<<OCIE0A); //Enable timer interrupts
sei(); //Enable global interrupts
}

ISR(TIMER0_COMPA_vect){

milis++; //Increase milis count by one millisecond
}
This code is like the blinky without delay that you can find in the Arduino IDE, just done
bare-metal.
And you can download the Avr Studio project here:
http://code.google.com/p/avr-tutorials/downloads/detail?name=milis.zip





11.10.6. Convertorul analog numeric (ADC)

Hello dear readers, today I will write(a lot, this is a pretty long tutorial today) about the
internal ADC of our micro-controller, but first a little introduction to what is an ADC.
ADC stands for analogic to digital converter and permits us to convert analogic voltage levels
to a digital representation, this permits us to read things like the output of a potentiometer,
LDRs, temperature sensors(like the LM35), humidity sensors, accelerometers and
gyroscopes that have an analogic voltage output, pressure sensors and much more things.

Our atmega328p(and all of the atmega micro-controllers from atmel) has a built in analogic
to digital converter that is ready to use(some older micro-controllers like the 16F family from
Microchip and the BasicStamp they didnt have a built in ADC) and doesnt need any
additional hardware, this enables us to just connect an analogic sensor a pot for testing and
just do the software part and we are ready to go! The internal ADC of our micro-controller
has a resolution of 10 bits, this means that the input analogic voltage will be converted to a
numeric value between 0 and 1023.
Although the atmega328p has 6 pins that are capable of being used as analogic input pins,
there is only one ADC in the micro-controller, but between the ADC and the pins there is a
thing called analogic multiplexer, this permits us to choose which pin is connected to the
ADC, this means that although we can use all the pins we can only read the value of each one
at a time, for almost applications this is more than enough, but in some limited cases that
need high speed ADC readings we might need to use external ADCs, but for all our projects
the internal one is good enough. In the case of the atmega328p the pins that can be used an
analogic input are all the pins from PORT C.
As our chip is being feed with 5v we can plug any signal that we want to the ADC input pins
if the signal is inside the 0-5v range, above or below that and the ADC circuitry will be
damaged for ever and you might even destroy the whole chip. We can also change(given that
its always bellow the Vcc of the atmega chip) the maximum voltage that the ADC uses, for
that you can put your desired max voltage(its called the reference voltage and its against this
voltage that all analogic to digital conversions are done) in the Aref pin, that is pin 21 of the
DIP package and then configure the ADC in software to use that voltage reference, I will not
explain this in this tutorial, but if you have doubts just shoot a question.
Now you are thinking, why would I want to reduce the maximum voltage of my ADC? Well
this as a lot of uses, but lets explain some things first. Using the default reference voltage of
5v and this voltage is converted to a 10 bits value, the resolution of each bit is 5v/1023 =
4.88mV for each consecutive value, but imagine that you have an analogic accelerometer,
those are almost always 3.3v part, so if you used the 5v reference you would have 5 3.3 =
1.7v of unused values and also a reduced resolution, now lets see what is the resolution if you
used an 3.3v reference voltage 3.3/1023 = 3.22mV for each consecutive value, so its a gain in
resolution and you would be able to used the full range of the ADC.
The internal ADC can also be used in an 8bits mode, where only the most significant 8 bits of
the full 10bits resolution are used, this might be useful when working in noisy environments

and you only need 8 bits resolution, using this mode is a plus because you dont need to
spend extra time shifting the full 10 bits result into an 8 bits one. The ADC can also be
configured to do one conversion and stop or can be configured to work in a free running
mode, the first option is the best one when we want to read different pins, and the latter is
better when we only need to sample one pin this can save some time between conversions.
We also need to take care of the maximum working frequency of the ADC, this value is
specified in the data-sheet and its 200Khz, this is the value of the internal clock of the ADC
circuitry and is generated by dividing the main atmega clock, that in my/your case is 16Mhz,
this dividing of the clock is done using pre-scalers and unfortunately there is only a very
limited range of values for then so the maximum frequency that we can use and still be inside
the maximum working frequency is 125Khz, we can over-clock our ADC, but we will loose
precision, this means that if we exceed the maximum 200Khz the ADC is still fully function
that it will no longer guarantee its 10 bits precision, but I can guarantee that if you use the
next possible frequency that the atmega328p can offer when clocked at 16Mhz that is 250Khz
you still have at least 8 bits, maybe 9, much more than 250Khz and the returned converted
value is more and more useless and more and more filled with noise, my opinion, if you
really need a faster ADC just use an external one.
Lets start by doing a simple test program so we can see our ADC in action. For this our
atmega will read an 10Kohm pot connected to pin 0 of PORT C, that is the analogic 0 of the
Arduino board, and regarding the read value it will turn on or off the led that is connected in
pin 5 of PORT B (the digital 13 led).
The pot will be connected following this schematic:

Open AvrStudion and start a new project, call it adc, this will be our pseudo-code:
1
2
3
4
5
6
7
8
9
10
Configure led pin
Configure ADC
Turn on ADC
Start the ADC conversions

Infinite loop{
Read ADC value
If ADC value > 512 turn led on
Else turn led off
}



Lets start by setting up our led pin to be an output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <avr/io.h>

int main(void){

DDRB |= (1<<PB5); //PB5/digital 13 is an output

//Configure ADC
//Turn on ADC
//Start ADC convertions

for(;;){ //The infinite loop could also be while(1)
//Read ADC value
//If ADC value > 512 turn led on
//Else turn led off
}

return 0;
}
Until now there is nothing new, but now I will teach you how to set up the ADC, so lets grab
the datasheet and jump to Chapter 23, page 251, this is the ADC chapter and as the
description of every register and also about the ADC circuitry, so prepare yourself for another
wall of text!
First we need to provide a clock to the ADC, and as we have seen before this signal as a
maximum recommended value and this clock is generated by the prescalers, so lets first setup
our prescaler. This is configured in the ADCSRA register and the bits that are related to the
prescaler settings are ADPS2, ADPS1 and ADPS0, you can see in page 265 the possible
values for the prescaler are 2,4,8,16,32,64 and 128, as we are running at 16Mhz we will use
the 128 prescaler so our ADC clock will be of 125Khz, to set this value we need to set the
three ADPS bits to 1.
Now we will configure the voltage reference that our ADC will use, in this tutorial I will use
the voltage that is also used to power the rest of our Atmega(+5v), with a capacitor connected
to Aref(the Arduino board as the needed cap in the Aref pin), the reference voltage source is
configured in the ADMUX register with the REFS1 and REFS0 bits, this is in page 263, in
our case we will put REFS1 at 0 and REFS0 at 1, its also in the ADMUX register that we can
select which channel will be used to perform an analogic to digital conversion, this is selected
using the MUX3 to MUX0 bits, in this first example I will not touch this bits as we are
reading from channel 0 and all the bits in the registers are in the 0 state when we power up
our Atmega.
Now our ADC is almost setup, we just need to turn it on(because by default its turned off so
the micro-controller consumes less current), and for that we put the ADEN bit at 1 in the
ADCSRA register, and we set the ADSC bit in the same ADCSRA register, and in the
ADCSRB register we need to clear the ADTS2, ADTS1 and ADTS0 bits, this ones determine
how is a new conversion started, all cleared means that we are running in free-running mode,
but you can see in the data-sheet that a new conversion than be caused by a timer, or by

setting some bits in a non free-running mode, finally we also need to set ADATE bit to 1 so
that the free-running mode as a trigger source to start a new conversion.
This is way simpler when coded, so lets do it!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <avr/io.h>

int main(void){

DDRB |= (1<<PB5); ///PB5/digital 13 is an output

ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //Prescaler at 128 so we have an
125Khz clock source
ADMUX |= (1<<REFS0);
ADMUX &= ~(1<<REFS1); //Avcc(+5v) as voltage reference
ADCSRB &= ~((1<<ADTS2)|(1<<ADTS1)|(1<<ADTS0)); //ADC in free-running mode
ADCSRA |= (1<<ADATE); //Signal source, in this case is the free-running
ADCSRA |= (1<<ADEN); //Power up the ADC
ADCSRA |= (1<<ADSC); //Start converting

for(;;){ //The infinite loop could also be while(1)
//Read ADC value
//If ADC value > 512 turn led on
//Else turn led off
}

return 0;
}
Now the only thing that its left is to read the ADC converted value, and this is the easiest
part, we only need to write one word to access the converted value, I will just complete the
code, because its only a simple if statement.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <avr/io.h>
int adc_value; //Variable used to store the value read from the ADC converter

int main(void){

DDRB |= (1<<PB5); ///PB5/digital 13 is an output

ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //Prescaler at 128 so we have
an 125Khz clock source
ADMUX |= (1<<REFS0);
ADMUX &= ~(1<<REFS1); //Avcc(+5v) as voltage reference
ADCSRB &= ~((1<<ADTS2)|(1<<ADTS1)|(1<<ADTS0)); //ADC in free-running
mode
ADCSRA |= (1<<ADATE); //Signal source, in this case is the free-running
ADCSRA |= (1<<ADEN); //Power up the ADC
ADCSRA |= (1<<ADSC); //Start converting

for(;;){ //The infinite loop

19
20
21
22
23
24
25
26
27
adc_value = ADCW; //Read the ADC value, really that's just it
if(adc_value > 512){
PORTB |= (1<<PB5); //If ADC value is above 512 turn led on
}
else {
PORTB &= ~(1<<PB5); //Else turn led off
}
}

return 0;
}
Now its just a matter of copy paste the code to AvrStudio and compile it, it should present no
errors or warnings, and upload it to your board using avrdude, if you have problems
uploading read by first and second tutorial again or leave a comment.

Here the upload is already done, now just turn your pot, the led should light up when you
rotate the pot clockwise past its midpoint and turn off when you turn anti-clockwise before
the midpoint of the pot.


And well, thats it, you already have the knowledge to use the ADC, but you still dont know
how to change channel/analogic input pin, so this is sort of a part 2, in part because this will a
rather big tutorial and you can read until here and leave the rest to another day.
Lets learn how to change the input channel so we can read any analogic input that we want,
as I have already said this can be done setting or clearing the MUX3, MUX2, MUX1 and
MUX0 bits in the ADMUX register, the mapping between the MUX values and the selected
channel is shown in this table:
1
2
3
4
5
6
7
MUX3 MUX2 MUX1 MUX0 Pin that will be read
0 0 0 0 PORTC0 Analogic0
0 0 0 1 PORTC1 Analogic1
0 0 1 0 PORTC2 Analogic2
0 0 1 1 PORTC3 Analogic3
0 1 0 0 PORTC4 Analogic4
0 1 0 1 PORTC5 Analogic5
As we are going to read different pins there is no sense to have the ADC in free-running
mode, because having it in that mode imposes a limitation, when we change the adc
channel/pin in free-running mode we must wait for 2 conversions to be made because thats
the time that the multiplexer takes to change from pin to pin, but if we start a single
conversion after setting the multiplexer we dont need to wait any time.
But when running in single conversion mode there are some new things that we must check,
as the ADC clock is ratter slow (125Khz compared to the 16Mhz that the chip is running) and
each conversion takes 13 cycles of that 125Khz clock when we read the ADC we start a new
single conversion and we need to wait until its done, to do this we check the bit ADSC until
its cleared, when its cleared the conversion is done, and as we are doing single conversions
we dont need to mess with the ADTS and ADATE bits, so less code.
The code that will show here is basically the code from the first part, but wrapped in two nice
functions to make it a bit cleaner and the function that is used to read the ADC as the code
needed to change channels already added.


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
#include <avr/io.h>

uint16_t adc_value; //Variable used to store the value read from the ADC
void adc_init(void); //Function to initialize/configure the ADC
uint16_t read_adc(uint8_t channel); //Function to read an arbitrary analogic channel/pin

int main(void){

for(;;){ //Our infinite loop
}

return 0;
}

void adc_init(void);{

ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz the
ADC reference clock
ADMUX |= (1<<REFS0); //Voltage reference from Avcc (5v)
ADCSRA |= (1<<ADEN); //Turn on ADC
ADCSRA |= (1<<ADSC); //Do an initial conversion because this one is the
slowest and to ensure that everything is up and running
}

uint16_t read_adc(uint8_t channel){
ADMUX &= 0xF0; //Clear the older channel that was read
ADMUX |= channel; //Defines the new ADC channel to be read
ADCSRA |= (1<<ADSC); //Starts a new conversion
while(ADCSRA & (1<<ADSC)); //Wait until the conversion is done
return ADCW; //Returns the ADC value of the chosen channel
}
The code is still easy to ready and understand, and now we have two handy functions that you
can just copy and paste into your projects and read the ADC just like you are using the
Arduino functions, the number that you pass to the read_adc() function is the same number
that is printed in the Arduino board, its also the pin number from PORTC, so analogic
channel 0 is in PORTC0 and can be read using read_adc(0).
Now, to make this code a little bit more interesting lets go back in time and get some serial
functions to send some data read from the ADC back to our computer where we can capture
it using the Terminal and do for example some graphs using GnuPlot or a simple spreadsheet
in Excel.


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
#define F_CPU 16000000UL
#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

void USART_send( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}

}
Now lets merge this together, dont get lost, its only a copy paste operation to put together the
ADC and the serial code together:


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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <avr/io.h>
#define F_CPU 16000000UL
#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

uint16_t adc_value; //Variable used to store the value read from the ADC
void adc_init(void); //Function to initialize/configure the ADC
uint16_t read_adc(uint8_t channel); //Function to read an arbitrary analogic channel/pin
void USART_init(void); //Function to initialize and configure the USART/serial
void USART_send( unsigned char data); //Function that sends a char over the serial port
void USART_putstring(char* StringPtr); //Function that sends a string over the serial
port

int main(void){
adc_init(); //Setup the ADC
USART_init(); //Setup the USART

for(;;){ //Our infinite loop
//Read the channels one by one and then send the read value to the terminal via serial
}

return 0;
}

void adc_init(void){
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz the
ADC reference clock
ADMUX |= (1<<REFS0); //Voltage reference from Avcc (5v)
ADCSRA |= (1<<ADEN); //Turn on ADC
ADCSRA |= (1<<ADSC); //Do an initial conversion because this one is the
slowest and to ensure that everything is up and running
}

uint16_t read_adc(uint8_t channel){
ADMUX &= 0xF0; //Clear the older channel that was read
ADMUX |= channel; //Defines the new ADC channel to be read
ADCSRA |= (1<<ADSC); //Starts a new conversion
while(ADCSRA & (1<<ADSC)); //Wait until the conversion is done
return ADCW; //Returns the ADC value of the chosen channel
}

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

void USART_send( unsigned char data){

51
52
53
54
55
56
57
58
59
60

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}

}
And now we have a little problem, when using the Arduino IDE we can just use the print
functions and they will take care of everything under to hood to convert for example the 10
bits data from the ADC to a nice string of number that we can read, but doing things bare-
metal we dont have such royalties. In order to convert the 10 bits ADC value to a readable
number string we need to use a function called ITOA(stands for Integer TO Ascii) this
functions as 3 input parameters, one is the value that we want to convert, this can be an
uint8_t, uint16_t, int, and other similar types of integer variables, other of the input
parameters is the base for where we want to convert, 2 to convert to binary, 8 for octal, 10 for
decimal, and 16 for hexadecimal, and finally a small array that will be the output string plus
the NULL string terminator, this output array must have at least space for the maximum
number of chars that our number as plus one for the NULL, so as we are using 10 bits values
from the ADC, this means that our maximum value is 2^10-1 = 1023, so we can have a
maximum of 4 numbers plus the terminator so we need an array with space for 5 chars. Also,
itoa is one of the standart functions of C, and thus it is located in the stdlib.h header and that
header must be included so the compiler doesnt complains.In a generic mode this is how the
itoa function is used:
1
2
3
4
5
#include <stdlib.h> //This lib is where the itoa function is located

char buffer[5]; //The output array
uint16_t adc_value; //A variable were we have some data that we want to convert
to a string
itoa(adc_value, buffer, 10); //And now buffer as the string with the decimal value
that was in the adc_value variable
Now lets add this function to our code and add some more bits so it can scan all the ADC
ports and send the data to the terminal, you can use this as I said above as a simple data
logger, and this little program as already been handy to log some voltages over time and then
graph then in Excel.


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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <avr/io.h>
#include <stdlib.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

uint16_t adc_value; //Variable used to store the value read from the ADC
char buffer[5]; //Output of the itoa function
uint8_t i=0; //Variable for the for() loop

void adc_init(void); //Function to initialize/configure the ADC
uint16_t read_adc(uint8_t channel); //Function to read an arbitrary analogic channel/pin
void USART_init(void); //Function to initialize and configure the USART/serial
void USART_send( unsigned char data); //Function that sends a char over the serial port
void USART_putstring(char* StringPtr); //Function that sends a string over the serial
port

int main(void){
adc_init(); //Setup the ADC
USART_init(); //Setup the USART

for(;;){ //Our infinite loop
for(i=0; i<6; i++){
USART_putstring("Reading channel ");
USART_send('0' + i); //This is a nifty trick when we only want to send a number
between 0 and 9
USART_putstring(" : "); //Just to keep things pretty
adc_value = read_adc(i); //Read one ADC channel
itoa(adc_value, buffer, 10); //Convert the read value to an ascii string
USART_putstring(buffer); //Send the converted value to the terminal
USART_putstring(" "); //Some more formatting
_delay_ms(500); //You can tweak this value to have slower or faster readings or
for max speed remove this line
}
USART_send('\r');
USART_send('\n'); //This two lines are to tell to the terminal to change line
}

return 0;
}

void adc_init(void){
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz the
ADC reference clock
ADMUX |= (1<<REFS0); //Voltage reference from Avcc (5v)
ADCSRA |= (1<<ADEN); //Turn on ADC
ADCSRA |= (1<<ADSC); //Do an initial conversion because this one is the
slowest and to ensure that everything is up and running
}

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

uint16_t read_adc(uint8_t channel){
ADMUX &= 0xF0; //Clear the older channel that was read
ADMUX |= channel; //Defines the new ADC channel to be read
ADCSRA |= (1<<ADSC); //Starts a new conversion
while(ADCSRA & (1<<ADSC)); //Wait until the conversion is done
return ADCW; //Returns the ADC value of the chosen channel
}

void USART_init(void){

UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}

void USART_send( unsigned char data){

while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

}

void USART_putstring(char* StringPtr){

while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}

}
Now compile this and upload it to your Arduino, if you just want to test the program you
dont need to connect anything to the ADC inputs, they will act as antennas and capture some
random noise so you will see varying number in the terminal.


I have updated my Terminal, you can also do the same or keep using the older one, there are
no differences, and the configuration is exactly the same for this new one or for the older one,
you can get it here: https://sites.google.com/site/terminalbpp/
And this is the result:

And thats it, a long tutorial, but it covers a lot about the ADC and also teach a little about
using the itoa function, fell free to try it and leave feedback in the comments, thanks for
reading!
Corrected some errors in the text, and added the two examples to Google Code to download
then as Avr Studio projects:
http://code.google.com/p/avr-tutorials/downloads/detail?name=adc1.zip
http://code.google.com/p/avr-tutorials/downloads/detail?name=adc2.zip


11.10.7. Introducere in modulatia impulsurilor in durata (PWM)

Lets start, this one will be about PWM generation using the hardware timers.
PWM stands for Pulse Width Modulation, what all this fancy words mean is that using a
timer (or by software but that is not aborded in this tutorial) we control the time that our
signal is HIGH and LOW, by doing this the average energy that is supplied to our target
device can be controlled and this HIGH and LOW time is called duty cycle.
This means that we can control the brightness of an LED, mix colour when using RGB leds,
control the speed of a dc motor, or even generate some audio. PWM signals are also used to
control the so common servos that are used in so many robotics projects, and using a simple
RC filter can be used as a limited analog signal, this can be used for example to generate
sound or any other uses that you might come of.
In this image you can see what is the look of a PWM wave with three different duty cycle
values:

In this tutorial I will write about two PWM modes that our micro-controller offers to us, one
is the Fast PWM that can be generated in 8,9 or 10 bits, of course more than 8 bits resolution
can only be achieved when using one 16bits timer, and I will also write about the phase
correct PWM, this one is the mode that should be used when doing motor control to ensure
that everything runs perfectly.
First lets see the Fast PWM. It is probably called fast because for me its the easiest mode to
work with and it can work at higher frequencies than the phase correct mode, but it also as its
short-comings, for example it shouldnt be used as a PWM for motor control because it is
phase incorrect, this image will enlighten you about the phase correctness problem:


The top two PWM signals are the output generated by the fast PWM mode and the two
bottom ones are generated by the phase correct mode. The fast PWM HIGH part of the wave
always start in the same place as you can see in the picture but the LOW part will end in an
arbitrary place, that is defined by the duty cycle, this means that the center of the HIGH part
of the wave will not be constant and thats the main and key difference between the two
modes and thats why you shouldnt use it in motor control.

The above image explains how the phase correct PWM mode works. In fast PWM the timer
counts from BOTTOM to TOP and then starts over from BOTTOM again, but in phase
correct mode, the timer counts up and down, and the output wave is generated comparing our
desired duty cycle in both the up and down counts, instead of been compared only when the
timer is counting up and then being reset at the overflow when the timer is operating in fast
mode.
Overflow is the technical name that is used to said that the timer as hit TOP and as gone back
to BOTTOM.
Lets start to code something to put into practice all this timers and PWM theory, in this first
example I will show how to fade a led, in a smooth transition from off to on and then back to
off and then repeating all that again.


1
2
3
4
5
6
7
8
9
10
11
12
13
#include <avr/io.h>

int main(void){

//Set led pin as output
//Configure timer

for(;;){
//Set new duty cycle value and delay a little bit
}

return 0;
}
For this example I will use the timer 0, because there is no need to use our only 16bits timer
to simply fade a led, the first thing that we need to learn how to configure is the waveform
generation modes, that are described for the timer in in page 109 of the Atmega328p
datasheet.
The control bits described in that table can be found in two separate registers, the TCCR0A
and TCCR0B and are called WGM02, WGM01 and WGM00:

To use fast pwm we have two modes to choose, mode 3 and mode 7, the main difference
between this two modes is that in mode 3 TOP is fixed at 0xFF and in mode 7 TOP is defined
by the TOP register, this means that if there is the need, we can change the maximum count
that the timer will do until it overflows, so this means that we could control the frequency and
the duty cycle, I never felt the need to do that, but if you want now you know that you can do
it.
To use the mode 3, the WGM01 and WGM00 bits must be set to one, those bits can be found
in the TCCR0A register.
The next thing that needs to be configured is the Compare Match Output A(B) Mode, this is
what gives the pwm generation hardware the ability to control the output pins. For timer 0 the
pwm pins are PD6 for the OC0A and PD5 for the OC0B.
For this particular example lets choose PD6 as the pin where we will connect our led, to have

pwm behaviour in this pin we need to look to table 14-3 that can be found in page 106 to
learn how to enable this particular behaviour (to simplify I will attach the table here):

Looking to that table we can see that our desired mode is number 3, so we must set both
COM0A1 and COM0A0. The last thing that must be set is the prescaler that will provide the
clock source to our timer, as usual this clock source should be chosen wisely and not at
random, in page 103 of the datasheet is shown the formula that permits us to calculate what
will be the pwm frequency when using the fast pwm.
1
2
3
4
5
6
7
8
9
10
11
Fclk=16Mhz //Arduino clock/crystal speed

The formula:
Fpwm = Fclk/(Prescaler*256)

Prescaler Fout
1 62.5Khz
8 7812.5Hz
64 976Hz
256 244.141hz
1024 61.03Hz
When using the pwm modes the frequencies are pretty low, but for what they are generally
used they are more than enough, for this example I will choose the 32 prescaler, so lets get all
this info together in the source-code:


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 <avr/io.h>
#define F_CPU 16000000UL
#include <avr/delay.h>

int main(void){

unsigned char i=0;

DDRD = (1<<PD6); //Set our pwm pin as an output
//PD6 is Arduino digital pin 6

//Timer configuration
TCCR0A = ((1<<COM0A1)|(1<<WGM01)|(1<<WGM00)); //Enable pwm mode in pin
PD6 and set the WGM bits to Fast pwm mode
TCCR0B = ((1<<CS01)|(1<<CS00)); //Set prescaler to 32

for(;;){

//Fade up
for(i=0; i<255;i++){
OCR0A = i; //Set new duty cycle value
_delay_ms(50); //delay a litle bit
}

//Fade down
for(i=255; i>0;i--){
OCR0A = i; //Set new duty cycle value
_delay_ms(50); //delay a litle bit
}
}

return 0;
}
video fade
Now, lets do something fancier and more complex, because all this tutorials have been very
long and the visible results have been well small, so I will teach you how to do a mood light
using an RGB led or if you dont have an RGB led you can also use three leds, one red, one
green and one blue, and lets also add two pots, one to control the intensity of the light and
one to control the time that takes between each step. To make this even more challenging
instead of delays I will use my custom milis so our code is non-blocking(this means that our
micro-controller will not sit there and just do nothing while delaying the needed time).
The first thing is that we need to use two timers, because using only one timer only gives us
two pwm pins/outputs, so I will also use timer 2 to get the third pwm pin, and timer 1 to put
my milis function up and running, the configuration of timer 2 is precisely equal to what is
done to timer 0, its just a matter of changing the name of the registers from 0 to 2.
I will now put all this in pseudo-code:
1 #include <avr/io.h>

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

int main(void){

//Set led pins as output
//Configure timer0 to generate two pwm signals
//Configure timer2 to generate one pwm signal
//Configure timer1 to be used as our milis time-base
//Configure ADC

for(;;){
//Read both the time and intensity pots
if(lastTime-milis() > timePotValue){
//Update the duty-cycles to output the next color
}
}

return 0;
}
In words it seemed complex but even in pseudo-code we can see that this will be a simple
task.
Now a crash course about colour spaces. Our leds are RGB this means that we have isolated
red, green and blue, but to mix this colours to create the maximum possible number of
distinct colours its very complex and when we try to add intensity control to that it gets even
worse, so I will use HSV (Hue, Saturation, Value), this is an also common colour space and
has the great advantage that it is represented in cylindrical coordinates and it is also easy to
convert an HSV color to RGB. If you really want to know more about HSV and color spaces,
reading this page will teach a lot, and anything that I can write will sound strange and fuzy,
because Im not really a master in the area of color spaces:
http://en.wikipedia.org/wiki/HSL_and_HSV
Our color will be obtained varying the Hue component and the intensity will act in the Value
range.
Lets start to fill our pseudo-code with real code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <avr/io.h>
#include <math.h>

#define INTENSITY 0 //The pot that controll the intensity is attached to adc pin 0, aka
PC0
#define TIME 1 //The delay time is controlled by the pot attached to adc pin 1, aka
PC1

//Functions prototypes
void timer0_init(void);
void timer1_init(void);
void timer2_init(void);
void adc_init(void);
void set_pwm(uint8_t red, uint8_t green, uint8_t blue);

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
void HSV_RGB();
uint16_t read_adc(uint8_t channel);
unsigned long milis(void);

int main(void){

//Local variables declaration
uint16_t delayTime = 0; //Variable to store the value read from one of the pots
uint16_t intensity = 0; //Variable to store the value read from the other pot

DDRD = ((1<<PD5)|(1<<PD6)); //Set pwm pins from timer 0 as outputs
DDRD |= (1<<PD3); //Set pwm pin OC2B from timer 2 as output

timer0_init(); //Setup timer 0
timer1_init(); //Setup timer 1
timer2_init(); //Setup timer 2
adc_init(); //Setup the ADC

sei(); //Enable global interrupts so our milis function can work

for(;;){
//Read both the time and intensity pots
delayTime = read_adc(TIME);
intensity = read_adc(INTENSITY);
if(lastTime-milis() > delayTime){
//Update the duty-cycles to output the next color
}
}

return 0;
}

void adc_init(void){
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz the
ADC reference clock
ADMUX |= (1<<REFS0); //Voltage reference from Avcc (5v)
ADCSRA |= (1<<ADEN); //Turn on ADC
ADCSRA |= (1<<ADSC); //Do an initial conversion because this one is
the slowest and to ensure that everything is up and running
}

uint16_t read_adc(uint8_t channel){
ADMUX &= 0xF0; //Clear the older channel that was read
ADMUX |= channel; //Defines the new ADC channel to be read
ADCSRA |= (1<<ADSC); //Starts a new conversion
while(ADCSRA & (1<<ADSC)); //Wait until the conversion is done
return ADCW; //Returns the ADC value of the chosen channel
}

void timer0_init(void){

TCCR0A = ((1<<COM0A1)|(1<<WGM01)|(1<<WGM00)); //Enable pwm mode in pin
PD6 and set the WGM bits to Fast pwm mode
TCCR0A |= (1<<COM0B1); //Enable pwm mode in pin PD5
TCCR0B = ((1<<CS01)|(1<<CS00)); //Set prescaler to 32
}
The ADC code is just copied from the ADC tutorial, so you already know it, and the
timer0_init function is just the code that I wrote above inside a little function, with the extra
COM registers to enable pwm in the OCR0B(the PD5 pin).
Now there is the need for some math, because in the timer tutorial I used timer 0 to
implement the milis functionality and now I will use timer 1 that is an 16 bits timer, and I will
also add the configuration for the timer 2 to also output one pwm signal and finally I will
introduce the function that does the conversion from HSV to RGB.
The timer 2 as also two pwm capable pins, those are the PD3 that is the OC2B pin and PB3
that is the OC2A pin. For this tutorial and with no special reason I choose the OC2B pin, the
configuration is equal as the one done to configure timer 0, because both of them are 8bits
timers. This is easy to understand, so I only show it only in the sourcecode that will follow
this text.
Now, lets see how we can get an 1ms interrupt from timer 1 so we can have our milis
function. Timer 1 is special, because instead of 8bits it is a 16 bits timer, this means that the
max count is 65535 instead of 255, and it has much more features than its smaller brothers,
like clock input from an external pin, so you can measure frequency with it, it also as some
extra hardware that can do de-bouncing of buttons, but it can only be used in one pin, it can
also generate pwm up to 10 bits, and has more modes of operation.
1
2
3
4
5
6
7
8
9
10
Target Timer Count = (((Input Frequency / Prescaler) / Target Frequency) - 1)
Input Frequency = 16Mhz
Target frequency = 1000Hz

Prescaler value | Target timer count
1 | 15999
8 | 1999
64 | 249
256 | 61.5
1024 | 14.625
As we are using an 16bits we can use the first value, because it is lower than the maximum
count of 65535.
Lets get all this together in the code.
1
2
3
4
5
6
7
8
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>

#define VAL 0 //The pot that controll the intensity is attached to adc pin 0, aka
PC0
#define TIME 1 //The delay time is controlled by the pot attached to adc pin 1,
aka PC1

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

//Functions prototypes
void timer0_init(void);
void timer1_init(void);
void timer2_init(void);
void adc_init(void);
void set_pwm(uint8_t red, uint8_t green, uint8_t blue);
void Hsv2Rgb( double *r, double *g, double *b, double h, double s, double v );
unsigned long milis(void);
uint16_t read_adc(uint8_t channel);

//Global Variables
volatile unsigned long milis_count = 0; //This var is shared between function and an
ISR, so it must be declared volatile

int main(void){

//Local variables declaration
unsigned int delayTime = 10; //Variable to store the value read from one of the pots
uint16_t intensity = 0; //Variable to store the value read from the other pot
unsigned long lastTime = 0; //Variable to count how much time as passed
double red = 0.0; //Actual red value
double green = 0.0; //Actual green value
double blue = 0.0; //Actual blue value
double hue = 0.0; //Actual hue value, this says what color is it
double saturation = 100; //Set saturation value to maximum, this value can be
tweaked
double value = 1.0; //This is where we set the light intensity using the pot

timer0_init(); //Setup timer 0
timer1_init(); //Setup timer 1
timer2_init(); //Setup timer 2
adc_init(); //Setup the ADC

sei(); //Enable global interrupts so our milis function can work
DDRB = (1<<PB5);

for(;;){
if( (milis() - lastTime) >= delayTime){

PORTB ^= (1<<PB5);
lastTime = milis();

//Read both the time and intensity pots
delayTime = read_adc(TIME) * 2; //I use times two here to set the max delay to 2
seconds, but you can tweak the code
//to increase or decrease this

if(delayTime <= 10){
delayTime = 10; //Just to make sure that we always wait at least 10ms to change

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
color;
}

intensity = read_adc(VAL);
value = ((double)(intensity/1024.0)*255.0); //This is like a map, so the intensity value is
between 0 and 255

if(value >= 255.0){
value = 255.0; //Just to make sure that we don't go beyond 255 or it can cause strange
results
}

if(value <= 0.1){
value = 0.0;
}

//Update the duty-cycles to output the next color

Hsv2Rgb(&red, &green, &blue, hue, saturation, value);

red = red * 255.0; //This is needed be cause the conversion formula returns values
between 0 and 1
green = green * 255.0; //And we need values between 0 and 255 for our pwm
generators
blue = blue * 255.0;

hue = hue + 1.0; //You can also tweak this value to have bigger or smaller steps
between colors

if(hue > 360){
hue = 0;
}

OCR0A = (uint8_t)red; //Red led is connected to pin PD6/digital 6
OCR0B = (uint8_t)green; //Green led is connected to pin PD5/digital 5
OCR2B = (uint8_t)blue; //Blue led is connected to pin PD3/digital pin 3

//If you are using an RGB led this will work out of the box for common anode ones
}
}

return 0;
}

void adc_init(void){
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz the
ADC reference clock
ADMUX |= (1<<REFS0); //Voltage reference from Avcc (5v)
ADCSRA |= (1<<ADEN); //Turn on ADC
ADCSRA |= (1<<ADSC); //Do an initial conversion because this one is

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
the slowest and to ensure that everything is up and running
}

uint16_t read_adc(uint8_t channel){
ADMUX &= 0xF0; //Clear the older channel that was read
ADMUX |= channel; //Defines the new ADC channel to be read
ADCSRA |= (1<<ADSC); //Starts a new convertion
while(ADCSRA & (1<<ADSC)); //Wait until the convertion is done
return ADCW; //Returns the ADC value of the choosen channel
}

void timer0_init(void){

DDRD = ((1<<PD5)|(1<<PD6)); //Set pwm pins from timer 0 as outputs
TCCR0A = ((1<<COM0A1)|(1<<WGM01)|(1<<WGM00)); //Enable pwm mode in pin
PD6 and set the WGM bits to Fast pwm mode
TCCR0A |= (1<<COM0B1); //Enable pwm mode in pin PD5
TCCR0B = ((1<<CS01)|(1<<CS00)); //Set prescaler to 32
}

void timer2_init(void){
DDRD |= (1<<PD3); //Set pwm pin OC2B from timer 2 as output
TCCR2A = ((1<<COM2B1)|(1<<WGM21)|(1<<WGM20)); //Enable pwm mode in
PD3 and set the WGM bits for fast pwm mode
TCCR2B = ((1<<CS21)|(1<<CS20)); //Set prescaler to 32
//As you can see, the code for timer 0 and 2 is very similiar, and even almost registers are
identical, this is equal also for timer 1
}

void timer1_init(void){

TCCR1B = ((1<<WGM12)|(1<<CS10)); //Timer in CTC mode, prescaler set to 1
OCR1A = 15999; //Our target count to have an 1ms interrupt
TIMSK1 = (1<<OCIE1A); //Enable interrupt when OCR1A value is reached
}

unsigned long milis(void){

cli(); //Disable all interrupts so we can read our long variable atomically
//This is to ensure that no interrupt is fired while reading the long variable
//And possibly trash the readed value
unsigned long milis_value = milis_count; //Copy the value and return it
sei(); //Enable all interrupt again
return milis_value;

}

ISR(TIMER1_COMPA_vect){
milis_count++; //Just add 1 to our milis value
}

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

void Hsv2Rgb( double *r, double *g, double *b, double h, double s, double v ) {
int i;
double f, p, q, t;

s/=100.0;
v/=255.0;

if( s == 0 ) {
// achromatic (grey)
*r = *g = *b = v;
return;
}

h /= 60; // sector 0 to 5
i = (int)floor( h );
f = h - i; // factorial part of h
p = v * ( 1.0 - s );
q = v * ( 1.0 - s * f );
t = v * ( 1.0 - s * ( 1 - f ) );

switch( i ) {
case 0:
*r = v;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = v;
*b = p;
break;
case 2:
*r = p;
*g = v;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = v;
break;
case 4:
*r = t;
*g = p;
*b = v;
break;
default: // case 5:
*r = v;
*g = p;

*b = q;
break;
}
}
The Hsv2Rgb function is a bit complex/more advance than the usual code shown in this
tutorials, probably the most complex part of it is the use of pointers, I hope that for now you
can just understand it, but if there are at least one request, in the future I will also make a
tutorial about pointers, but for now this might enlighten you:
http://en.wikipedia.org/wiki/Pointer_%28computing%29
I know that Im linking to wikipedia twice in this tutorial, but it is a great resource of
information and if I explained everything here this tutorial would be even longer.
Also one note of advice, when using math.h you should tell the IDE/compiler to link with lib
math that was written just for AVRs, and is much more improved than the stndart one, here
is how you do it. First open the Configuration Option menu that is available under the Project
tab:

Then go to the Libraries tab/section select libm.a, press Add Library and it should appear in
the Link with these Objects listing, this image might help:


To keep things clear here is an schematic on how you should connect everything:

Now just build the circuit, its really easy just one/three leds, three resistor, they can 330 as I
used or 270Ohm or a bit more than 330Ohm, but that will decreased the maximum brightness

http://code.google.com/p/avr-tutorials/downloads/detail?name=pwm_tutorial.zip





12. Getting started Arduino
13. Sisteme cu mP incorporate . RTOS
14. Introducere in mP Atmega 328p si Arduino
15. Aplicatii Arduino IDE 22
16. Aplicatii Atmega 16 si STK500
17. Aplicatii Codevision
18. AVR - GCC
19. Aplicatii STK500 Codevision
20. Aplicatii Codevision
21. Realizari constructive
22. Complemente de programare in C
23. Bibliografie

S-ar putea să vă placă și