1. Trang chủ >
  2. Giáo Dục - Đào Tạo >
  3. Cao đẳng - Đại học >

8 Experimenting with RESET, SLEEP, and the Watchdog Timer

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (9.59 MB, 687 trang )


The PIC18Fxx2: System Startup and Parallel Port IO



229



FIGURE 8.10 RCON register definition, bit values under

different reset conditions.3



Figure 8.11 shows a C program useful for experimenting with the different

PIC18 reset conditions. The code assumes the existence of a serial port connection

for displaying the results of the printf() statements and reading serial port input,

which is discussed in Chapter 9.

On main() entry, the program initializes the serial port, and then determines if

a power-on reset or watchdog timer reset has occurred. If the test POR == 0 is true,

power-on reset has occurred and the variable reset_cnt is initialized to zero. Observe that POR = 1 is included, as this bit is unaffected by other reset types, so it must

be set in order to detect other reset types. In addition, the persistent qualifier is

used for the declaration of reset_cnt, excluding it from being initialized by the

start-up code executed before main() entry. This means that reset_cnt is only initialized in the if{} body of the POR test, allowing this variable to keep a count of

the number of non-POR resets experienced. If the test TO == 0 is true, the watchdog

timer has expired, causing a reset. The watchdog timer is then disabled by clearing

3



Figure 8.10 adapted with permission of the copyright owner, Microchip Technology, Incorporated. All rights reserved. No

further reprints or reproductions may be made without Microchip Inc.’s prior written consent.



230



Microprocessors



void pcrlf (void) // print a newline to terminal

{

putch(0x0a); putch(0x0d);

}

persistent qualifier



prevents variable from being

initialized by start-up code prior to main



persistent char reset_cnt;

main(void){

int i;

char c;



Initializes serial interface, discussed in Chapter 9.



serial_init(95,1); // 19200 in HSPLL mode, crystal = 7.3728 MHz

pcrlf();

Detects power-on reset

if (POR == 0){

printf("Power-on reset has occurred."); pcrlf();

POR = 1; // setting to bit to 1 means that will

// remain a '1' for other reset types

reset_cnt = 0;

reset_cnt only initialized here

}

if (TO == 0) {

Detects watchdog timer expiration

SWDTEN = 0; // disable watchdog timer

printf("Watchdog timer reset has occurred."); pcrlf();

}

i = reset_cnt;

printf("Reset cnt is: %d",i);

pcrlf();

reset_cnt++;

reset_cnt increases in value for each non-POR reset

while(1) {

printf("'1' to enable watchdog timer"); pcrlf();

printf("'2' for sleep mode"); pcrlf();

printf("'3 ' for both watchdog timer and sleep mode"); pcrlf();

printf("Anything else does nothing, enter keypress: ");

c = getch();

putch(c);

pcrlf();

if (c == '1') SWDTEN = 1; // enable watchdog timer

Inline assembly used to insert SLEEP

else if (c == '2') asm("sleep");

else if (c == '3') {

instruction

SWDTEN = 1;

// enable watchdog timer

asm("sleep");

}

}

}



ON THE CD



FIGURE 8.11 Program (reset.c) for experimenting with reset types.



the SWDTEN bit, which is bit 0 of the WDTCON register. After these two reset

checks, the reset_cnt variable is incremented, and an infinite while(1){} loop is entered. A choice menu is printed within the loop, giving the user the option of enabling the watchdog timer, entering sleep mode, or enabling the watchdog timer,

and then entering sleep mode. Choice #1 enables the watchdog timer via the statement SWDTEN = 1, which sets the SWDTEN bit. If nothing else is done after this

choice is made, the WDT expires after approximately two seconds assuming the

WDT postscaler is set to 128:1. This causes a reset, and the message “Watchdog

timer reset has occurred” is printed by the code that detects this condition. Choice

#2 enters sleep mode by executing the SLEEP instruction, which is inserted in the C

code by the statement asm(“SLEEP”). This is known as inline assembly, and allows assembly language instructions to be specified directly within C code. After this

choice is made, the only method of waking the processor is to press the MCLR#

reset button, or to cycle power (assuming the schematic of Figure 8.4). Choice #3

first enables the watchdog timer, and then enters sleep mode. Two seconds later,

the watchdog timer expires, waking the processor from sleep mode, and causing execution to resume at the instruction following the SLEEP instruction. Since this is at



The PIC18Fxx2: System Startup and Parallel Port IO



231



the end of the loop, a jump is made back to the beginning of the loop, and the

choice menu is reprinted. If no choices are made, the watchdog timer expires again

after another two seconds, causing a device reset. Extending this code to check for

other reset conditions, or generating other types of reset is left for the review problems at the end of the chapter. Figure 8.12 shows terminal output from testing the

code of Figure 8.11.



Power-on reset, so reset_cnt is 0



Pressed reset button to generate

MCLR# reset, so

reset_cnt increments

Typed “1”, WDT enabled.

Menu reprinted,

but no input typed,

WDT reset occurs, WDT disabled.

reset_cnt increments.



Typed “2”, so sleeps.

Must press reset to wakeup,

incrementing reset_cnt

Typed “3”, so WDT enabled

and sleep.

WDT expires, waking PIC.

Loop and re-display menu.

No input typed, WDT reset occurs,

WDT disabled.

reset_cnt increments.



Cycle Power

Power-on reset, so reset_cnt is 0



FIGURE 8.12 Testing the reset.c program.



8.9 PARALLEL PORT OPERATION

Parallel port IO refers to groups of pins whose values can be read or written as a

group via special function registers. On the PIC18F242, three parallel ports are

available: PORTA, PORTB, and PORTC. Two additional ports, PORTD and



232



Microprocessors



PORTE, are available on larger pin count versions of the PIC18Fxx2. Only PORTA,

PORTB, and PORTC are discussed in this book, as the PIC18F242 is the target device for the interfacing examples. Each parallel port has three special function registers associated with it: PORTx/TRISx/LATx, where x is A, B, or C. The TRISx

register is used to configure each bidirectional port bit as either an input or output.

A “1” in a TRISx register bit configures the associated PORTx register bit to be an

input, while a “0” configures the associated PORTx register bit to be an output. The

LATx register is the data latch used to drive the port pins when it is configured as

an output. Reading PORTx returns the values of the external pins, while reading

LATx reads the data latch value. Writing to either LATx or PORTx writes to the

data latch of the associated port. Please note that reading LATx may not return the

same value as reading PORTx. If the port is configured as an input, reading LATx

returns the last value written to LATx or PORTx, while reading PORTx returns the

value of the external pin. If the port is configured as an output, reading LATx will

normally return the same value as reading PORTx because the data latch is driving

the external pin. However, if there is another external driver that is clashing with

the port driver, or if the port driver itself is a special case like an open drain output

(explained later in this section), LATx and PORTx may return different values

when read. A write to a port bit configured as an input changes the value of the output data latch (LATx), but does not change the value seen on the external pin whose

value is set by whatever is driving that pin.

PORTB

Figure 8.13 shows the internal logic of port pins RB[2:0]. Each port has slightly different features, and the PIC18Fxx2 datasheet should be consulted for a complete

description of each port’s capabilities. This diagram clearly shows the differences

between the PORTB, LATB, and TRISB special function registers. The TRISA register controls port direction, PORTB represents the state of the external pins, and

LATB holds the data used to drive the port pins.

Figure 8.13 shows that the TRISB[y] bit is connected to the enable input of the

tristate buffer that is on the output data latch that drives the PORTB pin. If

TRISB[y] is “0” (the port bit is an output), the tristate buffer is enabled, and simply passes its input value to its output. If TRISB[y] is “1” (the port bit is an input),

the tristate buffer is disabled, and its output becomes high impedance, whose state

is commonly designated as “Z”. Figure 8.14 shows that one can think of the tristate

buffer enable as controlling a switch on the output of the buffer; the switch is closed

when the enable is asserted, allowing the buffer to drive its output. The switch is

open when the enable is negated, causing the output to float (also known as high

impedance). Note that a port bit cannot be both an input and an output simultaneously; it is either one or the other based on the setting of the TRISB[y] bit.



The PIC18Fxx2: System Startup and Parallel Port IO



233



The lower part of Figure 8.14 shows data flow on a bidirectional data link using one

wire; data is either flowing from CPU_a to CPU_b or vice versa, but never both directions at the same time over one wire if voltage mode signaling is used.

Vdd

RBPU(1)



P Weak Pullup



RD LATB

Data Bus

WR LATB

or PORTB



Data Latch

D

Q

IO Pin



CK

TRIS Latch

D

Q



WR TRISB



CK



TTL Input

Buffer



RD TRISB

Q

RD PORTB



D

EN

RD PORTB



Schmitt Trigger Input



RBn/INTn



(1) To enable weak pull-ups, set the appropriate TRIS bit(s) and clear the

RPBU bit (INTCON2[7])

Figure redrawn by author from PIC18Fxx2 datasheet (DS39564B), Microchip Technology Inc.



FIGURE 8.13



Port RB2:RB0 pin internals.4



In Figure 8.13, if a port is configured as an input and the RBPU bit (INTCON2[7]) is “0”, the weak pullup is enabled; observe that this enables the weak

pullup for all PORTB pins configured as inputs. The weak pullup is implemented

as a high-resistance P-transistor; when enabled, the gate of this transistor is “0”,

turning it on. The weak pullup is useful for eliminating the need for an external

pullup resistor on an input switch (see Figure 8.15). The term weak is used because

the resistance is high enough that an external driver can overpower the pullup resistor and pull the input to near ground, producing a “0” input. PORTB is the only

port with internal weak pullups. Note that a pushbutton switch configured as a

low-true input switch must have some form of pullup resistor, either internal or external, or the input floats when the pushbutton is not pressed, allowing the input to

be read as either “1” or “0”.

The PORTB pin logic of Figure 8.13 shows both a TTL buffer and a Schmitt

trigger buffer used for driving internal signals from the external pin. Figure 8.16

shows the Vin/Vout characteristics of these two input buffer types. Observe that for

a Schmitt trigger, a low-to-high transition must become close to Vdd before the

4



Figure 8.13 adapted with permission of the copyright owner, Microchip Technology, Incorporated. All rights reserved. No

further reprints or reproductions may be made without Microchip Inc.’s prior written consent.



234



Microprocessors



Tristate buffer with low-true enable

Y=A



A



A



Y=A

EN=0



EN=0

Y = high-z



A



A



Y = high-z

EN=1



EN=1

Tristate buffer with high-true enable

A



Y=A



A



Y=A

EN=1



EN=1

Y = high-z



A



A



Y = high-z

EN=0



EN=0



data direction

high-z



RBn



CPU_a



1 or 0

RBn



TRISn=1



CPU_b



TRISn=0



data direction

1 or 0

RBn



CPU_a



high-z



RBn



CPU_b



TRISn=1



TRISn=0



FIGURE 8.14 Tristate buffer operation and

bidirectional IO.



Vdd

RBPU = 0



0

P



TRISBn = 1



Vdd



No External

Pullup

Needed



Must always have

some form of pullup,

or input floats when

switch is not pressed.



Weak Pullup

Enabled

IO Pin



FIGURE 8.15 Weak pullup operation.



buffer trips; conversely, a high-to-low transition must be close to ground before the

buffer trips. This hysteresis in the buffer action provides extra immunity against

noise on the input signal, and is also used for transforming slowly changing inputs

into signals with fast rise and fall times. Schmitt triggers consume more power than



The PIC18Fxx2: System Startup and Parallel Port IO



235



TTL inputs, and thus are only used on inputs that either provide internal interrupts

(such as RB0, RB1, RB2, MCLR#) or drive the clock signal of an internal subsystem.

TTL Input (Vdd = 5 V)

Vout



Schmitt Trigger (Vdd = 5 V)

Vout



Voh



Voh



approx

1.0 V



approx

4.0 V



Vin

VIL = 0.8 V

(max)

Vin



VIH = 2.0 V

(min)

Vout



Vin



Vin



Vout



FIGURE 8.16 TTL buffer versus Schmitt trigger buffer PORTA.



PORTA pins are shared with the analog-to-digital converter subsystem, and the

default configuration is for these pins to be analog inputs, causing a “0” to always

be read for those inputs when reading special function register PORTA. To configure all PORTA pins for digital operation, the statement ADCON1 = 0x06 is required;

other values written to the ADCON1 register provide different combinations of

analog/digital inputs (see the PIC18Fxx2 datasheet and Chapter 12 for more details). Pins RA0:RA3 and RA5 provide bidirectional IO, CMOS logic levels for output, and use a TTL buffer for input. Pin RA4 is different; it is an open-drain output

configuration, which can either drive its output low or leave it floating (see Figure

8.17). The term open-drain is used because the drain terminal of the N pulldown

transistor is open; there is no P pullup transistor. The right-hand side of Figure 8.17

shows a common use of open-drain outputs, which is to implement wired logic. The

three RA4 outputs of the CPUs are wired directly together, and pulled up to Vdd

through an external resistor. This is a low-true wired-or configuration because the

BUSY line is asserted low, turning on the LED, whenever CPU_a or CPU_b or

CPU_c asserts its RA4 output low. If all RA4 outputs are floating, the BUSY line is

high, and the LED is turned off. You cannot connect normal CMOS outputs directly together like this because there will be a clash when one output drives high,

and another output drives low, resulting in an uncertain voltage level on the wire.

A common mistake is to use RA4 as a normal output that must provide both high

and low voltage levels. This is difficult to debug, as a “1” written to RA4 causes the

output to float, which can be read by the receiving logic (if it is a CMOS input) as



236



Microprocessors



either a “1” or “0”. Thus, the system will fail intermittently, which is one of the most

difficult types of hardware problems to debug.

Vdd

No P pullup

(open-drain)



RD LATA



Busy

LED



Q



Data Bus



D



WR LATA

or PORTA



Q



N



CPU_a



IO Pin



RA4



CK

Data Latch

D



WR TRISA



CPU_b



Q



RA4



Schmitt Trigger

Input



CK

TRIS Latch



Busy

line



CPU_c

RA4



RD TRISA

Q



D

EN



RD PORTA

TMR0 Clock Input



Wired OR (low-true) :

if CPU_a OR

CPU_b OR

CPU_c asserts RA4 low,

then BUSY is asserted

(LED on).



Figure redrawn by author from PIC18Fxx2 datasheet (DS39564B), Microchip Technology Inc.



FIGURE 8.17 Pin RA4, open-drain output.5



PORTC

PORTC pins are bidirectional, with CMOS output drivers. In the PIC18F242, the

PORTC output pins are shared with other subsystem functions that are used in this

book’s interfacing examples. As such, the examples in this book use PORTB and

PORTA pins for any parallel IO needs. Details on the PORTC parallel port logic, as

well as PORTD and PORTE can be found in the PIC18Fxx2 datasheet.

Sample Question: Write C code that configures pins RB0, RB2, RB4 as outputs, and the

rest of PORTB as inputs.



Answer: Recall that if a TRISx bit is a “1”, the port pin functions as an input;

a “0” configures the port as an output. This configuration can be accomplished in two ways; either by a single assignment to the TRISB register or by

individual TRISB bit assignments. The statement TRISB = 0xEA (0b11101010)

works, as this clears bits TRISB4, TRISB2, TRISB0 to “0” and sets the rest as “1”.

If the TRISB configuration occurs after power-on reset (POR), then the statements:

TRISB4 = 0; TRISB2 = 0; TRISB0 = 0;

5



Figure 8.17 adapted with permission of the copyright owner, Microchip Technology, Incorporated. All rights reserved. No

further reprints or reproductions may be made without Microchip Inc.’s prior written consent.



The PIC18Fxx2: System Startup and Parallel Port IO



237



also works, as all bits in the TRISB register are reset to “1” after power-on reset

(see Appendix A for the settings of all special function register bits after POR).

Obviously one statement is more efficient than multiple statements, but if you

are new to microcontrollers it is suggested that you use the coding style that

you understand the best.



8.10 LED/SWITCH IO AND STATE MACHINE PROGRAMMING

A common input device is a momentary pushbutton switch. Figure 8.18 shows a

pushbutton switch connected to RB6. When the pushbutton is released (not

pressed) the RB6 input reads as “1”; when the pushbutton is pressed the RB6 input

reads as “0”.

Vdd

10 kΩ

RB6



Input

Switch



PIC



RB4



470 Ω

Count number of

switch presses.

ON THE CD



main(){

int i;

TRISB = 0xEF;

RB4 = 0;

i = 0;

while (1) {

if (!RB6) {

//switch pressed

//increment i

i++;

}

}

}



a. Incorrect, variable i is

incremented as long as

the switch is pushed, which

could be a long time!



main(){

int i;

TRISB = 0xEF;

RB4 = 0;

i = 0;

while (1) {

// wait for press

while (RB6); //loop (1)

DelayMs(30); //debounce

// wait for release

while (!RB6); //loop (2)

DelayMs(30); // debounce

i++;

}



b. Correct, loop 1 executed while

switch is not pressed. Once pressed,

becomes trapped in loop 2 until

switch is released, at which point

variable i is incremented.



FIGURE 8.18 LED/switch IO example #1.



Assume we would like to count the number of pushbutton presses and releases;

each press and release counts as one switch activation. A common mistake is shown

in code segment (a), which increments a variable i when RB6 returns “0”. The

problem with this code is that the variable i is not only incremented when the

pushbutton is pressed, but is also incremented for as long as the pushbutton is held

down. Human reaction times on pushbutton switches are measured in tens of milliseconds, so i is incremented many times for each pushbutton activation!

Code segment (b) shows a correct solution to this problem. When the

while(1){} loop is entered, the code becomes trapped in the loop while(RB6){},



238



Microprocessors



which loops waiting for the pushbutton to be pressed. Once the pushbutton is

pressed, the code is then trapped in the loop while(!RB6){}, waiting for the pushbutton to be released. Upon release, the variable i is incremented and the code becomes trapped in the loop while(RB6){} again. Thus, i is incremented only once for

each press and release of the pushbutton. The DelayMs(30) function calls are included after each change in the input switch status to ensure that all switch bounce

has settled before continuing. Mechanical switch bounce can produce multiple

pulses when a pushbutton is activated. The required delay is a function of the mechanics of the switch bounce, which can only be seen by using an oscilloscope to

capture the switch waveform or from a manufacturer data sheet. The value of 30

ms used here should be adequate for common momentary switches. This is a simple method for debouncing a switch with the drawback that the CPU cycles spent

in the software delay loop are wasted. Alternate methods for switch debouncing are

presented in Chapter 10.

Another example of LED/switch IO is given in Figure 8.19, in which the goal is

to toggle the LED each time the pushbutton is pressed and released. Code segment

(a) is incorrect, as the if{!RB6} statement only turns on the LED as long as the

pushbutton is held down. Code segment (b) is correct, as the two statements

while(RB6){}, while(!RB6){} wait for a press and release before turning on the LED;

then the next two statements while(RB6){}, while(!RB6){} wait for a subsequent

press and release before turning off the LED. The bit assignments LB4 = 1, LB4 = 0

can be used instead of RB4 = 1, RB4 = 0, as this also writes to the port data latch register. For the PICC-18 compiler, data latch bits can also be referenced using the

LAT prefix (e.g., LATB4).

Sample Question: Assume the same LED/switch configuration of Figure 8.19. Write a

while(1){} loop that blinks the LED twice for each switch press and release. Assume

the port is already configured.



Answer: One solution is shown in Listing 8.3.

LISTING 8.3



Solution A.



while(1){

while(RB6); DelayMs(30);

while(!RB6); DelayMs(30);

//blink twice

RB4 = 1; DelayMs(200);

RB4 = 0; DelayMs(200);

RB4 = 1; DelayMs(200);

RB4 = 0; DelayMs(200);

}



//wait for press

// wait for release

//turn

//turn

//turn

//turn



on, delay for blink

off, delay for blink

on, delay for blink

off, delay for blink



Xem Thêm
Tải bản đầy đủ (.pdf) (687 trang)

×