The PIC16F84 Microcontroller Part 3

Timer

Most MCUs have facilities to either measure elapsed time and/or to generate digital on/off waveforms with well defined durations. This is normally based around one or more counters that are incremented either from an external pulse or internal clock. For instance, if an automatic packing machine needs to count cans of beans going along a conveyer belt, then a photoelectric-based transducer could act as the timer input. If a new packing carton needed to be in place every 24 cans then an internal 8-bit counter would be set to E8h (-24). When the counter overflows from FFh to 00h then an interrupt would be generated and the MCU then take the appropriate action.

All PIC MCUs have at least a basic timer/counter known as Timer0 (TMR0). The read/write TMR0 counter register at File 1 can be clocked from the outside world via the T0CKI (Timer 0 ClocK In) pin, which is shared with the RA4 Port A pin. Alternatively, the incrementing source can be the internal Q4 phase clock, which is one quarter of the crystal frequency. For example, for a 4 MHz crystal this is 1 MHz. Either clock source can be frequency divided by a buried 8-bit prescale counter. This divide ratio is controlled by the lower three PreScale bits of the OPTION_REG register at File 81 h (see Fig. 13.2), labelled PS2:PS1:PS0. The ratio is then 2PS+1. For example, if PS [2 : 0] = 111 then the counter will increment at ^fg, where f is the clock source frequency. The prescaler can be disconnected by setting bit 3 of OPTION_REG to 1. This will give a direct connection between pulse source and counter. Writing to the Timer 0 register also zeros the Prescaler counter (for example movlw 0F8h, movwf 1) enabling the time period to begin from true zero time.


When this PSA (Pre-Scale Assignment) bit is 1 the prescaler becomes a postscaler to the Watchdog timer.The Watchdog timer is designed to reset the MCU unless periodically preset by the user’s program with the instruction clrwdt (CLeaR WatchDog Timer). This ensures that the PIC will eventually reset if due to an electrical disturbance or a software bug, the processor malfunctions, perhaps by jumping into an unprogrammed part of the Program store. This will disrupt the periodic preset. If the prescaler is assigned to the Timer then the Watchdog timer will periodically time-out (count down through zero) after approximately 18 ms.21 With PSA set to 1 then 2PS 18 ms Watchdog time-outs are required before the processor is reset. Thus, with PS[2 : 0] = 111, 27 = 128 time-outs gives a period to MCU reset of nominally 2.3 s. Thus the software must use the clrwdt instruction before this period elapses to prevent reset. This instruction also clears the Prescale counter. If it does time-out, then the TO bit in the Status register will be cleared. If desired the Watchdog timer may be disabled at the same time as code is programmed into the Program store. Various configuration bits (known as fuses) are located by the flash EEPROM programmer in location File 2007h (see Fig. 10.5 ), which is not accessible during the normal run mode. Such details are normally hidden to the operator by the EEPROM programmer’s operative software. Registers relating to Timer 0 are:

TMR0, File 1

Sometimes known as the Real-Time Clock/Counter (RTCC), is an 8-bit up-counter register that keeps tally of clock events. It may be preset to any byte value by moving data from W and read at any time. When it overflows from FFh to 00h it sets the T0IF (Timer0 Interrupt Flag) in the INTCON (INterrupT CONtrol) register.This maybe used to generate an interrupt.

OPTION_REG, File 81 h

Six bits in this register in Bank 1 at File 81 h are used in conjunction with the timer.

• PS2, PS1, PS0 at bits 2,1,0 respectively control the prescale ratio 2PS-1 for the timer or postscale ratio 2PS for the Watchdog timer.

• T0SE (Timer 0 Set Edge) at bit 4 allows the programmer to select which edge of a pulse at the T0CKI pin will increment the counter; a 0 for _/ and 1 for .

• T0CS (Timer 0 Clock Select) at bit 5 allows the programmer to select the clock source as either the internal clock (= 0) or a transition at the T0CKI pin.

The remaining two bits configure external interrupt edge select and electrical properties of Port B inputs.

Data EEPROM

The PIC16F84 has a block of 64 bytes of data that does not require power to retain its contents. This non-volatile memory is not part of the (volatile) Data store and is accessed through SPRs as a peripheral device. Any byte can be addressed and then read from or written to via the EEDATA register as addressed by the EEADR register and controlled by the EECON1 and EECON2 control file registers. Data EEPROM has a minimum endurance of 1,000,000 writes and such data is retained for upwards of 40 years.

Details of the Read and Write protocols are given in topic 15, but are briefly reviewed here for completeness.

Read

1. Put address (00 – 3Fh) into EEADR.

2. Set RD (bit0 of EECON1) to 1 to set to the ReaD mode.

3. Read the addressed contents in EEDATA. Write

1. Put address into EEADR.

2. Put data into EEDATA.

3. Set WREN (bit 2 of EECON1) to 1 to WRite ENable.

4. Put code 55h into EECON2.

5. Put code AAh into EECON2.

6. Begin the Write cycle by setting WR (bit 1 of EECON1) to 1.

Writing, which is normally an infrequent act, is deliberately made circuitous to protect against accidental changes to the EEPROM. The register EECON2 does not actually exist, but the interlock writing 5 5h followed directly by AAh to File 89h is a necessary part of unlocking the target byte. Interrupts can disrupt this sequence and should be inhibited if used. Writing takes around 50 ms to complete, and sets the EEIF (EEPROM Interrupt Flag) bit 4 of EECON1 after this time, and this can be used to interrupt the processor. The WRERR (WRite ERRor) bit 3 of EECON1 is set if a Write cycle is prematurely terminated, say, by an External reset. Registers associated with the Data EEPROM are:

EEDATA, File08h

This contains the addressed data after a Read action and holds data to be written into the addressed byte during a Write action.

EEADR, File09h

The 6-bit address of the target byte is placed here before a Read or Write cycle.

EECON1, File 88h

This holds the control and status bits that:

• Trigger an EEPROM Read.

• Enable a Write action.

• Trigger an EEPROM Write.

• Signals a premature end to a Write cycle.

• Signals a Write cycle has been completed. Details are given in Fig. 15.2.

EECON2, File 89h

The EEPROM CONtrol 2 is not a physical register and reads as zero. This address is used as the target for the Write cycle unlocking sequence which is implemented by moving 5 5h followed directly by AAh into this virtual location.

Examples

Example 4.1

Discuss how the performance of the PIC architecture is improved by incorporating pipelining into the design of the instruction-fetch unit. Do you forsee any problems associated with handling Jump instructions (such as goto) in connection with the pipeline structure?

Solution

The pipeline is a precondition for the parallel operation of the fetch and execution units. That is, in order to allow the execution of instruction n whilst the next instruction n + 1 is being fetched from the Instruction store, internal storage must be provided to present the instruction code to the Instruction decoder. As all instructions are the same size, that is 14 bits, then the pipeline register structure and control is considerably simplified. Most conventional CISC processors have instructions that vary considerably in length. For example the 68HC11 MCU core has instructions that cover the range one through four bytes; that is the fetch phase can take between one and four bus transactions. Some more sophisticated processors have multi-stage pipelines with each stage feeding part of the execution circuitry. Thus several streams of execution activity can occur simultaneously.

The problem with pipelines is that they presuppose that the program instructions will be executed sequentially as they are stored in memory. However, instructions that disrupt this smooth running and move on the Program Counter require that the pipeline be emptied so that the instruction code of the destination travels down to the end of the pipe. For example, if instruction k is goto n, then instruction k + 1 will be in the first stage of the pipeline by the time the processor knows that the next step is actually to be instruction n. Thus a null instruction cycle needs to be executed which simply brings this instruction code into the pipeline but does not execute instruction k +1 whose code is at the end of the pipeline. This is sometimes known as flushing the pipeline. Instructions such as goto need two clock cycles to execute. Conditional Skip instructions, such as incfsz and btfsc take two cycles when the skip is implemented and one otherwise. All other instructions always take one cycle.

Example 4.2

Can you determine why after a subtraction, or addition of a negative number (eg. addlw -6), the setting of the C flag is the complement of the borrow-out.

Solution

The solution lies in the method of subtraction by 2′s complementing the subtrahend. The subtract instructions convert the subtrahend to their 2′s complement form and then configure the ALU to add. After the addition there can be two outcomes, depending on the relative magnitude of the minuend and subtrahend.

1. Where the subtrahend is greater than the minuend then the outcome is negative and there is no carry-out. An example of this situation is: 06 – 0A ^ 00000110 + 11110110 = (0) 11111100 or – 4 (no carry).

2. Where the subtrahend is less than the minuend then the outcome is positive and there is a carry-out. An example of this situation is: 0A – 06 ^ 00001010 + 11111010 = (1) 00000100 or + 4 (carry).

In both cases the Carry flag acts as an inverted borrow. This is in keeping with the RISC philosophy of the PIC family, to keep the processor ‘lean and mean’. In any case this non inversion means that subtraction can be implemented by adding negative data, eg. addlw -6. This is translated by the assembler to addlw 0FCh, where FCh is of course the 2′s complement of 6.

Example 4.3

Write a program to increment a packed BCD quantity located in Data memory at File 20h.

Solution

Two Binary-Coded Decimal (BCD) digits may be packed into a single byte to represent numbers up to 99. For exampletmp18294_thumb[2][2]represents BCD 49. Incrementing a number stored in this hybrid decimal-binary form using the normal binary addition rules may give an incorrect result. For example 01001001 + 1 (49 + 1) gives 01001010 (4Ah) after addition, but should give 01010000 (50h). Similarly, 10011001 + 1 (99 + 1) gives 10011010 (9Ah) instead of 00000000 Carry 1 (100h).

From these examples it can be seen that whenever any of the BCD decades equals ten after incrementation then it should be zeroed and one added to any higher decade. Based on this increment and add algorithm we can formulate the task list.

1. Increment the packed BCD byte using normal binary arithmetic.

2. IF the lower nybble of the outcome is ten then add six to the outcome.

3. IF the upper nybble of the outcome is ten then add six to it.

Program 4.1 Incrementing a packed BCD byte.

Program 4.1 Incrementing a packed BCD byte.

Program 4.1 gives an efficient implementation of this task list. After incrementing using normal binary rules, six is added to the previous outcome and the DC flag checked for activity. This flag will only be set when the original nybble was ten (0Ah + 6 = 10h). In this case the add six operation is allowed to stand as the necessary correction otherwise it is cancelled by subtraction. The upper nybble (BCD digit) is checked and corrected in the same manner, but this time it is the full Carry flag that is tested. If this is set, then the addition of 60h is allowed to stand, otherwise it is subtracted. This Carry flag could be used to set a hundreds digit if desired, to show overflow from 99 to 100.

An alternative approach would be to subtract nine before incrementation and if the Z flag is set then leave the digit at zero and increment the higher digit; otherwise add ten. Repeat for the upper digit.

Example 4.4

Write a routine that will add two packed BCD numbers at File 20h and File 21 h. The outcome is to be in File 22h for the hundred’s digit and File 23h for the tens and unit digits.

Solution

As in the case of Example 4.3 the binary addition of numbers that are already in BCD form may need correction afterwards. Again, a correction will be needed where the digit outcome is greater than nine. The situation is more complex in this case as the sum of two digits can be anywhere between zero and 19 (9 + 9 + 1 (carry-in) = 19). The illegal range 10 to 19 may be determined by applying the criterion:

• Check for the range Ah to Fh (10 to 15) — for example, 3 + 9 = Ch (3 + 9 = 12).

• Otherwise check if there was a carry out to the next decade — for example, 9 + 9 = 1 2h (9 + 9 = 18).

In both cases the digit may be corrected by adding six to ‘jump over’ the six illegal BCD states.

Based on this course a possible task list is:

1. Add the two packed BCD bytes using normal binary arithmetic.

2. IF the addition results in a full Carry THEN Hundreds = 1

3. IF the addition results in a half Digit Carry OR IF the unit BCD nybble is greater than nine THEN add six to the outcome.

4. IF the last correction (if any) resulted in a full Carry OR IF the tens BCD nybble is greater than nine THEN add six to the upper nybble of the outcome.

Program 4.2 directly implements this strategy. The full Carry flag is tested three times.

1. Directly after the addition – for example, 99h + 99h = 1 32h.

2. After the first correction where six is added to the lower digit – for example, 77h + 88h = FFh; FFh + 06h = 1 05h.

3. After the second correction where six is added to the upper digit – for example, 70h + 80h = F0h; F0h + 60h = 1 40h.

If the flag is set at any point then the hundreds digit will be one; the maximum value in this case is 99 + 99 = 198.

A nybble is tested for over nine by subtracting ten. If a carry (half or full depending on which digit is being tested) is not generated then the original nybble must have been ten or greater. I have actually implemented the subtract ten operation by adding -10; that is addlw -10. This is because the sublw instruction actually takes the value in the Working register away from the literal and not the other way around.

Program 4.2 Adding two packed BCD numbers.

Program 4.2 Adding two packed BCD numbers.

Self-assessment questions

4.1 The PIC16F877 mid-range MCU has a 8 kbyte Program store, which can hold up to 8192 14-bit instructions located in the range 0000 -1FFFh. As part of a certain program, execution has to be transferred from the bottom quarter of this map to 1000h. Given that the goto instruction can only directly access 11-bit addresses (0000 – 07FFh), how could you engineer a jump to this address, i.e. goto 1000h?

4.2 Write a routine to decrement a packed BCD quantity, as in Example 4.3. Hint: Devise a simple test to activate the relevant carry flag if the digit is Fh.

4.3 Write a routine to add ten onto a packed BCD byte located in File 20h. Hint: This is similar to Example 4.3 but only the tens digit is augmented.

4.4 Where microprocessors are used in a general-purpose computing environment, the program is normally loaded into and run from read/write RAM memory. This means that the system can run a word-processor one minute and a spreadsheet program the next. Of course this means of operation is not applicable to embedded applications, where the program is stored in some variety of non-volatile read-only memory. Discuss why this is so and the virtues of ROM, EPROM and EEPROM implementations of non-volatile storage.

4.5 The following routine is designed to do nothing other than defer execution of the main routine by 1282 ^s in a PIC MCU which is being clocked using a 4 MHz crystal. Taking into account pipelining, verify this figure.

tmp18297_thumb[2][2]

4.6 Can you devise an algorithm and task list to subtract two packed BCD numbers located as in Example 4.4. The outcome packed byte is to be in File 23h and File 22h is to hold the overflow carry – that is the negative indicator. This overflow is to be zero if there was a full borrow out, otherwise one. For example 45h – 29h = (01)16h (that is 45 – 29 = +16) and 29h – 45h = (00)84h (29 – 45 = -84) where 84 is the ten’s complement of 16.

Next post:

Previous post: