You are on page 1of 18

EET484 Microcontroller Lecture 8 (Part 2)

(Adapted from Prof. Huangs lecture notes)


Programmable Counter Array
1. PCA provides enhanced timer functionality while needs less CPU intervention than
the standard timers/counters. It consists of a dedicated 16-bit counter/timer and six
16-bit capture/compare modules. The clock source can be selected from one of the six
sources. Each capture/compare module may be configured to operate independently
in one of six modes:
edge-triggered capture
software timer
high-speed output (toggle)
frequency output
8-bit PWM
16-bit PWM

1.1 The PCA 16-bit Timer/Counter serves as the time base of all PCA operations.
It consists of two 8-bit counters PCA0H and PCA0L.
Reading the PCA0L register automatically latches the value of PCA0H into a
snapshot register, the following read of PCA0H accesses this snapshot register.
This ensures an accurate reading of the entire 16-bit timer.
The rollover of PCA0 timer from 0xFFFF to 0x0000 sets the CF flag.
The operation of the PCA timer is controlled by the PCA0CN (enables timer to
count, keeps track of the capture/compare flags of all PCA channels), and
PCA0MD register (selects clock source, enables/disables PCA interrupts,
enable/disable PCA module when CPU is in the idle state.)

1.2 Capture/Compare Modules


This module can perform these operations:
16-bit capture, positive-edge (rising-edge) triggered
16-bit capture, negative-edge (falling-edge) triggered
16-bit capture, both positive-edge and negative-edge triggered.
16-bit software timer
16-bit high speed output
frequency output
8-bit pulse width modulation
16-bit pulse width modulation
Each PCA module has a mode register (PCA0CPMn) to select which function to
perform in Figure 8.15.
The ECCFn bit enables the PCA interrupt when a modules event flag is set.
Each module has an event flag CCFn in the PCA0CN in Figure 8.13, which will
be set when a capture event, software timer, or high speed output event occurs.
Each module has a pair of 8-bit compare/capture registers called
PCA0CPHn:PCA0CPLn associated with it.
PCA0CPHn:PCA0CPLn stores the timer value when a capture event occurred
or a compare event should occur.
A summary of the PCA0CPMn settings for entering each PWM mode is
summarized in Table 8.3.

Example 8.8 Configure PCA module 0 of the C8051F040 to capture the rising edge of
the signal applied to the CEX0 pin. Use SYSCLK 12 as the clock source of the timer.
Solution:
Three registers need to be programmed:
PCA0CN register:
The PCA counter must be enabled (CR = 1) and all flags should be cleared at the
beginning.
PCA0MD register:
This application does not care about watchdog function, nor counter idle control; Disable
both. Bits 3, 2, and 1 of the PCA0MD register should be set to 000 to select SYSCLK/12
as the PCA clock source. PCA overflow interrupt is not needed; Set the bit 0 to 0.
PCA0CPM register:
For module 0,
Bit PWM160 (bit 7): set to 0 (this bit is dont care)
Bit ECOM0 (bit 6): set to 0 to disable the comparator.
Bit CAPP0 (bit 5): set to 1 to capture the rising edge.
Bit CAPN0 (bit 4): set to 0 to disable falling edge capture.
Bit MAT0 (bit 3): set to 0 to disable module 0 comparator.
Bit TOG0 (bit 2): set to 0 so that CEX0 pin will not toggle when PCA counter
matches the compare/capture registers of module 0
Bit PWM0 (bit 1): set to 0 to disable pulse modulation output.
Bit ECCF0 (bit 0): cleared to disable CCF interrupt.
Therefore, the value 20H should be written into the PCA0CPM0 register. The following
instructions accomplish the intended configuration:
PCA0CN
= 0x40;
PCA0MD
= 0;
PCA0CPM0
= 0x20;
1.3 Edge-Triggered Capture Mode
The PCA copies the 16-bit timer into the capture register at the moment that the
selected edge on the CEXn pin is detected.
This action can be used to measure period, pulse width, duty cycle, and phase
difference of signals.
The signal edge that triggers the capture action is selected by setting or clearing
the CAPPn and CAPNn bits in the PCA mode register.

Measure the Signal Pulse Width Using Capture Mode

Let
ovcnt
edge1
edge2
diff

= the PCA timer overflow count


= the captured time of the first edge
= the captured time of the second edge
= edge2 edge1

Then the pulse width can be calculated using the following equations:
Case 1: edge2 edge 1
Pulse width = ovcnt 216 + diff
-- (8-7)
Case 2: edge2 < edge1
Pulse width = (ovcnt 1) 216 + diff -- (8-8)
Example 8.9 Suppose an unknown signal is connected to the CEX0 pin. Write a program
to measure the pulse width of this signal assuming that the system clock is generated by a
24-MHz external crystal oscillator.
Solution:
The settings of PCA0CN, PCA0MD, and PCA0CPM0 are as follows:
Configuration of PCA0CN:
Clear all the flags and enable PCA timer to run. Write the value 40H into PCA0CN.
Configuration of PCA0MD:
Choose SYSCLK 12 as the clock source of the PCA timer and enable PCA timer
overflow interrupt. Disable watchdog timer and choose to gate off the PCA timer
during idle mode. Write the value 81H into PCA0MD.

Configuration of PCA0CPM0:
Disable the comparator function, capture rising edge, disable match, disable toggling,
disable pulse width modulation, and disable capture interrupt. Write the value 20H into
the PCA0CPM0 register. Falling edge capture must be enabled after the rising edge has
been captured.
#include <c8051F040.h>
void pcaISR (void);
void sysInit (void);
unsigned char pwH, pwL,tovCnt;
unsigned long PulseWidth;
void main (void)
{
unsigned short t1,t2,t3;
sysInit();
SFRPAGE = 0;
tovCnt
= 0;
PCA0CN
= 0x00;
PCA0MD
= 0x81;
PCA0CPM0= 0x20;
IE
= 0;
CR
= 1;
while (!CCF0);
pwH
= PCA0CPH0;
pwL
= PCA0CPL0;

// switch to SFR page 0


// clear all PCA flags
// use SYSCLK/12 as the PCA timer clock input
// prepare to capture the CEX0 rising edge
// disable interrupt
// start the PCA timer
// wait for the arrival of the rising edge
// save the captured rising edge value
//

PCA0CPM0 = 0x10;
// prepare to capture CEX0's falling edge
CCF0
= 0;
// clear flags
CF
= 0;
EIE1
= 0x08;
// enable PCA0 timer overflow interrupt
EA
= 1;
// enable interrupt globally
while (!CCF0);
// wait for the arrival of the falling edge
EIE1
= 0;
// disable PCA interrupts
t1
= 256 * (unsigned short)pwH + (unsigned short)pwL;
t2
= 256 * (unsigned short) PCA0CPH0 + (unsigned short) PCA0CPL0;
t3
= t2 t1;
if (t2 < t1)
tovCnt--;
PulseWidth = (unsigned long) tovCnt * 65536 + (unsigned long)t3;
}
void sysInit (void)
{
SFRPAGE = 0x0F;
WDTCN = 0xDE;
WDTCN = 0xAD;
OSCXCN = 0x67;

// disable watchdog timer


// start external oscillator; 24 MHz Crystal

for (n = 0; n < 255; n++);


while ((OSCXCN & 0x80) == 0);
CLKSEL |= 0x01;

// delay about 1 ms
// wait for oscillator to stabilize
// switch to external oscillator

XBR0
= 0xF7;
// assign all peripheral function pins to port pins
XBR1
= 0xFF;
//
"
XBR2
= 0x5D;
//
"
XBR3
= 0x8F;
//
"
SFRPAGE = 0;
// switch to SFR page 0
SPI0CN
= 0x01; // enable 3-wire SPI
}
void pcaISR (void) interrupt 9
{
CF = 0;
// clear the CF flag
tovCnt++;
// increment PCA timer overflow count
}

1.4 16-bit Software Timer and High Speed Output (Toggle)


Software timer mode is also referred to as compare mode.
In compare mode, the PCA timer compares with the capture/compare register in
every clock cycle.
When PCA timer and the capture/compare register match, the CCFn bit is set.
There are three steps in using the software timer mode:
(a) Make a copy of the PCA timer value
(b) Add to this copy a value equal to the desired time delay
(c) Store the sum into the module compare registers (PCA0CPHn, PCA0CPLn)
Main applications:
Create time delays
Generate waveforms
Example 8.10 Write a C function that uses PCA module 0 to generate a time delay that is
a multiple of 10 ms assuming that fSYSCLK = 24 MHz.
Solution: Use SYSCLK/12 as the PCA clock source. The number of timer clocks
required to create 10-ms time delay is 20,000 (0x4E20).
void delayby10ms (unsigned char kk)
{
unsigned char i, temp, temp1;
temp = SFRPAGE;
SFRPAGE = 0;
PCA0MD = 0x80; // suspend PCA in idle mode and uses SYSCLK/12 as PCA clock
PCA0CPM0= 0x48;
// select software timer mode
PCA0CN = 0x00;
// disable PCA timer
for (i = 0; i < kk; i++){
temp1
= PCA0L;
PCA0CPH0= PCA0H + 0x4E; // create the 10 ms time delay
PCA0CPL0 = temp1 + 0x20;
if (CY)
// Does the express ion temp1 + 0x20 cause a carry?
PCA0CPH0++;
CCF0= 0;
// clear the capture/compare flag
CR = 1;
// Enable PCA0 timer
while(!CCF0);
CR = 0;
}

SFRPAGE = temp;
}

Example 8.11 Assume that there is a C8051F040 demo board running with a 24-MHz
crystal oscillator. Write a program that enables the PCA module 0 to generate a 1-kHz
digital waveform with 40% duty cycle.
Solution: A 1-kHz digital waveform with 40% duty cycle is shown in Figure 8.20.

The procedure for generating the specified waveform is as follows:


Step 1
Configure PCA module 0 to toggle mode and enable CCF0 interrupt.
Step 2
Use a register as a flag (called it hiORlo) to specify the delay to be used in the compare
operation. When hiORlo is 1, use 800 as the delay count. When hiORlo is 0, use 1200 as
the delay count.
Step 3
Make a copy of the PCA counter, add 800 to it, and store the sum in
CAPCPH0:CAPCPL0 register pair. Set hiORlo to 0 and stay in a wait loop.
Write an interrupt service routine that performs the following operations:
Step 1 Clear all PCA0 flags and check the hiORlo value.
Step 2
If dlyflag = 1
PCA0CPH0:PCA0CPL0 += 800;
dlyflag = 0;
otherwise
PCA0CPH0:PCA0CPL0 += 1200;
dlyflag = 1;
Step 3 Return from interrupt.
#include
#define
#define
#define
#define
#define
#define

<C8051F040.h>
HThi 0x03 // high interval delay count (800)
HTlo 0x20 //
"
LThi 0x04 // low interval delay count (1200)
LTlo 0xB0 //
"
HI 1
LO 0

void PCA0_ISR (void);


void sysInit (void);
unsigned char hiORlo;
unsigned char temp;

// prototype of PCA0 interrupt service routine


// system initialization function prototype
// flag to indicate high or low interval of the waveform
// used to check if a carry to high byte is needed

void main (void)


{
1 sysInit();
2
SFRPAGE = PCA0_PAGE;
3
PCA0CN = 0;
// clear all PCA0 related flag, disable PCA0 counter
4
PCA0MD = 0x80;
// stop PCA0 when idle, use SYSCLK/12 as PCA0 clock
5
PCA0CPM0= 0x4D; // select high-speed output mode, enable CCF0 interrupt
6
P1
|= 0x02;
// pull CEX0 to high initially
7
temp
= PCA0L;
8
PCA0CPH0= PCA0H + HThi;
9
PCA0CPL0 = PCA0L + HTlo;
10 if (temp > PCA0CPL0)
// is there a carry to the high byte?
11
PCA0CPH0++;
12 PCA0CN |= 0x40;
// enable PCA0 counter
13 hiORlo
= LO;
// next time use LT as delay
14 EIE1
|= 0x08;
// enable PCA0 interrupt
15 EIP1
|= 0x08;
// place PCA0 interrupt at high priority
16 EA
= 1;
// enable interrupt globally
17 while(1);
// wait for PCA0 interrupt
}
void sysInit(void)
{
unsigned char cx;
SFRPAGE = CONFIG_PAGE;
WDTCN = 0xDE; // disable watchdog interrupt
WDTCN = 0xAD; //
"
OSCXCN = 0x67;
// start external crystal oscillator
for (cx = 0; cx < 255; cx++);
while(!(OSCXCN & 0x80)); // wait for crystal oscillator to stabilize
CLKSEL |= 1;
// switch to external crystal oscillator as clock source
XBR2
= 0x5D;
// enable crossbar decoder, and assign I/O pins to all
XBR0
= 0xF7;
// peripheral signals
XBR1
= 0xFF;
//
"
XBR3
= 0x8F;
//
"
P1MDOUT = 0x07;
// enable CEX0 pin as output
SFRPAGE = SPI0_PAGE; // switch to SFR page where the SPI is in
SPI0CN
= 1;
// select 3-wire SPI (just to fixed I/O pin assignment)
}
void PCA0_ISR (void) interrupt 9
{
PCA0CN &= 0x40; // clear all PCA0 flags
temp = PCA0CPL0;
if (hiORlo == HI) {
PCA0CPH0 += HThi;
PCA0CPL0 += HTlo;
if (temp > PCA0CPL0)
// is there a carry to the high byte?
PCA0CPH0++;
hiORlo = LO;
}

10

else {
PCA0CPH0 += LThi;
PCA0CPL0 += LTlo;
if (temp > PCA0CPL0)
PCA0CPH0++;
hiORlo
= HI;

// is there a carry to the high byte?

}
}

1.5 PCA Frequency Output Mode


The CEXn (n = 0,,5) pin toggles whenever PCA0Ls value matches that in
PCA0CPLn.
On a match, the value of the PCA0CPHn is added to the PCA0CPLn. The value in
the PCA0CPHn controls the frequency of the CEXn output.
The high byte holds the number of PCA clocks to count before the output is
toggled.

Example 8.12 Use the CEX0s frequency output mode to generate a 10-kHz signal
assuming that the C8051F040 is running with a 24-MHz external crystal oscillator.
Solution:
#include <C8051F040.h>
void sysInit(void);
void main (void)
{
sysInit();
SFRPAGE = PCA0_PAGE;
PCA0CN = 0;
PCA0CPM0
= 0x46;
PCA0MD = 0x80;
PCA0CPL0 = 0x64;
PCA0CPH0= 0x64;
PCA0L
= 0;
PCA0CN = 0x40;
while(1);

// stop PCA timer


// enable frequency output mode
// use SYSCLK/12 as PCA clock source
// load 100 into PCA0CPL0
// delay count to be added to generate 10-KHz waveform
// let PCA timer count up from 0
// start PCA timer

11

}
void sysInit(void)
{
unsigned char cx;
SFRPAGE = SPI0_PAGE; // switch to SFR page where the SPI registers reside
SPI0CN
= 1;
// select 3-wire SPI (just to fixed I/O pin assignment)
SFRPAGE = CONFIG_PAGE;
WDTCN = 0xDE;
// disable watchdog interrupt
WDTCN = 0xAD;
//
"
OSCXCN = 0x67;
// start external crystal oscillator
for (cx = 0; cx < 255; cx++);
while(!(OSCXCN & 0x80)); // wait for crystal oscillator to stabilize
CLKSEL |= 1;
// switch to external crystal oscillator as clock source
XBR2
= 0x5D;
// enable crossbar decoder, and assign I/O pins to all
XBR0
= 0xF7;
// peripheral signals
XBR1
= 0xFF;
// "
XBR3
= 0x8F;
// "
P1MDOUT
= 0x07;
// enable CEX0 pin as output
}

1.6 Eight-Bit PWM Mode (Fixed Frequency)


The frequency of the PWM output is dependent on the clock source of the PCA.
The duty cycle of the PWM is varied using the modules PCA0CPLn register.
Whenever the value in PCA0CPLn is equal to that in PCA0L, the CEXn pin will
be pulled high.
Whenever the PCA0L overflows, the CEXn pin will be pulled low and the
PCA0CPLn register is reloaded with the value stored in the PCA0CPHn register.
This mode is entered by setting the ECOMn and PWMn bits in the PCA0CPMn
register.
The frequency of the PWM waveform is given by dividing the chosen PCA clock
frequency by 256.
The value to be placed in PCA0CPHn for a certain duty cycle is given by
PCA0CPHn = 256(1 duty cycle)

12

Example 8.13 Write a C program to generate a PWM waveform with 60% duty cycle
assuming that the program is to be run on a C8051F040 demo board.
Solution:
Load the value 102 (256*(1-60%)) into the PCA0CPH0, thus the logic 1 time for the
PWM output will be 154 clock cycles and the resultant PWM waveform will have about
a 60% duty cycle.
#include <C8051F040.h>
void sysInit(void);
void main (void)
{
sysInit();
PCA0MD
= 0x80;
PCA0L = 0;
PCA0H = 0;
PCA0CPM0 = 0x42;
PCA0CPL0 = 102;
PCA0CPH0 = 102;
PCA0CN
= 0x40;
while(1);
}
void sysInit(void)
{
.
}

// choose OSC/12 as clock input to PCA timer


// let PCA0 counter counts from 0
// *
// configure module for 8-bit PWM mode
// set duty cycle to 60%
//
// enable the PCA timer and clear all PCA flags

1.7 16-bit PWM Mode (Fixed Frequency)


Using 16-bit can make duty cycle setting mode accurate
Whenever the PCA0 timer matches the 16-bit capture/compare register, the CEXn
pin is asserted high.
Whenever the PCA0 timer overflows, the CEXn pin is assered low.
To enter this mode, set ECOMn, PWMn, and PWM16n bits to 1s in the
PCA0CPMn register to 1.
The value to be loaded into the PCA0CPn register for a specified duty cycle is as
follows:
PCA0CPn = 65536 (1 duty cycle)
Example 8.14 Write a program to configure the PCA module 0 so that a 16-bit PWM
signal with 60% duty cycle is generated. This program is to be run on a C8051F040 demo
board running with a 24-MHz external oscillator.
Solution:

13

Load the value 26214 (65536*(1-60%)) into the PCA0CPH0, thus the logic 1 time for the
PWM output will be 39322 clock cycles and the resultant PWM waveform will have
about a 60% duty cycle.
#include <C8051F040.h>
void sysInit(void);
void main (void)
{
sysInit();
PCA0MD = 0x80;
// choose OSC/12 as clock input to PCA timer
PCA0L
= 0;
// let PCA0 counter counts from 0
PCA0H
= 0;
//
*
PCA0CPM0
= 0xC2;
// configure module for 16-bit PWM mode
PCA0CPL0 = 0x66;
// set duty cycle to 60%
PCA0CPH0= 0x66;
// (reload value is 26,214 = 0x6666)
PCA0CN = 0x40;
// enable the PCA timer and clear all PCA flags
while(1);
}
void sysInit(void)
{
SFRPAGE = 0;
// switch to SFR page 0
SPI0CN
= 0x01;
// enable 3-wire SPI
SFRPAGE = 0x0F;
WDTCN = 0xDE; // disable watchdog timer
WDTCN = 0xAD;
CLKSEL = 0;
// select internal oscillator as SYSCLK
OSCICN = 0x83;
// set SYSCLK frequency to 24.5 MHz
XBR0
= 0xF7;
// assign port pins to all peripheral signals
XBR1
= 0xFF;
XBR2
= 0x5D;
XBR3
= 0x8F;
P1MDOUT
|= 0x02;
// enable CEX0 output (P1.1 pin)
}

14

2. DC Motor Control
DC motors are used in control systems as positioning devices
Both the speed and torque of the DC motor can be precisely controlled over a
wide range.
A DC motor consists of a stator and a rotor (also called armature).
The stator of the DC motor is a permanent magnet whereas the armature consists
of coils.
When current flows into the armature, the motor starts to rotate.
The speed of the DC motor is determined by the voltage applied to the armature
coils.
PWM function is often used to control the DC motor speed.
MCU can not drive the motor directly and needs a driver chip to provide the
needed current levels.

2.1 DC Motor Driver Chips


The SN754410 from TI and the L293 from ST Microelectronics are the two most
popular motor driver chips. These two chips are pin compatible.
Each chip has four channels and can source up to 1 A current from each channel.
Pin assignment of SN754410 and L293 is shown in Figure 8.25.
VCC2 is the output voltage supply whereas VCC1 is the input logic voltage supply.
Both can be from 4.5 V to 36 V.
In the actual circuit connection, VCC1 would be connected to 5 V and VCC2 is
connected to at least 12 V.

15

DC Motor Control Feedback


DC motor controller needs information to adjust the voltage output to the motor
driver circuit.
The most important information is the motor speed which can be obtained by
using a sensing device such as Hall-effect transistor, position encoder, and
infrared detector.
Figure 8.26 shows the attaching of two magnets to the rotor (armature) and induce
output in the Hall-effect transistor.
The schematic of a DC motor control system is shown in Figure 8.27.

16

In Figure 8.27,
The PWM output (CEX0) is connected to one end of the motor voltage input
whereas the P4.0 pin provides the direction control (shown in Figure 8.28).
Due to its mass, a DC motor cannot reach final speed instantaneously.

Example 8.15 For the circuit connection shown in Figure 8.27, write a C function to
measure the motor speed (in rpm) assuming that the C8051F040 is running with a 24MHz external oscillator.
Solution: To measure the motor speed, we need to capture two consecutive falling (or
rising) edges. Let the difference of two consecutive edges be diff and the period of the
timer be set to 0.5 s (set the clock prescaler of the PCA0 timer to 12), then the motor
speed (rpm- revolutions per minute) is
Speed = 60(s) (1/( 0.5 10-6 diff 2)) = 60 106 /diff
The C function that measures the motor speed is as follows:

17

unsigned int motorRPM(void)


{
unsigned int edge1,edge2,diff,rpm;
long int temp;
PCA0CPM1
= 0x10;
/* configure PCA module 1 to capture falling edge */
CCF1
= 0;
/* clear CCF1 flag */
while (!CCF1);
/* wait for the first falling edge */
edge1= (unsigned int) PCA0CPH1 * 256 + (unsigned int)PCA0CPL1;
CCF1
= 0;
while (!CCF1);
/* wait for the second falling edge */
edge2= (unsigned int) PCA0CPH1 * 256 + (unsigned int)PCA0CPL1;
diff
= edge2 - edge1;
temp
= 60000000L/(long) diff;
rpm
= temp;
return rpm;
}

Electrical Braking
Turning off the voltage to the motor does not make it stop immediately because
the momentum will keep it rotating.
An abrupt stop may be required by certain applications in which the motor must
run a few turns and stop quickly at a predetermined point. This is called electrical
braking.
Electrical braking is done by reversing the voltage applied to the motor.
In Figure 8.28, the motor can be braked by (1) reducing the duty cycle of PWM
output (at CEX0) to 0.4% and (2) setting the port pin P4.0 output to high for an
appropriate amount of time.

18

You might also like