History and Binary Representation
History and Binary Representation
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.
Abstract
In this lesson we will review the history of electronics and the devel-
opment of the first microprocessors.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital.
1 History
Let us begin with the history of semiconductors and contemporary electronics.
Although it started in Germany, it flourished at the Bell Labs in the United
States.
∗ creq@[Link]
1
1874 Diode effect discovered by Ferdinand Braun at the University
of Berlin.
1906 Diode patented.
1925 Bell Labs is founded.
1925 MOS transistor is patented by Julius Lilienfeld.
1929 Walter Brattain joins Bell Labs.
1934 Another MOS patent by Oskar Heil.
1936 Mervin Kelly becomes director of Bell Labs.
1936 William Shockley joins Bell Labs.
1945 John Bardeen joins Bell Labs.
1947 Bardeen and Brattain conceive the Point Contact Transistor.
1948 Shockley invents the Bipolar Junction Transistor.
1953 First transistor computer built at the University of Manchester
by Dick Grimsdale.
1954 Transistors are fabricated in Si by Morris Tanenbaum at Bell Labs.
1956 Nobel Prize for the invention of the transistor.
1956 Shockley found Shockley Semiconductor Laboratory in Mountain
View, CA.
1957 Robert Noyce, Gordon Moore, Jean Hoerni and the other traitorous
eight found Fairchild Semiconductors.
1958 Jack Kilby at Texas Instruments and Robert Noyce at Fairchild
Semiconductors independently develop the fist Integrated Circuit.
1959 Planar transistor developed by Jean Hoerni at Fairchild
Semiconductors.
1968 Robert Noyce and Gordon Moore found Intel Corporation.
2
Figure 1: DIP, PLCC and PGA packagings.
3
3 Binary Representation
Let us begin our study of microcontrollers by reviewing the binary representa-
tion and operations.
A binary number has only two mnemonics. We will use 1 to represent the
high state, and 0 to represent the low state. Thus, we can have a binary number
such as 011001. This can be converted to decimal by:
ÿ
X“ bn 2n
n
“ 1 ˆ 20 ` 0 ˆ 21 ` 0 ˆ 22 ` 1 ˆ 23 ` 1 ˆ 24 ` 0 ˆ 24 (1)
“ 1 ` 8 ` 16
“ 25.
The reverse operation can be constructed by successively dividing a decimal
number by 2 and taking the remainder. For example:
25{2 “ 12 ` rr1s
12{2 “ 6 ` rr0s
6{2 “ 3 ` rr0s (2)
3{2 “ 1 ` rr1s
1{2 “ 0 ` rr1s,
where r[x] is the remainder of the operation. Therefore, 25 can be represented
as 11001.
Now, let’s take number 9 in binary:
9{2 “ 4 ` rr1s
4{2 “ 2 ` rr0s
(3)
2{2 “ 1 ` rr0s
1{2 “ 0 ` rr1s
It needs 4 bits to be represented. We could have reached the same result by
taking Log2 p9q « 3.17 Ñ 4. Thus, we can represent decimal numbers in groups
of four bits. This is called binary coded decimal or BCD. For instance,25 would
be represented as 0010 0101. It requires more bits to be represented but it has
the advantage of simplicity.
4
110.01 “ 1 ˆ 22 ` 1 ˆ 21 ` 0 ˆ 20 ` 0 ˆ 2´1 ` 1 ˆ 2´2
“ 4 ` 2 ` 0.25 (4)
“ 6.25.
In our case both 25 and 6.25 have exacly the same representation in binary. The
only difference is the point.
´3 “ 100
´2 “ 101
´1 “ 110
´0 “ 111
(5)
0 “ 000
1 “ 001
2 “ 010
3 “ 011
This has some problems. For example, the 1’s complement of 000000 (0)
is 111111 (-0). Furthermore, arithmetic operations become problematic. Let’s
take for example 3-1 in a 3 bit representation. This would be 011 + 110, which
would produce 001 and a carry-out bit of 1. This has to be added to the result
and we obtain 010, which is the expected result.
´4 “ 100
´3 “ 101
´2 “ 110
´1 “ 111
(6)
0 “ 000
1 “ 001
2 “ 010
3 “ 011
5
This way, not only we avoid the problem of -0 as we also simplify the arithmetics.
Let’s see that example of 3-1 again now in 2’s complement. This would be
011+111=010=2 with a carry bit that can be completely discarded. In 2’s
complement, overflow can be detected if summing two numbers of the same
sign produces a number with an opposite sign.
Let us now see how this works for signed fixed point numbers:
´2.0 “ 100
´1.5 “ 101
´1.0 “ 110
´0.5 “ 111
(7)
0.0 “ 000
0.5 “ 001
1.0 “ 010
1.5 “ 011
3.1.3 Arithmetic
For fixed point representation, addition and subtraction are exactly the same
operations as we would do for integer numbers. For example:
010
ˆ 001
010
1.0 ˆ 0.5 “ (9)
000
` 000
00010
We must now account for the radix point. Since both multiplicands have points
after the first bit, the result has to have the point after two bits. Therefore,
the result is 000.10. However, our representation includes only one bit for the
fractional part and two for the integer part. We therefore must either truncate
or round the result for the appropriate number of bits. It is simple in this case
to just truncate it to 00.1, which in decimal is 0.5, the result that we expected.
Let us now use two bits for each the integer and the fractional part. Our
correspondence table becomes:
6
0.00 “ 0000
0.25 “ 0001 ´0.25 “ 1111
0.50 “ 0010 ´0.50 “ 1110
0.75 “ 0011 ´0.75 “ 1101
1.00 “ 0100 ´1.00 “ 1100 (10)
1.25 “ 0101 ´1.25 “ 1011
1.50 “ 0110 ´1.50 “ 1010
1.75 “ 0111 ´1.75 “ 1001
´2.00 “ 1000
Let’s multiply 0.25 ˆ ´2.00:
0001
ˆ 1000
0000
0000 (11)
0000
` 1000
1000000
Our multiplicands have two bits for the fractional part. Therefore, the result
should have four bits for its fractional part and we would get 100.0000. Trun-
cating it we get 00.00, which is completely wrong. This happened because we
did not account for the sign. One way to compensate for it is by expanding the
bit sign:
1000
ˆ 0001
111000
0000 (12)
0000
` 0000
0111000
We must place the point four bits from the right hand side end. Therefore, the
truncated result becomes 11.10, which corresponds to -0.5 as expected. Why
did we do this 1 filling operation? Because we are multiplying 1ˆ a negative
number. We therefore must take its 2’s complement. We obtain it by 1 filling.
This is known as sign extension. Let’s calculate it now the other way around:
0001
ˆ 1000
0000
0000 (13)
0000
` 1111
1111000
7
Taking four bits for the radix point and truncating we get 11.10, which is the
expected result. Note, however that we took 2’s complement. This happened
because we are multiplying one argument by the sign bit. It is like multiplying
the argument by -1.
Let’s now take a look at another example: ´0.75 ˆ 0.75:
1101
ˆ 0011
1111101
111101 (14)
0000
` 0000
11110111
Placing the point we get 1111.0111. If we simply truncate the result we get
1101 which corresponds to -0.75. The right result would be -0.5625 and we
have a quantization error which cannot be accounted for in this representation
with a restricted number of bits. For the sake of practice, let’s make the same
calculation the other way around:
0011
ˆ 1101
0011
0000 (15)
0011
` 1101
11110111
Which is exactly the same value.
S E3 E2 E1 E0 M5 M4 M3 M2 M1 M0 , (16)
where S is a bit for the sign, E is the exponent, and M is the mantissa. This
can be represented as p´1qS M ˆ 2E . Typically, in floating point representation,
the mantissa is normalized. For example:
110.100 “ 1.10100 ˆ 22
. (17)
0.00101 “ 1.01000 ˆ 2´3
Also, the exponent is stored with a 127 bias according to IEEE 754 standard.
This means that the exponent is added to 127 (01111111) and then stored.
For example, 12 (01100) is stored as 139 (010001011), and -5 is stored as 122
(01111010).
8
Let us now put it all together. A number in floating point notation is stored
as SIGN EXPONENT MANTISSA. Also, for the mantissa, the 1 at the left
hand side of the radix point is dropped. Let’s look at some examples:
3.2.1 Arithmetic
Addition and subtraction are quite simple. We first must put both operands in
the same exponent and them perform a standard sum of the mantissas main-
taining the exponent.
Multiplication and division are also simple. For the mantissa we must per-
form a standard multiplication. We sum the exponents and subtract the bias.
The sign bit are just added and the carry is dropped.
Thus for a floating point representation with 2 bits for the exponent with a
bias 2 and 3 bits for the mantissa we have:
2.5 ` 0.5 “
“ 10.1 ` 0.1
“ 1.01 ˆ 21 ` 1.00 ˆ 2´1
“ 0 11 010 ` 0 01 000
“ 101.00 ˆ 2´1 ` 1.00 ˆ 2´1 (19)
“ 110.00 ˆ 2´1
“ 1.10 ˆ 21
“ 0 11 100
“ 3.0.
´2.0 ˆ 0.25 “
“ ´10.0 ˆ 0.01
“ ´1.00 ˆ 21 ˆ 1.00 ˆ 2´2
“ 1 11 000 ˆ 0 00 000
(20)
“ 1 01 000
“ ´1.000 ˆ 2´1
“ ´0.100
“ ´0.5
9
Computer Architecture
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.
Abstract
In this lesson we will review digital electronics and begin studying
processor architectures.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital.
1 Circuit Blocks
As logical connectives let’s take the dyadics conjunction (^, AND), disjunction
(_, OR), the exclusive disjunction (Ü, XOR), and the unary negation ( ,
NOT). Also, as memory elements let’s take the register. These elements are
shown in Fig. 1.
In a digital system we may have an adder, a subtracter and many other
small blocks. In order for the processor to work, we must have a unit that sends
the appropriate signals for these blocks, that load registers, etc. This is called
control unit. There must be another block that actually make computations.
This block is known as processing unit. Certainly, we must also have registers
and some other components that store information. This is called memory block.
∗ creq@[Link]
A A A
A B A B A B
B B B
D Q
A A
clr Q
1
Let us consider a stupid simple architecture that takes two bits and either
add or subtract them. Let us design the adder and the subtracter. If we make
an operation such as 0-1, we must raise a flag to state that we have an un-
derflow. By the same token, if we add 1+1 we must also raise a flag to state
that we have an overflow. For the sake of simplicity, let’s make this flag the same.
From this truth table we clearly see that add = b1 b b2 , sub = b1 .b̄2 , and flag
= b2 . These operations will be inside the logical and arithmetic unit or ALU.
However, we must select whether we want the ALU to perform an addition or
a subtraction. Let’s say that if the selection bit ’s’ is 0 we add the inputs. The
truth table for this is:
add/sub
00 01 11 10
0 1 1
S
1 1 1
For LAU we thus have s̄.add ` [Link]. Thus, we have the control unit illus-
trated in Fig. 2.
This block has to perform operations on data and this is stored in registers
or in a memory bank. In our example, let’s use a single register ‘R’ that can
2
ADD
flag
b2 LAU
b1
s
SUB
Figure 2: Logic and arithmetic unit. The dashed boxes correspond to the adder
and subtracter subblocks.
feed the LAU and also store its result. Also, we can also asynchronously set and
reset it. Nonetheless, our operations are dyadic, so we need another element.
Since our circuit works with only one bit, the other element can only be 0 or 1.
This can come from another point of the circuit and we shall call it ‘Y’. At this
point our circuit is as that shown in Fig. 3.
Y
SET R
set
D Q
LOAD R
clr Q
CLEAR R
X Y
S s
flag
Figure 3: 1 bit LAU and register with control signals explicitly shown.
3
trically erasable programmable read only memory (EEPROM). In any case we
need to tell it which position of the memory we want to read. Furthermore we
need to tell it that we want to read that address. In order to do this we will
use a counter, which we shall call Program Counter (PC). Nonetheless, the PC
need signals to increment its status and the memory needs a signal to read the
contents of the corresponding position. This circuit block is illustrated in Fig.
4.
READ
read
INC inc cnt add MEM
data
PC
CODE
Figure 4: Program counter and memory block.
What code can be stored in this memory? Our LAU can do addition and
subtraction. Also, we can set, reset or load the R register. Therefore we can
have a very limited set of instructions. For each one we must assign a different
binary code. We can have something like the instruction set shown in Table 1.
We now need a block that interprets the instructions and sends the appro-
priate signals to the other circuit blocks. This we will call the control unit.
From the table we see that the instructions related to R register have a 0 most
significant bit (MSB). Therefore we must have a C¯3 .C1 for the SET R signal,
C¯3 .C¯2 .C¯1 for the CLEAR R signal, and C¯3 .C2 for the LOAD R signal. The
commands for the LAU have a 0 MSB. Furthermore, the addition instructions
have their second bit always 0, whereas the subtraction instructions have their
second bit always 1. Therefore, we must have C2 for the S signal and C1 for
the Y signal. Finally, we can always read the memory and increment the PC
for each clock signal. Thus, we connect the latter to the CLK signal and the
4
former to logic 1. We finally have the architecture shown in Fig. 5.
1
read
CLK inc cnt add MEM
data
PC
set
D Q
clr Q
X Y
s
flag
2 Architecture
The architecture of the first microprocessor (Intel 4004) is shown in Fig. 6. For
running this architecture, there were 45 instructions available. This is a good
point to start studying computer architecture. However, we can construct an
even simpler version of this microprocessor to understand basic concepts.
A very simple architecture is shown in the Fig. 7. Here we have the same
elements depicted in the 1 bit architecture but with a few modifications. First,
instead of a single flag, we have now a status register. The register can be fed
from the memory and also from the ALU itself. Furthermore, the memory is
now storing a set of more complex instructions. These are listed on Table 2.
5
D0-D3 bidirectional
Data Bus
Data Bus
Buffer
Temp.
Accumulator Instruction Register
Register
Register Multiplexer
0 1
Flag Stack
2 3
Flip Flops Multiplexer
Stack Pointer
Decoder and
Machine Level No. 1
6 7
Cycle
Level No. 2
Encoding
ALU 8 9
Level No. 3
10 11
Address
Stack
12 13
Decimal 14 15
Adjust
Scratch
Pad
Timing and Control
ROM Control RAM Control Test Sync Clocks
Reset
Figure 6: Internal architecture of the Intel 4004 (By Appaloosa (Own work) via
Wikimedia Commons).
PC MEM
LOAD OP L
INC
CPU
W
STATUS LOAD
LOAD CLR
CLR
OP
ALU
6
Table 2: Instruction set for the proposed simplified architecture.
Instruction Binary Code Description
MOVLW 0000 L3 L2 L1 L0 Move literal to W register.
AND 0001 L3 L2 L1 L0 AND between W register and literal. Result in W.
OR 0010 L3 L2 L1 L0 OR between W register and literal. Result in W.
ADD 0011 L3 L2 L1 L0 ADD literal and store in W register.
CMP 0100 L3 L2 L1 L0 Compare literal and W register, Result in STATUS register.
CLRW 0101 0000 Clear W register.
CLRS 0101 0001 Clear STATUS register.
GOTO 0110 L3 L2 L1 L0 Set PROGRAM COUNTER register to literal.
BTFSS 0111 0000 Skip next instruction is STATUS register is set.
NOP 0111 0001 Do nothing.
DATA CODE
MEM
MEM MEM
CPU CPU
7
tion set computer or CISC. It is convenient to the programmer since the code
becomes simpler and smaller. On the other hand the hardware engineer needs
to pack more content into the processor.
Over the years, manufacturers realized that most of the complex instructions
were rarely used and they required a lot of memory used. Furthermore it did not
offer much flexibility to the programmer since the microcode is already stored
in hardware. One solution proposed by some manufacturers was an architecture
based on a reduced instruction set computer or RISC. In this architecture, the
instructions are simpler, executed directly by the hardware without the inter-
mediation of any microcode. Furthermore, several techniques to improve the
access to the memory were pursued such as pipelining.
3 Memory Addressing
There are several ways that a microprocessor can use to access data. For in-
stance, we can include the data directly as the operand of a MOVLW instruc-
tion (move literal to W):
MOVLW W, 0x3F
Here we are assigning the hexadecimal 0x3F to the register W. This is called
Immediate Addressing.
We can also specify in which memory address the data is using a MOVWF
instruction (move content of W register to memory position specified by the
adddress):
MOVWF 0x3F
MOVLW 0x0C
MOVWF FSR
CLRF INDF
Here we have assigned the value 0x0C to FSR. When we send an instruction
to clear INDF, the microprocessor is actually clearing whatever is in memory ad-
dress 0x0C. This is called indirect addressing. The three addressing mechanisms
detailed here are shown in Fig. 9.
Some microprocessors offer other memory addressing modes such as indexed
and stacked addressing, but these are out of the scope of this text.
8
IMMEDIATE DIRECT INDIRECT
W = 0xA5 W = 0x3F
[0x3F] = 0x00
Figure 9: Immediate, direct and indirect addressing showing the contents of the
registers and memory.
There can be more than one memory element. Moreover, even if there was
only one memory element, we could need more bits for addressing it completely
than our bus allows. In such cases, the logical memory address can be segmented
in several banks. Thus, for accessing a memory position we first must specify
which memory bank we are interested in and then the offset within that bank.
This is called memory segmentation. You may already have encountered a mes-
sage “segmentation fault” in your personal computer. This is typically caused
by a program trying to access an position within a bank that is not allowed.
9
PIC Architecture
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.
Abstract
In this lesson we will review digital electronics and begin studying
processor architectures.
Keywords— Microcontrollers; Microprocessors; PIC.
1 Architecture
The architecture of microcontroller PIC16F877A is shown in Fig. 1
This RISC architecture has a total of 35 instructions that are shown in the
following table.
For this instruction set, f is any memory location, W is the working register,
b is the bit address within the register, d is the destination bit (0: W, 1: f), C
is the carry/borrow bit of the STATUS register, DC is the digit carry bit of the
STATUS register, and Z is the zero bit of the STATUS register.
The memory of this microcontroller is segmented in 4 banks that contain
specific registers. These are listed in Table 2.
In order to switch banks, we must set the appropriate bits in the STATUS
register at 03h, 83h, 103h or 183h depending on the current active bank.
The STATUS register is composed of the bits described on Table 3 and have
the respective interpretations:
IRP (bit 7) is the Register Bank Select used for indirect addressing. 0 corre-
sponds to banks 0 and 1, and 1 corresponds to banks 2 and 3. Some PICs such
as the 16F8X do not use this bit and it should be maintained clear.
RP1:RP0 (bits 6:5) are the Register Bank Select used for direct addressing.
00 corresponds to bank 0, 01 corresponds to bank 1, 10 corresponds to bank 2
∗ creq@[Link]
1
13 Data Bus 8 PORTA
Program Counter
FLASH RA0/AN0
RA1/AN1
Program RA2/AN2/VREF-
Memory RAM
8 Level Stack RA3/AN3/VREF+
File RA4/T0CKI
(13-bit) Registers RA5/AN4/SS
Program
Bus 14 PORTB
RAM Addr 9
RB0/INT
Addr. MUX RB1
Instruction Reg.
RB2
7 Indirect
Direct Addr. 8 RB3/PGM
Addr.
RB4
FSR reg. RB5
RB6/PGC
STATUS reg. RB7/PGD
8
PORTC
RC0/T1OSO/T1CKI
3 MUX RC1/T1OSI/CCP2
Power-up
Timer RC2/CCP1
Instruction RC3/SCK/SCL
Oscillator
RC4/SDI/SDA
Decode Start-up Timer ALU RC5/SD0
&Control Power-on
8 RC6/TX/CK
Reset RC7/RX/DT
Timing Watchdog
W reg.
Generation Timer PORTD
OSC1/CLKIN Brown-out RD0/PSP0
OSC2/CLKOUT Reset RD1/PSP1
In-Circuit RD2/PSP2
Debugger RD3/PSP3
Low-Voltage RD4/PSP4
Programming Parallel Slave Port RD5/PSP5
RD6/PSP6
RD7/PSP7
PORTE
RE1/AN6/WR
RE2/AN7/CS
Timer0 Timer1 Timer2 10-bit A/D
Synchronous
Data EEPROM CCP1,2 USART
Serial Port
and 11 corresponds to bank 3. In PICs that only use RP0 such as the 16F8X,
RP1 should be maintained clear.
/TO (bit 4) is the Time-out bit. This is a read-only bit. It is 1 after power-up,
a CLRWDT instruction or a SLEEP instruction. 0 indicates that a WDT time-
out occurred.
DC (bit 1) is the Digit carry/borrow. It is the carry-out bit from the 4th low
order bit of the result.
C (bit 0) is the Carry/borrow. It is the carry-out bit from the most significant
bit of the result. For borrow, the polarity is reversed.
2
Table 1: Instruction set for PIC16.
INSTRUCTION DESCRIPTION FLAGS CLK
Data Transfer
MOVLW k W=k – 1
MOVWF f f=W – 1
MOVF f,d d=f Z 1
CLRW Clear W Z 1
CLRF f Clear f Z 1
SWAPF f,d Swap nibbles in f – 1
Data Transfer
ADDLW k W=W+k C, DC, Z 1
ADDWF f,d d=W+f C, DC, Z 1
SUBLW k W=k-W C, DC, Z 1
SUBWF f,d d=f-W C, DC, Z 1
ANDLW k W = W AND k Z 1
ANDWF f,d d = W AND f Z 1
IORLW k W = W OR k Z 1
IORWF f,d W = W OR f Z 1
XORLW k W = W XOR k Z 1
XORWF f,d d = W XOR f Z 1
INCF f,d f=f+1 Z 1
DECF f,d f=f-1 Z 1
RLF f,d Rotate left through carry C 1
RRF f,d Rotate right through carry C 1
COMF f,d d = NOT f Z 1
Bit-oriented
BCF f,b f[b] = 0 – 1
BSF f,b f[b] = 1 – 1
Program Control
BTFSC f,b Skip next if f[b] == 0 – 1(2)
BTFSS f,b Skip next if f[b] == 1 – 1(2)
DECFSZ f,d d = f - 1, skip if Z == 1 – 1(2)
INCFSZ f,d d = f + 1, skip if Z == 0 – 1(2)
GOTO k Go to address k – 2
CALL k Call subroutine – 2
RETURN Return from subroutine – 2
RETLW k Return with W = k – 2
RETFIE Return from interrupt – 2
Other
NOP Does nothing –” 1
CLRWDT Clear watchdog timer TO=1, PD=1” 1
SLEEP Enter sleep mode TO=1, PD=0” 1
3
Table 2: Memory banks for the PIC16 microcontroller.
Bank 0 Bank 1 Bank 2 Bank 3
Addr. Name Addr. Name Addr. Name Addr. Name
00h INDF 80h INDF 100h INDF 180h INDF
01h TMR0 81h OPTION REG 101h TMR0 181h OPTION REG
02h PCL 82h PCL 102h PCL 182h PCL
03h STATUS 83h STATUS 103h STATUS 183h STATUS
04h FSR 84h FSR 104h FSR 184h FSR
05h PORTA 85h TRISA 105h WDTCON 185h SRCON
06h PORTB 86h TRISB 106h PORTB 186h TRISB
07h PORTC 87h TRISC 107h CM1CON0 187h BAUDCTL
08h PORTD 88h TRISD 108h CM2CON0 188h ANSEL
09h PORTE 89h TRISE 109h CM2CON1 189h ANSELH
0Ah PCLATH 8Ah PCLATH 10Ah PCLATH 18Ah PCLATH
0Bh INTCON 8Bh INTCON 10Bh INTCON 18Bh INTCON
0Ch PIR1 8Ch PIE1 10Ch EEDAT 18Ch EECON1
0Dh PIR2 8Dh PIE2 10Dh EEADR 18Dh EECON2
0Eh TMR1L 8Eh PCON 10Eh EEDATH 18Eh Not Used
0Fh TMR1H 8Fh OSCCON 10Fh EEADRH 18Fh Not Used
10h T1CON 90h OSCTUNE 110h GPR 96 bytes 190h GPR 96 bytes
.. ..
11h TMR2 91h SSPCON2 . .
12h T2CON 92h PR2
13h SSPBUF 93h SSPADD
14h SSPCON 94h SSPSTAT
15h CCPR1L 95h WPUB
16h CCPR1H 96h IOCB
17h CCP1CON 97h VRCON
18h RCSTA 98h TXSTA
19h TXREG 99h SPBRG
1Ah RCREG 9Ah SPBRGH
1Bh CCPR2L 9Bh PWM1CON
1Ch CCPR2H 9Ch ECCPAS
1Dh CCP2CON 9Dh PSTRCON
1Eh ADRESH 9Eh ADRESL
1Fh ADCON0 9Fh ADCON1
20h GPR 96 bytes A0h GPR 96 bytes
.. ..
. .
7Fh – FFh – 17Fh – 1EFh –
4
Table 3: STATUS register
bit description
7 IRP
6 RP1
5 RP0
4 /TO
3 /PD
2 Z
1 DC
0 C
2.1 Clock
The first thing to configure is the oscillator. Some microcontrollers have an
internal oscillator available. For the vast majority we have to setup an external
oscillator. The PIC microcontroller offer three possibilities that are illustrated
in Fig. 2.
For the external generator configuration not much has to be done. In the
hardware, we only need to connect the generator to OSC1 and leave OSC2 open.
In the software we need to tell the microprocessor to operate in HS, XT or LP.
For the crystal oscillator configuration, acceptable values for C1 and C2 are
given in Table 5. We also need to tell the microprocessor to operate in HS, XT
or LP.
For the RC oscillator configuration, Rext should be between 3 kΩ and 100
kΩ, and Cext should be higher than 20 pF. The frequency of operation will be
5
Mode Freq. C1 C2
LP 32 kHz 33 pF 33 pF
LP 200 kHz 15 pF 15 pF
XT 200 kHz 47-68 pF 47-68 pF
XT 1 MHz 15 pF 15 pF
XT 4 MHz 15 pF 15 pF
HS 4 MHz 15 pF 15 pF
HS 8 MHz 15-33 pF 15-33 pF
HS 20 MHz 15-33 pF 15-33 pF
6
3 Writing a Program
It is always a good practice to include comments in our code to make it readable.
We introduce a comment by beginning a line with a semicolon (;). Thus, our
software can begin somewhat like the following:
7
; [Link]
; CPU configuration
; RC oscillator
; Watchdog timer off
; Power-up timer on
processor 16f877a
include ă[Link]ą
config RC OSC & WDT OFF & PWRTE ON
3.1 Program
Next we must tell the compiler where the code will be. In our case let’s put
the code at the address 0:
; Program
org 0
; Select BANK 1
; BSF STATUS, RP0
bsf 0x03, 5
movlw B’00000000’
mofwf 0x85
bcf 0x83, 5
8
Binary: B‘0001010’
Octal: O‘772’
Decimal: D‘100’ or .100
Hexa: 0x9f or H‘9f’
ASCII: A‘C’ or ‘C’
9
a)
SLEEP PLL Fosc/4
Fosc
OSC1 OSC2
RS
C1 C2
b)
SLEEP PLL Fosc/4
Fosc
OSC1 OSC2
Fosc/4
c) SLEEP PLL
Fosc
OSC1
OSC2
Rext
10
Cext
Abstract
In this lesson we will study how to use the digital input and output
ports in microcontrollers.
1 Hardware
Imagine that we want to use a pin to output and input digital data to and into
a data bus. We may additionally want to use this pin to eventually input analog
data into an analog to digital converter (ADC). Therefore, it is convenient to
set the circuit responsible for the digital I/O into a tri-state configuration. We
can achieve this with PMOS and NMOS transistors as shown in Fig. 1. It works
according to the truth table described in Table 1. If register TRIS is set, then
the port enters in a tri-state configuration. Otherwise, data is sent to the pin if
a command to write the port is issued or data is read from the pin if a command
to read the port is issued.
We can see from this table that the logic function that drives the PMOS
transistor is simply:
∗ creq@[Link]
1
D Q
WR Q
PORT
D Q I/O Pin
WR Q
TRIS
DATA BUS
Q D
Q
RD
PORT
Figure 1: Internal circuit for digital I/O ports in the PIC microcontroller.
P “ P ORT ^ T RIS
P “ pP ORT ^ T RISq
(1)
P “ P ORT _ T RIS
P “ P ORT _ T RIS
The logic function that drives the NMOS transistor is simply P ORT ^
T RIS.
The diodes shown in the figure help to avoid electrostatic static discharges
(ESD). The latches store the values present in the data bus, the Schmitt trigger
buffer works as a signal conditioning stage to ensure that the input signal is
treated digitally by the circuit. Finally, the tri-state buffer is used to organize
the access to the data bus and avoid short circuits.
2 Software
The affected registers used in the digital I/O in the PIC microcontroller are
shown in Table 2.
First we must select the correct memory bank by setting RP0:1, then we
must configure the direction of each digital I/O pin by setting the TRIS register.
Finally, we must again select the correct memory bank and write or read the
appropriate port. We end up with a code similar to this:
2
bit STATUS PORT{A:E} TRIS{A:E}
(03h,83h) (05h:09h) (85h:89h)
7 IRP PORT7 TRIS7
6 RP1 PORT6 TRIS6
5 RP0 PORT5 TRIS5
4 /TO PORT4 TRIS4
3 /PDF PORT3 TRIS3
2 Z PORT2 TRIS2
1 DC PORT1 TRIS1
0 C PORT0 TRIS0
Software
org 0x00
bcf 0x03,6
bsf 0x03,5 ; Select bank #1: RP = 01.
movlw 0x0F ; Pins 4:7 are output, pins 0:3 are input.
movwf 0x85
movlw 0x20
movwf 0x05 ; Pin 5 is high.
3
Interrupts
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.
October 2, 2017
Abstract
In this lesson we will study how to handle interrupts in microcontrollers.
1 Introduction
Imagine that you need to follow an event and whenever it happens you take an appropriate action. One way of
doing this is my constantly polling the agent responsible for this event to check if it has started. This, however,
takes significant computing resources from a CPU that could be doing something else. A better way for doing this
is by asking the agent to warn the CPU whenever it happens. This is called an interrupt. One example in personal
computers is when the keyboard is pressed and it sends a signal to the CPU to process this event. There can be,
nonetheless, interrupts also caused by software. For instance, the processor may start a procedure to write some
data to an external memory and then generate an interrupt when it is done.
2 Hardware
The circuit responsible for handling interrupts in the PIC microcontroller is shown in Fig. 1 It is possible to block
all interrupts by resetting the General Interrupt Enable register (GIE). If this register is set, then both high and
low priority interrupts will be accepted by the CPU. The Peripheral Interrupt Enable register (PEIE) enables or
disables the low priority interrupts. Both the low and high priority interrupts have an enable register (E) and a flag
register (F). High priority interrupts are shown in Table 1, whereas low priority interrupts are shown in Table 2.
Flag Description
T0IF TIMER0 overflow interrupt.
INTF Universal external interrupt through pin RB0.
RBIF Interrupt caused by a change of state in one of RB4:7.
3 Software
The interrupt flags and enable bits can be accessed by the registers listed on Table 3. The memory organization
of the PIC microcontroller has two special positions. The Reset Vector is the position where the program counter
points to after a reset is placed. This vector is located at 00h in the program memory. The Interrupt Vector is
the position where the program counter points to after an interrupt is called. This vector is located at 04h in the
∗ creq@[Link]
1
Low Priority
EEIF
EEIE
PSPIF
PSPIE High Priority
ADIF
ADIE T0IF
T0IE
RCIF
RCIE INTF
INTE 4
TXIF Wake-up
RBIF (if sleeping)
TXIE
RBIE
SSPIF 11
Interrupt
SSPIE GIE
PEIE
CCP1IF
CCP1IE
TMR2IF
TMR2IE
TMR1IF
TMR1IE
CCP2IF
CCP2IE
BCLIF
BCLIE
Flag Description
EEIF Writing to EEPROM or Flash memories has completed.
PSPIF Reading/writing to Parallel Slave Port (PSP) - PORTD has completed.
ADIF A/D conversion has completed.
RCIF USART has received information through RCREG register.
TXIF TXREG register is empty and USART is ready to transmit data.
SSPIF Interrupt caused by the Master Synchronous Serial Port (MSSP) module.
CCP1IF Interrupt caused by the Capture/Compare module.
TMR2IF End of counting by TIMER2.
TMR1IF Overflow of TIMER1.
CCP2IF Interrupt caused by the Capture/Compare module.
BCLIF Interrupt caused by the MSSP module.
program memory. Now, in order to use interrupts we must write appropriate commands in these two positions. One
possibility is to write ‘goto’ instructions to move the program counter to a specific subroutine. This is shown below:
org 0x00
goto Main ; Start at Main.
org 0x04
goto Interrupt ; Go to Interrupt after an interrupt call.
Now at the ‘Main’ subroutine we must configure the appropriate registers to handle the interrupts. So let’s say
we want to be interrupted only by a signal at RB0. We must set this pin as input and also enable interrupts.
Therefore, we have:
2
Bit INTCON PIE1 PIR1 PIE2 PIR2
(0Bh - All Banks) (8Ch - Bank 2) (0Ch - Bank 1) (8Dh - Bank 2) (0Dh - Bank 1)
7 GIE PSPIE PSPIF – –
6 PEIE ADIE ADIF CMIE CMIF
5 T0IE RCIE RCIF – –
4 INTE TXIE TXIF EEIE EEIF
3 RBIE SSPIE SSPIF BCLIE BCLIF
2 T0IF CCP1IE CCP1IF – –
1 INTF TMR2IE TMR2IF – –
0 RBIF TMR1IE TMR1IF CCP2IE CCP2IF
movlw 0x01
movwf 0x85 ; RB0 is input.
Finally, we must write the interrupt subroutine. Here we have to check what caused the interrupt, reset the
corresponding flag and treat the event:
3
Timers & Counters
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.
Abstract
In this lesson we will study how to use timers and counters in micro-
controllers.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital; Timer.
1 Timer0
PIC has the circuit shown in Fig. 1 that is used for timer/counter 0.
0
fosc/4
1
1 2 CYCLE
DELAY
T0CLK 0
PRESCALE
TMR0
7 6 5 4 3 2 1 0
In PIC, the interrupt vector is located in the code memory position 0x04.
The interrupt vector is an instruction that the microcontroller executes every
∗ creq@[Link]
1
time an interruption occurs. Therefore, the first thing we must to do is to place
a ‘goto’ command in that position:
org 0x00
goto init
org 0x04
goto routine
Next, we must configure the circuit to work as a timer. For this, firstly T0CS
has to be set to 0. Next we must set the frequency of operation by setting the
PS registers. By setting PSA, our oscillator will work with a quarter of the
external oscillator. On the other hand, we can use fractions of this frequency
by resetting PSA and setting PS2:PS0 according to Table 1.
Let’s say that we want the timer to operate at fosc /16. Then OPTION REG
has to be B‘00000011’. Next, we must enable the microcontroller to accept in-
terrupts related to this timer. We can do this in PIC by first setting the timer
0 overflow interrupt enable register (T0IE). The code now evolves to:
org 0x00
goto init
org 0x04
goto routine
init: movlw B‘00000011’
movwf OPTION REG
movlw B‘00100000’
movwf INTCON
Now, the timer 0 overflow flag register (T0IF) will set every time TMR0
transits from 0xFF to 0x00 and the program will call the sub-routine located at
routine. We can do a further adjustment to the frequency by always starting
TMR0 with a specific value, let’s say 0x10. Also, we must enable the micropro-
cessor to accept interrupts in general by setting global interrupt register (GIE).
We end up with:
2
org 0x00
goto init
org 0x04
goto routine
init: movlw B‘00000011’
movwf OPTION REG
movlw B‘00100000’
movwf INTCON
movlw 0x10
movwf TMR0
bsf INTCON, 7
main: goto main
2 Timer1
Timer 1 on PIC can be used as: i ) a synchronous timer, ii ) a synchronous
counter, or iii ) as an asynchronous counter.
Independent on the mode of operation, the general program can be:
org 0x00
goto Main ; Go to main function.
org 0x04
goto IVEC ; Go to interrupt vector.
Main:
call CFG XX ; Configure appropriate mode of operation.
call CFGI ; Enable interrupts.
...
For all configurations, the prescaler can be set to 1:1 (00), 1:2 (01), 1:4 (10),
or 1:8 (11).
Synchronous Timer
3
T1OSCEN
0
fosc/4
1 CCP
T1OSC PRESCALE
1 TMR1
CLR
0
SINC: TMR1H TMR1L
DET
7 6 5 4 3 2 1 0
TMR1L
0x0E BANK 0
TMR1H
0x0F BANK 0
CFG ST:
bcf T1CON, TMR1CS ; Select f osc/4 as source.
bcf T1CON, T1CKPS1
bcf T1CON, T1CKPS0 ; Prescale 1:1.
bsf T1CON, T1SYNC ; Synchronization has no effect.
bsf T1CON, TMR1ON ; Enable TMR1.
return
Synchronous Counter
4
CFG SC:
bcf T1CON, T1OSCEN ; Turn off the T1 oscillator.
bsf T1CON, TMR1CS ; Select the counter as source.
bcf T1CON, T1CKPS1
bcf T1CON, T1CKPS0 ; Prescale 1:1.
bcf T1CON, T1SYNC ; Synchronize counter with internal oscillator.
bsf T1CON, TMR1ON ; Enable TMR1.
return
Asynchronous Counter
CFG SC:
bsf T1CON, T1OSCEN ; Turn on the T1 oscillator.
bsf T1CON, TMR1CS ; Select the counter as source.
bcf T1CON, T1CKPS1
bcf T1CON, T1CKPS0 ; Prescale 1:1.
bsf T1CON, T1SYNC ; Do not synchronize counter with internal oscillator.
bsf T1CON, TMR1ON ; Enable TMR1.
return
CFGI:
clrf TMR1L ; Initial value for TMR1.
clrf TMR1H
call BANK2 ; PIE is on bank #2.
bsf PIE1, TMR1IE ; Enable TMR1 interrupts.
bsf INTCON, PEIE ; Enable low priority interrupts.
bsf INTCON, GIE ; Enable general interrupts.
return
5
IVEC:
call BANK1 ; PIR is on Bank #1.
btfss PIR1, TMR1IF ; TMR1 interrupted ?
retfie
bcf PIR1, TMR1IF
...
call BANK0 ; TMR1 is on Bank #0.
bcf T1CON, TMR1ON ; Stop counter temporarily.
clrf TMR1L ; Restart TMR1 with a specific value.
clrf TMR1H
bsf T1CON, TMR1ON
retfie
If we want to read TMR1 in some place of the code we must pay attention
to the fact that between reading the low and high bytes, the counter may roll
over. Therefore a good way of reading the registers is:
3 Timer 2
Timer 2 is an 8-bit counter with a single source. It has both pre- and post-
scalers and overflows every time it reaches the same value indicated by the
Period Register (PR2). When this happens, TMR2 is reset and an interruption
is called through PIR1:TMR2IF. This is a counter simple to use and is commonly
associated with pulse width modulation (PWM) as we will soon see. A simple
way to program it is:
6
RESET
PRESCALE
fosc/4 TMR2
1:1, 1:4, 1:16
POSTSCALE
TMR2IF
1:1 - 1:16
PR2
2
4
T2CKPS<1:0> TOUTPS<3:0>
7 6 5 4 3 2 1 0
TMR2
0x11 BANK 0
PR2
0x92 BANK 1
...
clrf T2CON ; Pre and postscale are 0. Counter is disable.
clrf TMR2 ; Start counter with 0.
bsf T2CON,TMR2ON ; Start counter.
call Bank1
bsf PIE1, TMR2E ; Enable interrupts from TMR2.
movlw 0x1A ; Value to be compared to.
movwf PR2
call Bank0
bsf INTCON, PEIE ; Enable peripheral interrupts.
bsf INTCON, GIE ; Enable general interrupts.
...
IVET:
btfss PIR1, TMR2IF
retfie
bcf PIR1, TMR2IF
... ; TMR2 does not need to be cleared!
retfie
7
DT
vPWM
0 T
Figure 4: (red) Desired analog output, and (blue) PWM modulation. The inset
shows the concept of duty cycle: A pulse occupy only D% of a period T.
with a constant amplitude by modulating its duty cycle according to the analog
amplitude we want to obtain. Figure 4 illustrates this process.
If this signal is averaged, by an LC circuit, for example, we obtain:
"ˆ ˆ T #
DT
1
v̄ = vmax dt + vmin dt
T 0 DT
1 (1)
= [vmax DT + (1 − D)T vmin ]
T
= vmax D + vmin (1 − D)
Typically, vmin is 0. Therefore, v̄ = Dvmax and the output is directly propor-
tional to the duty cycle.
The software necessary to make the PWM work is very similar to that used
for Timer2. The first difference is that it does not use interrupts. Also, the
register CCP1CON has to be configured to operate as PWM by setting its bits
CCP1M3 and CCP1M2.
8
10 bits
R Q
RC2/CCP1
fosc/4
PRESCALE
TMR2
S Q
1:1, 1:4, 1:16
2
PR2
T2CKPS<1:0>
7 6 5 4 3 2 1 0
TMR2
0x11 BANK 0
PR2
0x92 BANK 1
CCPR1L
0x15 BANK 0
CCPR1H
0x16 BANK 0
The period of the PWM will be (PR2+1)·4·Tosc ·PS, whereas the duty cycle
will be CCPR1L:CCP1CON<5:4> ·Tosc ·PS. The CCPR1L and CCP1CON<5:4>
registers can be written at any time, but will only be fetched to CCPR1H after
the next time TMR2 = PR2.
9
Analog to Digital Converters
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.
Abstract
In this lesson we will study how to use analog to digital converters in microcontrollers.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital; ADC.
1 Sigma-Delta Converters
The most used analog-to-digital converters (ADC) have the so-called Sigma-Delta architecture. This
is structure is shown in Fig. 1 and is composed basically of five blocks. First the difference (delta)
between the input signal and a reference signal is obtained. This difference signal is integrated so that
an average is computed. This average then goes to an 1-bit ADC that can be fabricated with basically
a comparator and a flip-flop. This 1-bit signal then is used as the the input of a digital-to-analog
converter (DAC) and its output is the initial reference signal. Because of the negative feedback, the
input signal and the average output of the DAC will be approximately the same. Therefore, the number
of times the ADC outputs 1 will be proportional to the input signal. Thus, the only block missing is
a digital counter to count the number of 1’s in a period. The oversampling also has the advantage of
reducing the noise amplitude and pushing it to higher frequencies where it is filtered by the integrator.
This process is known as noise shaping.
2 Aliasing
If there is any component in the input signal that contains frequencies higher than the allowed band-
width, they will be mapped by the converter to the appropriate range. The effect is known as aliasing
and distorts the desired signal to be digitally converted. One example of this effect is the appearance
of a wheel rotating slowly or backwards, or even a stroboscopic effect. In order to avoid it, anti-aliasing
filters are used at the input of the ADC converter. This is a filter that allows only frequencies below
the Nyquist frequency to input the converted. For instance, if we are interested in audio frequencies (f
leq24 kHz), then the sampling rate has to be at least 48 samples per second and a filter cutting at 24
kHz has to be included in the input.
3 Circuit
PIC has the circuit shown in Fig. 2 that is used for the analog to digital converter (ADC). For converting
an analog value into digital we must specify the range within this voltage is. The maximum voltage is
∗ creq@[Link]
1
1 bit ADC
vi(t)
∫ D Q
counter
clk Q
vd(t)
oversampling
1 bit DAC
` ´
described by Vref , and the minimum voltage is Vref . For a converter that works with n bits, we can
achieve a resolution of:
` ´
Vref ´ Vref
R“ . (1)
2n ´ 1
` ´
For example, if Vref “ `5V, Vref “ 0V, and we use a 10 bit ADC, we get a resolution of:
5´0 5
R“ V “ “ 4.8876 mV. (2)
210 ´ 1 1023
This behavior is illustrated in Fig. 3
4 Registers
There are basically four registers involved with the AD converter as depicted in Fig. 2: ADRESH,
ADRESL, ADCON0, and ADCON1. Let’s analyze each one of them:
ADON (ADC On bit - ADCON0[0]): 1 = ADC module is operating, 0 = ADC module is shut-down
and consuming no energy.
GO/DONE (ADC Conversion Status bit - ADCON0[2]): 1 = ADC conversion in progress, 0 = ADC
conversion not in progress and automatically cleared when the conversion is done.
CHS (Channel Select - ADCON0[3:5]): Selects the input multiplexer for an AD conversion.
2
VREF+
ADCS2:0 PCFG3:PCFG
RE2/AN7 111 GO/DONE
RE1/AN6 110
RE0/AN5 101
RA5/AN4 Justification
RA3/AN3/VREF+
100
011
A/D ADFM
RA2/AN2/VREF- 010 ADRESH ADRESL
RA1/AN1 001 ADON 0x1E (0) 0x9E (1)
RA0/AN0 000
PCFG3:PCFG
VREF-
CHS2:CHS0
RW RW RW RW RW RW RW
7 6 5 4 3 2 1 0
Figure 2: Analog to digital converter circuit inside the PIC microcontroller, and corresponding registers
(green).
Table 1: AD Conversion Clock. (Tosc is the time period of the device clock.)
ADCS 2:0 Operation Maximum Freq.
000 2 Tosc 1.25 MHz
100 4 Tosc 2.50 MHz
001 8 Tosc 5.00 MHz
101 16 Tosc 10.00 MHz
010 32 Tosc 20.00 MHz
110 64 Tosc 20.00 MHz
x11 RC TAD „2-6 µs.
PCFG (ADC Configuration Control - ADCON1[0:3]): Configure the hardware pins as analog inputs,
digital I/O’s or as voltage references according to Table 2.
ADFM (ADC Result Format Select bit): The result of an ADC conversion has 10 bits. Setting ADFM
results in the 6 Most significant bits of ADRESH being 0 (000000XX XXXXXXXX). Resetting ADFM
results in the least significant bits of ADRESL being 0 (XXXXXXXX XX000000).
3
Digital
Output R
111
110
101
100
011
010
001
000
Analog
- + Input
VREF VREF
5 Software
Let’s say we want to have two analog input, the lowest input voltage is zero and the maximum voltage
is given externally. Therefore, according to Table 2, we must set PCFG3:0 as 0101. Our operating
frequency is 20 MHz, thus Tosc is 5 ˆ 10´8 s.
Since the ADC converter requires at least 1.6 µs for a conversion, we have 1.6 ˆ 10´6 {5 ˆ 10´8 “ 32.
Thus, according to Table 1, ADCS2:0 should be set as 010.
It is more convenient for my application that there are 0’s in the most significant byte. Therefore,
ADFM should be 0.
With this information, the ADCON1 register should be configured to 00000101 = 0x05.
Let’s start measuring channel 0, so CHS2:0 should be 0x00. Finally, let’s turn the ADC on, so
ADON should be 1. Therefore, ADCON0 register should be configure to 10000001 = 0x81.
Our code should then be:
org 0x00
4
Table 2: ADC Configuration Control (A: Analog input, D: Digital I/O).
PCFG 3:0 AN 7:4 AN3 AN2 AN 1:0 VREF+ VREF-
0000 AAAA A A AA VDD VSS
0001 AAAA VREF+ A AA AN3 VSS
0010 DDDA A A AA VDD VSS
0011 DDDA VREF+ A AA AN3 VSS
0100 DDDD A D AA VDD VSS
0101 DDDD VREF+ D AA AN3 VSS
011x DDDD D D DD – –
1000 AAAA VREF+ VREF- AA AN3 AN2
1001 DDAA A A AA VDD VSS
1010 DDAA VREF+ A AA AN3 VSS
1011 DDAA VREF+ VREF- AA AN3 AN2
1100 DDDA VREF+ VREF- AA AN3 AN2
1101 DDDD VREF+ VREF- AA AN3 AN2
1110 DDDD D D DA VDD VSS
1111 DDDD VREF+ VREF- DA AN3 AN2
6 Comparator Module
The analog inputs can also be used in two comparator modules as shown in Fig. 4. The comparators
can be used in eight different configurations controlled by the CM bits of the CMCOM register. The
configurations are given in Table 3.
The nine possible configurations are shown in Fig. 5. All input pins not used are set as digital.
5
CM2:CM0/CIS
AN0
CM2:CM0
C1OUT RA4
AN3
CM2:CM0/CIS
VREF
C2OUT RA5
AN2
CM2:CM0
AN1
CM2:CM0/CIS
7 6 5 4 3 2 1 0
6
CM2:0 = 000, CIS = X CM2:0 = 011, CIS = X CM2:0 = 110, CIS = 0
VREF
C2OUT C2OUT C2OUT
AN1 AN2
AN0 AN0
AN2
C2OUT C2OUT RA5 C2OUT
AN1 AN1
7
CVREN
8R
16x
R
VREF
RA2/AN2/VREF-
CVRR 8R CVROE
CVR3:0
7 6 5 4 3 2 1 0
8
Digital PID Controller
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.
Abstract
In this lesson we will learn how to implement a PID controller in a 8-bit microcontroller using
integer math.
Keywords— PID controller.
1 Introduction
A PID controller is composed of three components: i) one that gives an output proportional to the
difference between a setpoint and the actual output (error), ii) one that gives an output integral to
this difference, and iii) another that gives an output differential to this difference.
For the error we have:
y(t) = kp e(t)
= kp x(t) − kp y(t)
y(t)(1 + kp ) = kp x(t) (2)
kp
yn = xn
1 + kp
yn = ξp xn (3)
For the integral component we have:
ˆ t
y(t) = ki e(t)dt
0
ˆ t
(4)
= ki (x(t) − y(t))dt
0
yn = ki ∆T Sn ,
∗ creq@[Link]
1
for X
Sn = (xn − yn )
n (5)
Sn = Sn−1 + xn − yn .
Therefore,
yn = ki ∆T (Sn−1 + xn − yn )
yn (1 + ki ∆T ) = ki ∆T Sn−1 + ki ∆T xn
(6)
ki ∆T
yn = (Sn−1 + xn )
1 + k i ∆T
yn = ξi (Sn−1 + xn )
Sn = Sn−1 + xn − yn (7)
S−1 = 0
∂e(t)
y(t) = kd
∂t
∂
= kd (x(t) − y(t))
∂t
∂x(t) ∂y(n)
= kd − kd
∂t ∂t
kd kd
yn = [xn − xn−1 ] − [yn − yn−1 ] (8)
∆T ∆T
∆T
yn = xn − xn−1 − yn + yn−1
kd
∆T
yn + 1 = yn−1 + xn − xn−1
kd
kd
yn = (yn−1 + xn − xn−1 )
kd + ∆T
1.1 ξ Factors
The ξ factors are given by:
kp
ξp = ,
1 + kp
ki ∆T
ξi = , (10)
1 + ki ∆T
kd
ξd = .
∆T + kd
One interesting aspect of these factors is that they are restricted to values between -1 and 1. Therefore,
we can write them as:
ξp = αp /K0 ,
ξi = αi /K0 , (11)
ξd = αd /K0 ,
2
where K0 can be conveniently chosen to be 2n , and this would imply just n bit shifts. Also, the α
factors are now simple integers.
Finally we get an expression for the PID controller:
αp + αi + αd αd αi
yn = xn + (yn−1 − xn−1 ) + Sn−1
K0 K0 K0
Sn = Sn−1 + xn − yn (12)
S−1 = 0
Now using a 2-complement representation and operations for bit shift, addition and multiplication
we can implement the PID controller.
3
Serial Communication
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.
Abstract
In this lesson we will study how the serial coomunication of the PIC microcontroller works.
Keywords— PIC, Serial, USART.
1 USART
The heart of the Universal Synchronous/Asynchronous Receiver-Transmitter (USART) is a shift register
that converts a set of bits of a word into a sequential set of bits to be transmitted or the other way
around. Once in a serial format, the communication can be simples if it is unidirectional, one equipment
only sends information and the other only receives. It can also operate in half duplex mode where there is
also only one channel available and both equipments take turns in sending and receiving information in
a master/slave configuration. This protocol is also known as synchronous. Finally, serial communication
can also happen in a full duplex mode wherein both devices are able to send and receive information
at the same time. This is also known as asynchronous.
The serial protocol maintains its line typically in a high state to indicate that the line is active. To
start a communication, first a start bit is sent (low state). Next, 8 data bits are transmitted from the
LSB to the MSB. After that, some devices implement an extra parity bit. Finally, there is a stop bit to
signal the end of transmission in a low state.
The PIC microcontroller operates with 1 start bit, 8 data bits, an optional extra bit that can be
used for parity check via software, and a stop bit. This is slightly different from the standard RS232
where there is only 8 data bits and no parity bit. In this last case, for instance, it takes exactly 10 bits
to transmit a word. For a bit rate B, the word transmission rate is consequently B/10.
Furthermore, the PIC microcontroller serial module operates in a non-return to zero level (NRZ-L)
protocol where the logic level 1 corresponds to VDD and the the logic level 0 corresponds to GND. Both
occupy the whole period of the clock and there is no rest condition. Again, this is slightly different from
the RS232 protocol where the logic 1 corresponds to a voltage within +5V and +12V, and the logic 0
corresponds to a value within -12V and -5V. This is typically overcome with level converters such as
the MAX232.
The main registers associated with the USART operation are:
1
In order to use the PIC USART, the first thing that we must do is specify whether it will operate
in synchronous or asynchronous mode.
The TX pin is shared with PortC, so we must set it to work with the USART. Next, we must turn the
USART on and enable transmission.
0x18.
The PIC microcontroller allows us to use a ninth bit for parity check. However, the check has to be
done by the user in software.
At this point we can write the word to be sent to the USART and wait until it is fetched to its
internal register TSR.
2
movlw WORD
movwf TXREG ; Send word to be transmitted.
It is also possible to check if the data was transmitted by the USART by reading TXSTA:TRMT.
Next we must configure the PORTC, turn the USART, say if we want a ninth bit and enable
reception.
Finally, we can either set an interrupt vector or pool the USART to wait for the data.
The received data will be on RCREG and on RCSTA:RX9D. If an error occurred, we must also
clear RCSTA:RCEN. This could be for example an overrun error indicated at RCSTA:OERR.
3
Table 2: Registers related to an asynchronous read.
address word. The code is very similar, but we must also tell the microcontroller that we are interested
in this mode by setting the ADDEN register.
movf RCREG
xorwf ADDRESS,W ; Is it my address?
btfss STATUS,Z
goto NOPE
bcf RCSTA, ADDEN ; Ok, I’ll receive data now, not only addresses.
..
.
2 Synchronous Mode
SYNC = 1 CSRC = 1: Master, 0: Slave Reception: SREN = 1 (single word) ou CREN (continuous
word)
TX becomes Clock RX becomes Data
4
3.1 SPI
The SPI mode was developed by Motorola in the 1980’s. It allows for transmitting synchronously 8
bits of data both in and out of the microcontroller. It uses four wires for transmitting data. The
master sends the clock signal through the serial clock (SCLK) line and data through the master output
slave input (MOSI) line. The slave sends data through the master input slave output (MISO) line.
Moreover, there is an slave activation bit through slave select (SS) line.
In order to use the MSSP module in the SPI mode we must specify whether we will use the micro-
controller in master mode or in a slave mode. This is controlled by the SSP Mode Select (SSPMx3 : 0y)
bits of the MSSP control register (SSPCON1). Table 3 shows the possible configurations:
SSPMx3 : 0y Configuration
0000 Master Mode, clock = Fosc {4.
0001 Master Mode, clock = Fosc {16.
0010 Master Mode, clock = Fosc {64.
0011 Master Mode, clock = TMR2 Out/2.
0100 Slave Mode, SS pin enabled.
0101 Slave Mode, SS pin disabled.
In this mode, the transmission is performed bitwise with the MSB being the first to be transmitted.
Furthermore, during communication the master sends a bit that has to be read by the slave and then
it sends a bit that has to be read by the master. This has to occur even it the transmission is purely
unidirectional. This happens in a circular configuration where bit after bit the registers of the master
and the slave devices exchange their words.
Other parameters can be set. For example, we can specify the the polarity of the idle state through
the SSPCON1:CKP register, we can enable or disable the SSP through the SSPCON1:SSPEN
register, and set if we want the transmission to occur during the transition from low to high or the
other way around through the SSPSTAT:CKE register. The completion of a reception can be verified
through the SSPSTAT:BF register, and the data is read from or written to the SSPBUF register.
The complete specification of the registers is shown in Table 4.
In slave mode, the SSPIF flag is raised when the last bit of a word is received.
3.2 I2 C
A competitor of SPI is the Inter-Integrated Circuit (I2 C) invented in 1982 by Philips Semiconductors.
The main advantage over SPI is the use of only two lines: a Serial Data Line (SDA) and a Serial Clock
Line (SCL). Both lines are driven by open drain MOS transistors and thus have to be pulled up with
resistors („ 4.7 K). It operates within 3.3 V and 5 V, and can operate up to 400 kbit/s. The biggest
drawback of this mode is that in order to use fewer lines, its programming is more complex.
5
Transmitting data with the i2 c protocol is based on the concept of condition events. For example,
the equivalent of a start bit is the start condition (S) that is represented by the SDA transitioning
from high to low while the SCL is kept high.
The stop condition (P) is characterized by the opposite path. The SDA transitions from low to
high while the SCL is kept high.
There is also an acknowledge condition (A) where the device brings SDA low during the 9th
clock pulso of SCL. This can also be a negative acknowledge condition (N) if the device sets the
SDA up instead.
Finally, it is possible to send a restart condition (R), which is a stop condition followed by a start
condition. The SCL is kept high and SDA transitions from low to high. Then, SCL is lowered, set up
again and SDA transitions to low. Finally, SCL goes back to low.
Writing
For writing data on a device, the microcontroller must have the data bit valid on the raising edge
of the SCL. The communication starts with the microcontroller emitting an S condition followed by a
control in byte to tell the controlled device what it should do. The device answers with an A condition.
Next, the microcontroller sends an address byte. Again the controlled device answers with an A. The
microcontroller then emits the data, which is once again answered by an A. The communication is
finalized with the controller sending a P.
Reading
For reading a device, the microcontroller sends an S condition followed by the control in byte. The
device answers with an A. Next the address by is sent and answered with another A. Next, the mi-
crocontroller sends an R and a control out byte. The device answers with an A and the data. The
microcontroller answers with an N condition and a P condition to finalize the communication.
I2 C allows for an interesting situation to occur. If the device receives a command but is not ready
to transmit the data, it can hold the SCL low until it is ready. This is known as clock stretching.
The LSB of the control byte is 0 for writing and 1 for reading. Words between 0x00 to 0x07 and
0x78 to 0x7F are reserved.