CHAPTER 9. Taking timing further
We began to see in Chapter 6 how important counting and timing are in the embedded environment. We also saw how easy it is to count digitally and to convert that counting ability to an ability to measure time. We need now to take this capability much further, especially in the timing arena. Once we have good tools for timing, we can use them to underpin other microcontroller functions, like the generation of serial data or of pulse width modulation. We can also use those timing tools to facilitate complex external activity, generating, for example, the timing signals for an engine management system.
This chapter will explore counting and timing needs in the embedded environment and develop capabilities to meet those needs, to a comparatively sophisticated level. While counting remains the underlying technique, it is its timing function that emerges as the predominant activity.
A central theme of this chapter will be the exploration of enhanced counter/timer structures. This will lead to the microcontroller being able to hand over much of its time-based activity to this hardware. Program execution can then continue doing other things while the hardware looks after timing issues. This activity will include:
• Maintaining continuous counting functions.
• Recording (‘capturing’) in timer hardware the time an event occurs.
• Using timer hardware to trigger events at particular times.
• Setting up an environment whereby repetitive time-based events can be generated.
• Measuring frequency, and hence physical variables that can be expressed as frequencies, for example motor speed.
The structures examined will be those of the 16F873A microcontroller. This will lead both to increased expertise in using this device and its relatives, and to an understanding of the underlying concepts, applicable to any microcontroller system. Many aspects will be illustrated with examples from the Derbot AGV. The necessary build for this is outlined in the final section of this chapter.
Note that Microchip tend to use the terminology ‘timer’ when referring to their counter/timer modules. In this chapter, ‘timer’ and ‘counter/timer’ will be used more or less interchangeably.
9.1. The main ideas – taking counting and timing further
Building on the material of Chapter 6, we need now to move on to more advanced applications of counting and timing, as shown in the bullet-point list above. The ability to do these things depends very much on extending the basic counter/timer hardware. Therefore, in this chapter each new counting or timing technique will be introduced alongside a description of the hardware that enables it to happen.
The Timer 0 of the PIC® 16 Series was introduced in Section 6.3 of Chapter 6. Take a moment to look at Figure 6.8 and remind yourself of its principal features, if there is any chance you have forgotten. At the heart is a digital counter which is memory mapped and can be written to and read from. The clock input to the counter can be selected from two sources. Either an external input can be chosen, in which case the module is often viewed as being in ‘counter’ mode. Alternatively, the internal oscillator signal can be connected to the counter, in which case it is viewed as being in ‘timer’ mode. A prescaler can be applied, which divides down the frequency of the incoming clock signal. When the counter counts up to its maximum value and then overflows to zero, an interrupt can be generated.
The PIC 16F873A has three timers, with some important accessories, which we now explore. The comparatively simple structure just reviewed forms the basis of the more advanced designs that we shall see.
9.2. The 16F87XA Timer 0 and Timer 1
9.2.1. Timer 0
The 16F873A uses the standard mid-range Timer 0 module. This is therefore the same counter/timer design as used by the 16F84A. Hence the description of Chapter 6, Section 6.3.3 fully applies.
9.2.2. Timer 1
The PIC mid-range Timer 0 is limited by being only 8-bit. Timer 1, shown in Figure 9.1, builds directly on the concepts of Timer 0 but has a number of important differences. First of all, it is 16-bit. As the figure shows, it is made up of two 8-bit registers, TMR1H and TMR1L. These are Special Function Registers (SFRs), which in the usual way are readable and writeable. They can be seen in the register file map of Figure 7.6. Together, they can count from 0000 to FFFFH, or 65536D. When the count rolls over from FFFFH back to 0, the interrupt flag TMR1IF (seen in the interrupt structure diagram of Figure 7.10) is set. This can be enabled to form an interrupt on overflow.
Timer 1 is controlled by the T1CON register, shown in Figure 9.2. The timer is switched on and off with bit TMR1ON. The timer has three distinct clock sources, which can be traced on Figure 9.1. For counting functions, the external input T1CKI, shared with pin 0 of Port C, must be used. For timing functions, there remains the option of the internal clock oscillator, Fosc/4. Selection between these two is made by the TMR1CS bit in the control register. A third possible clock source is made available due to the possibility of setting up a dedicated Timer 1 external oscillator, connected to the two external pins shown. This removes the dependence of working with the main oscillator frequency. The external oscillator can operate at a frequency entirely distinct from the main oscillator, and can also run when the main one is shut down in Sleep mode. The external oscillator is enabled with the T1OSCEN bit. The oscillator input for Timer 1 is identical to the main LP oscillator (Section 3.5.3 of Chapter 3). It is intended for lower-frequency oscillation, up to around 200 kHz. Typically it is used with a 32.768 kHz crystal, which can be divided down to provide a one-second time base.
Whichever clock source is chosen, there is the option of applying the prescaler. With only two control bits, T1CKPS1 and T1CKPS0, this does not have the range of scaling options offered by Timer 0, with only three effective division values, of 2, 4 and 8. Finally, synchronisation of the external input is enabled by bit T1SYNC. The timer must run synchronously if either the Capture or Compare modes, described in the coming sections, are to be used. If operating asynchronously, however, it can continue to run when the microcontroller is in Sleep mode.
When the external clock source is chosen, the counter is always incremented on a rising edge (on Timer 0, a rising or falling edge can be chosen). However, the counter must first have a falling edge before it starts to count. There is a danger, therefore, that the first pulse might be lost. We will see in the Derbot program that follows how to get over this little problem.
9.2.3. Application of Timer 0 and Timer 1 as counters for Derbot odometry
Having suggested that timing is to be the dominant theme of this chapter, our first example is of counting! A fundamental need of any vehicle is an ability to measure how far it has travelled, a technique known as ‘odometry’. This is done in the Derbot by using its handmade optical shaft encoders, as described in Section 8.6.4 of Chapter 8. By counting pulses from the shaft encoder and calculating from the wheel geometry the distance represented by each pulse, a measure of total distance travelled can be obtained.
Program Example 9.1 applies the shaft encoder to implement simple odometry with the Derbot. The outputs of the two optical sensors are connected on the Derbot PIC to the inputs of Timer 0 and Timer 1, as shown in Figure A3.1. Both of these are used in Counting mode. For the wheel diameters used in the prototype, and applying the shaft encoders described in Appendix 3, the program drives the Derbot forward for 1 m. It then completes a 180° turn on the spot and runs forward for 1 m again. The program loops continuously in this manner.
As before, to save space, the full program listing is not reproduced in the book, but can be found on the book's companion website. It is instructive to look at a number of features of the
program. Port bits are set up in the normal way, to reflect Derbot bit usage. ADCON1 controls whether the Port A bits are to be used for analog input or digital input/output. It is initialised here for the final expected analog/digital distribution of the Port A bits, even though the analog input is not used in this program.
|Program Example 9.1.|
|Application of odometry with the Derbot|
By checking the Option register diagram in Figure 6.9, the Timer 0 settings described in the comment can be verified. Similarly, a look at Figure 9.2 should verify the setting for Timer 1.
At the program section opto_move, both timers are cleared to zero. The input to Timer 1 is, however, tested. If it is zero, then the timer value is incremented to one, as the first rising edge is not detected in the hardware. The two motors are then set running forward, using the same subroutines used in Program Example 8.4. Program execution then moves to the loop opto_loop. Here the timer values are continuously tested. A count of 91 represents a distance travelled of 1 m, for an encoder pattern of 16 black/white cycles per wheel revolution, as described in Appendix 3. When the timer value reaches 91, the respective motor enable bit is cleared to zero and the motor stops.
When both motors have stopped, the Derbot executes a turn on the spot, running the motors in opposite directions. The distance that each wheel must cover is calculated by applying the geometry described in Appendix 4, which equates to the count of 23 that is found in the program. In program execution, the arc travelled by each wheel in the turn is measured with the shaft encoder and the motors stop running when the distance is complete. The AGV then runs the same fixed distance back to its starting point and the process continues.
This program demonstrates the application of counting to odometry, and also its weaknesses. The resolution of the distance measurement using this simple home-made shaft encoder is poor and suitable for demonstration purposes only – interesting though these are. The AGV can execute only approximate 180° turns and an approximate return home. If it is allowed to continue its back and forth trajectory, its return becomes increasingly approximate, as a cumulative error builds up. Moreover, there is no speed control on the motors. Although driven from the same voltage, any two motors are rarely identical and the AGV tends to run in a curve, albeit slight. We will be able to resolve this problem when speed measurement is implemented later in this chapter, and that of speed control in Chapter 11.
9.2.4. Using Timer 0 and Timer 1 to generate repetitive interrupts
An important use of a counter/timer is often for it to generate a continuously running series of accurately timed interrupts. These can be used for a host of timing applications, including forming the basis of a sophisticated programming framework known as a ‘real-time operating system’ – but that's the business of Chapter 18! Sometimes such a series of interrupts is called a ‘clock tick’. This can be a little misleading, as we already have a clock oscillator and now we are talking about something different. However, such a clock tick can become almost as fundamental as the microcontroller clock oscillator itself, and can be used as the basis for almost as many time-based operations.
Timer 0 and Timer 1 can readily be used to generate such a clock tick, as both can produce an interrupt on overflow. The principle is illustrated in Figure 9.3. The timer is set to run continuously, in Timer mode, with interrupts enabled. Its value is represented by the stepped waveform in the diagram. It repeatedly counts up to its maximum value and overflows back to zero. Every time it does this, an interrupt is generated.
In general, if the timer is n-bit, then it will count 2n cycles, from one zero to the next. The time between the interrupts, Tint, is then given by:
where tclk is the period of the clock input to the timer.
Design Example 9.1
Design Example 9.1
Assuming an oscillator frequency of 4 MHz, what is the slowest ‘clock tick’ rate that can be obtained from Timer 0 and Timer 1? What is the next fastest in each case?
For Timer 0, refer to Figure 6.8 and Figure 6.9. To achieve the slowest interrupt rate, the prescaler is set to ÷256. The input clock frequency to the timer itself is therefore 1 MHz/256, or 3.906 kHz. The action of the 8-bit timer itself is to divide this frequency by 256 to produce the clock tick frequency, which will be 3.906 kHz/256, or 15.26 Hz. The next frequency up would be if the prescaler were set to ÷128. In this case, the interrupt rate would be 30.52 Hz.
For Timer 1, refer to Figure 9.1 and Figure 9.2. The maximum prescale rate is ÷8. Using this, the clock input to the timer itself will be 125 kHz. The action of the timer is to divide this by 216, leading to an interrupt frequency of 1.91 Hz. The next highest frequency would be if the prescaler were set to ÷4, leading to an interrupt frequency of 3.81 Hz.
It is interesting to see that there is not a major difference between the slowest rates of each timer. Although Timer 0 is only 8-bit, the fact that it has a very effective prescaler compensates in this sort of application for its smaller size.
9.3. The 16F87XA Timer 2, comparator and PR2 register
9.3.1. Timer 2
The 16F87XA Timer 2 is a simple 8-bit device. It is shown in block diagram form in Figure 9.4. Only two of the elements in the diagram, the TMR2 register and the prescaler, actually relate to the conventional timer function. Timer 2 is a pure timer so is driven only from the internal oscillator, shown at the right of the diagram. No external input is possible. The 8-bit Timer register is readable and writeable, and can be seen at memory location 11H in Figure 7.6. Modest prescaling opportunities are possible.
The control register for Timer 2, T2CON, appears in Figure 9.5. The explanations in the figure give a good description of the role of each bit.
9.3.2. The PR2 register, comparator and postscaler
Timer 2 has a Period register PR2, at memory location 92H in the memory map (Figure 7.6), which can be preset by the programmer. When the timer is running, its value is continuously compared with the PR2 register by the comparator. When it reaches the value held in PR2, it resets to 0 on the next input cycle.
This process is illustrated in Figure 9.6. The PR2 value is shown fixed, although it can be changed within the program. The Timer 2 value is now just represented as a sawtooth, although its underlying stepped nature (as shown in Figure 9.3) should still be recognised. It counts up to the PR2 value. When they are equal, a reset is generated and Timer 2 is cleared to zero. This occurs on the increment cycle after the equality has been detected, so there are (PR2 + 1) cycles between each reset. Figure 9.4 shows that this reset forms an output of the module, labelled ‘TMR2 output’. This can be selected as a baud rate generator by the Synchronous Serial Port (SSP), as described in the following chapter.
Design Example 9.2
Design Example 9.2
The Derbot AGV has an oscillator frequency of 4MHz. What is the slowest Timer 2 interrupt rate that it can generate?
To achieve the slowest rate, PR2 and the post- and prescalers must be set to maximum. If the prescale is set to ÷16 then the frequency of the clock driving Timer 2 will be 1 MHz ÷ 16, or 62.5 kHz. If PR2 is set to 255, then Timer 2 will be able to clock up to its maximum value (i.e. 255) before returning to 0. Therefore, the reset frequency will be 62.5/256 kHz, or 244.14 Hz. If this is further postscaled by 16, then the interrupt frequency will be 15.26 Hz. This is the slowest possible interrupt frequency for this source.
The series of resets just described also forms an input to the postscaler, whose output can be used as an interrupt source. The postscaler is controlled by the TOUTPSX bits of the control register. Notice that it can take any division value up to 16 – it is not just limited to binary powers. Figure 9.6 shows the case in which the postscaler divides by four. The outcome of this is a stream of interrupts, whose frequency can be adjusted across a range of values.
9.4. The capture/compare/pulse width modulation (CCP) modules
9.4.1. A capture/compare/pulse width modulation overview
At the beginning of Chapter 6 it was suggested that embedded systems have timing needs which are equivalent in some ways to various timing needs in everyday life. The embedded system does need the equivalent of setting an alarm and of recording the time of an event. These and other requirements are neatly resolved by the addition of one or more registers to a basic counter/timer. A register that can record the time of an event is called a ‘Capture’ register. One that can generate an alarm does this by holding a preset value and comparing it with the value of a running timer (as we have seen already with PR2). The alarm occurs when the two are equal. Such registers are called ‘Compare’ registers. The PIC 16 Series microcontrollers combine these different functions, and more besides, in their capture/compare/PWM (CCP) modules.
The CCP modules are very versatile and interact with both Timer 1 and Timer 2. The 16F873A has two such modules and they are well worth understanding. Each module has two 8-bit registers, called CCPRxL and CCPRxH, where x is 1 or 2. Together they form a 16-bit register that can be used for capture, compare or to form the duty cycle of a PWM stream. The CCP modules are controlled by their respective CCPxCON registers (Figure 9.7). It is the least significant four bits of these that determine the mode of operation of the module. It can be seen that they can be switched off, set for PWM or set for one of four possible configurations in either Capture or Compare mode. We will examine each operating mode in turn.
9.4.2. Capture mode
A Capture register operates something like a stopwatch. When an event occurs, the value indicated by a running clock is recorded. In a stopwatch, the watch then stops running. In a Capture register, the clock goes on running, but its value at the instant when the event occurred is recorded.
The CCP1 in Capture mode is shown in Figure 9.8. CCP2 will act the same as CCP1 in this mode, but will share its input with Port C bit 1. Because the input pin is shared with Port C, it must be set as an input in TRISC. An external signal, representing an ‘event’, is connected to the microcontroller pin RC2/CCP1. The purpose of the Capture mode is to record in CCPR1L and CCPR1H the value of Timer 1 when the event occurs. Further flexibility can be built in, as the external signal can be prescaled by 4 or 16, and the rising or falling edge can be selected. The possible options can be seen in Figure 9.7. As well as causing a capture to occur, the occurrence of the event also causes an interrupt, represented by the CCP1IF flag in the interrupt structure diagram of Figure 7.10. Module CCP2 has an equivalent interrupt, represented by CCP2IF.
9.4.3. Compare mode
The CCP1 module configured in Compare mode is shown in Figure 9.9. Here a digital comparator is designed into the hardware which continuously compares the value of Timer 1 and the 16-bit register made up of CCPR1H and CCPR1L. Timer 1 must be running in Timer mode or in synchronised Counter mode. The module is connected to an external pin, which must be configured as an output in TRISC. When a match occurs, one of several things may happen, depending on the setting of the control register (Figure 9.7). The associated output bit can be set or cleared (with the interrupt flag bit set in both cases). This allows external events to be started or terminated. Alternatively, the interrupt may be set with no change to the output. Finally, a ‘special event’ may be triggered. For both modules this includes clearing Timer 1 and leaving the output pin unchanged. Module CCP2 also initiates an analog-to-digital conversion, if the converter is enabled.
9.5. Pulse width modulation
Pulse width modulation is a very powerful technique which allows analog variables to be controlled from a purely digital output, and with only a single data connection!
9.5.1. The principle of pulse width modulation
An understanding of a typical application of PWM requires a little bit of background electronics. This is so important that we will review it briefly, by reference to Figure 9.10.
where V is the voltage across the inductor, i the current through it and L its inductance. Derived from this, if a step change in voltage is applied, then the current rises exponentially to a steady-state value of V/R, where R is the resistance of the inductor. The rate of rise depends on a circuit quantity known as the ‘time constant’, which for an inductor is given by L/R. It can be shown that, for a step change in applied voltage, the current rises from 10 to 90 per cent of its final value in time 2.2L/R. If the voltage is removed, the time taken for it to fall (assuming there is a circuit for it to flow in) is the same.
Let us imagine an inductive load is switched on and off by a transistor switch, as shown in Figure 9.10 (a). When the transistor is switched off, the decaying current flows in the freewheeling diode. If the time duration it is on is much greater than the circuit time constant, then the current rise and fall times will just be a small proportion of the overall time, and the current waveform will appear as shown in Figure 9.10 (b). If, however, the switching is repetitive, with a period less than the inductor time constant, then the current has no chance to reach steady state. It rises a little when the switch is on and falls a little (flowing through the freewheeling diode) when it is off. If the switching is continuous, the current rises to an average value which is dependent on the Mark : Space ratio of the switching waveform. This is represented in Figure 9.10 (c, d).
The great thing about this is that the average current flowing in the inductor can be controlled by the Mark : Space ratio of the switching waveform. PWM is born!
A PWM waveform generally has a fixed period T, with a variable pulse width ton. It can be shown, for the circuit of Figure 9.10 (a), that the average current flowing in the inductor, Iave, is given by:
9.5.2. Generating pulse width modulation signals in hardware – the 16F87XA pulse width modulation
The beauty of PWM lies in its simplicity and the way in which it acts as a gateway between the digital and analog worlds. It is easy to generate a PWM waveform in digital hardware. We will use the PIC 16 Series as an example to explain this. Although the principle is straightforward, the useful ‘extras’ introduced by Microchip add to the complexity. A little care is therefore needed in its understanding.
The simplified block diagram of the CCP configured to generate PWM is shown in Figure 9.11, with example waveforms in Figure 9.12. It can be seen that Figure 9.11 contains the central features of Figure 9.4, with Timer 2, comparator and the PR2 register working together. Although not now shown, Timer 2 is still driven from the on-chip oscillator, through its own prescaler. With Timer 2 free-running, it is reasonable to expect the waveforms of Figure 9.6 to be found in the PWM process. This is indeed the case – the waveforms of Figure 9.6 are extended to become those of Figure 9.12. The comparator output, however, now drives an R–S flip-flop. When the value in PR2 equals Timer 2, then the comparator clears the timer and sets the flip-flop, whose output goes high. This is seen in Figure 9.12. This action sets the PWM period.
Having established the PWM period, let us consider how the pulse width is determined. A second Compare register arrangement is introduced to do this. This is made up of the CCPR1H register, plus a second comparator. As the logic of the diagram shows, every time this comparator finds equal input values, it resets the output flip-flop, clearing the output to zero. It is this comparator that determines the pulse width. Again, this is shown in Figure 9.12. To change the pulse width, the programmer writes to the CCPR1L register, which acts as a buffer. Its value is transferred to CCPR1H only when a PWM cycle is complete, to avoid output errors in the process.
The block diagram is made more complex because three of the registers are ‘stretched’, to make them potentially 10-bit instead of 8-bit. This increases the resolution. CCPR1L uses two bits of the CCP1CON register (as already seen in Figure 9.7). CCPR1H is extended with an internal 2-bit latch, while the extension to Timer 2 is as described in Note 1 of Figure 9.11. Because of these two extra bits, in its 10-bit version it is effectively clocked direct from the internal oscillator signal, undivided. If the prescaler is used, then it acts on this frequency, not the usual Fosc/4. Notice, however, that the PR2 register remains at eight bits. This means that the PWM period has only an 8-bit equivalent resolution.
The PWM period T is determined by the interaction of the PR2 register and the eight bits of Timer 2. It may be calculated as follows:
The PWM pulse width ton is determined by the interaction of the extended CCPR1H register (all 10 bits of it) and the extended (10-bit) Timer 2. It may be calculated as follows:
where ‘PWM timer input clock period’ is the period of the clock input to the extended Timer 2 and ‘pulse width register’ is the value in the extended CCPR1H register. Hence,
Note that there is not here a factor of four with the Tosc term, as explained above.
9.5.3. Pulse width modulation applied in the Derbot for motor control
Let us now explore an application of the 16F873A PWM to the Derbot AGV. We need first of all to understand how PWM is applied in the circuit design. We saw in Chapter 8 how an H-bridge could be used for reversible drive. If PWM, rather than just on/off drive, is applied to an H-bridge, then continuously variable reversible drive can be achieved.
The Derbot circuit diagram for the left motor is shown in Figure 9.13 (a). Half of the L293D IC (Figure 8.27) is used to form an H-bridge, with outputs driving the motor. The two inputs of the H-bridge are connected with a logic inverter between them, so that whenever one is at Logic 1, the other is at Logic 0, and vice versa. If the input labelled ‘Bridge Drive’ is held at Logic 1, the motor will run in one direction; if at Logic 0, it will run in the other.
If now the Bridge Drive is connected to a PWM source, interesting things happen. If it is an exact square wave of sufficiently high frequency, the motor stands still, as the average current is zero. This is illustrated in Figure 9.13 (b). If the Bridge Drive changes to a Mark : Space ratio of less than 1, the current takes up a negative average value. With a Mark : Space ratio of greater than 1 it takes up a positive average value. This is also seen in Figure 9.13 (b). By varying the PWM pulse width across its full range, from absolute minimum to absolute maximum, the motor speed can be continuously varied, in both directions.
Looking at the full circuit diagram in Figure A3.1, it should be possible to work out that CCP1 drives the right motor, while CCP2 drives the left. Enable signals come from bits 2 and 5 of Port A.
The simplest program that we have available to look at PWM use in the Derbot AGV is the ‘blind navigation’ program of Chapter 8, appearing in part as Program Example 8.4. The parts of the program relating to PWM, omitted in the earlier chapter, now appear as Program Example 9.2.
The example program sections start with initialisation of the PWM. By writing to the T2CON register (Figure 9.5), Timer 2 is switched on, with neither pre- nor postscale (see Figure 9.4). Applying the CCPxCON registers, the two CCP control registers are set up in PWM mode. Finally, the PR2 register is loaded with 249D. Noting that the clock oscillator frequency is 4 MHz, we can deduce from Equation (9.2) that the PWM period is:
i.e. PWM frequency = 4.00 kHz.
This is a convenient frequency value, which we shall use for other things later. It retains almost the full resolution of the PWM system.
|Program Example 9.2.|
|Pulse width modulation – related sections of ‘blind navigation’ program|
Also shown in Program Example 9.2 are the subroutines used to set the motors running forward and back, leftmot_fwd, rtmot_fwd and so on. Each of these starts by enabling the respective motor drive, by setting the port bit mot_en_rt or mot_en_left high. A number is then loaded into CCPR1L or CCPR2L which determines the PWM pulse width. For simplicity, the two least significant bits of the pulse width setting, held in CCPxCON, are preset to zero and not further used in this program. Therefore, the pulse width setting can range from 00 to 250D loaded into CCPRxL, where 00 gives full reverse, 250D gives full forward and 125D gives no rotation. The numbers actually loaded in the program, 176D and 80D, were found experimentally to give gentle forward and reverse speeds. Later in this chapter, and then later in the book, programs are developed to exploit the PWM capability to give variable speed drive.
9.6. Generating pulse width modulation in software
While hardware PWM sources are versatile and simple to use, they are not always available. Perhaps a cost-conscious application has chosen a microcontroller without a PWM source. Alternatively, an application may have used up all its PWM sources and still need more. PWM is a classic case of a capability that can be developed either in hardware or in software – if using a software solution, the only hardware resource that is needed is a single port I/O pin, set to output!
PWM outputs can be generated based on software delay loops only, such as those described in Chapter 5. A possible flow diagram appears in Figure 5.4 of Ref. 1.1. This approach, however, ties up the CPU almost completely, so is likely to be of only limited use in practice.
An alternative to using a purely programming approach to generating a PWM stream, still without requiring a PWM hardware module, is to use a timer interrupt to set the period. This can simplify programming complexity, and allows the CPU to be used in part for other activities. All that is needed is to set a timer interrupt on overflow running at an appropriate speed, as described in Section 9.3.3 of this chapter. On every interrupt the PWM output should be set high and a programmed delay initiated. At the end of the delay the PWM output is cleared. This is illustrated in Figure 9.14.
9.6.1. An example of software-generated pulse width modulation
A good example of the technique just described is found in Program Example 9.3. This drives the Derbot servo, which is used to rotate the ultrasound detector. The 16F873A has only two
PWM sources and these are committed to the motors. The servo requires the pulse waveform shown in Figure 8.23. This is particularly appropriate for a program-generated technique, as the pulse width is always small compared to the period, so the CPU is committed for only a comparatively short period. The program moves the servo shaft position in 45° steps, from a reference 0° to 180°. Because the current consumption is very high if an instantaneous step movement is demanded of the servo, a ramp is generated between each step position.
|Program Example 9.3.|
|Pulse width modulation generated in software|
With Timers 0 and 1 committed to the shaft encoder function, only Timer 2 is possibly available for timer overflow use. However, it appears to be tied up with the PWM function. Here we see how a timer can be used for two apparently unrelated things. The timer can be left in its PWM role, but its interrupt on overflow, via the postscaler (Figure 9.4), can be evaluated for this new application. The two applications are in some conflict – the servo needs a period of 20 ms, while the PWM frequency needs to remain in the region of several kilohertz. The flexibility of the postscaler is an advantage here. As with the motor PWM setting, it can be seen that if the contents of PR2 are set to 249D, then the Timer 2 overflow rate is 4 kHz. With the postscaler set to ÷16, the interrupt frequency becomes 250 Hz, or a period of 4 ms. This is not the 20 ms we want, but it is easy in the program to output a pulse every five interrupts.
The settings just described can be seen in the program example. Register PR2 is loaded with 249D and the Timer 2 postscaler set to ÷16. Three software counters are then preset – int_cntr counts the incoming interrupts, pulse_cntr counts the number of pulses sent at each pulse width, while past_pulse holds the pulse width of the previous pulse and is used to determine whether ramping is needed between one pulse width and the next. The Timer 2 interrupt is then enabled and the program moves to sit in a wait loop. All subsequent program action is then in the ISR (Interrupt Service Routine).
Within the ISR, the value of int_cntr is first decremented to test whether a pulse is to be output. If it is, the value of pulse_cntr is then decremented to test if the pulse width is to be changed. In this case, the value of servo_dirn is incremented. This acts as a pointer to the look-up table, from which the new period is taken. At label ISR1, the look-up table is accessed and the ‘demand’ pulse width is read. This is stored in memory location pw_cntr. The value stored determines how many times a 20 μs delay routine is called, setting the pulse width.
The ramp, if needed, is now generated. The value in pw_cntr is compared with the previous value, in memory location past_pulse. If they are equal, the pulse is immediately output. If not, a test of the Carry flag determines which was the greater. The value of pw_cntr is then incremented or decremented accordingly, to set the new pulse width. The pulse is then output using a simple delay loop.
9.6.2. Further Assembler directives for memory definition and branching
Notice the use in the program of two useful additions to our Assembler coding repertoire. Early in the program, the directive pair cblock and endc are used to define the list of data memory locations. This saves the use of a long list of equ statements. In the ISR, branching is achieved with instructions such as the following:
btfscstatus,c;if carry clear, demand>past
incfpast_pulse,1;here if demand>past, hence ramping up
Here the dollar symbol $ represents the current Program Counter value. Its usage in the line goto $+3 therefore forces a forward jump of three lines. Negative values can also be used. This technique is invaluable for local branches of a few lines forward or back, reducing the need for line labels. It is less useful with longer jumps, as a program change may be made some distance from the goto instruction, making the indicated jump value invalid.
9.7. Pulse width modulation used for digital-to-analog conversion
While PWM is perhaps primarily used for load control, it allows a simple but very effective digital-to-analog converter (DAC). If a PWM stream of fixed Mark : Space ratio is low-pass filtered, with a suitable cut-off frequency, then the digital stream becomes a DC voltage, with a little residual ripple. If the PWM Mark : Space ratio is modulated, then a varying-output voltage can be produced.
This idea is illustrated in simple form in Figure 9.15. The PWM stream is taken through an RC filter, which has the smoothing effect shown. The filter characteristic, in Figure 9.15 (b), is chosen so that the PWM frequency is well into the filter stop-band. If the modulation frequency is in the filter pass-band, then the PWM is effectively blocked and the modulating frequency passed. The effect can be quite dramatic.
9.7.1. An example of pulse width modulation used for digital-to-analog conversion
The Derbot has two low-pass RC filter sections in its circuit, with outputs at TP1 and TP2 (Figure A5.1). These are simply there to demonstrate analog voltage generation with PWM and are nothing whatever to do with the operation of the AGV. If used experimentally for this purpose, the motor enable bits should be set to 0!
The program dbt_pwm_qrtr_sinwave on the book's companion website is a simple illustration of this technique. It is reproduced in part in Program Example 9.4. The program uses the full 10-bit width available for setting the PWM time period. It generates a quarter sine wave by taking samples in turn from a look-up table called Sin_Table. A memory location
called pointer indicates where in the look-up table the program currently is. There are 45 samples, held as 16-bit values, in two bytes each. These give a binary, scaled sine value for 0°, 2°, 4° and so on up to 90°. Only the most significant two bits of the lower byte are used, however.
|Program Example 9.4.|
|Generating a quarter sine wave with pulse width modulation|
Once initialisation is complete, the program is structured as a simple loop, starting at sin_loop. The more significant sample byte is transferred directly to CCPR1l. The less significant byte has to be adjusted to fit the two target bits in CCP1CON. At the same time, the other bits of this register must not be affected. It should be possible to follow through in the program listing the way this is done. A 1 ms delay is inserted for each sample, using the delay1 subroutine. It is this, along with the execution time of the remainder of the program, which determines the sine wave frequency.
Also on the book's companion website is a program called dbt_pwm_full_sinwave. This uses the same look-up table to generate the full sine wave, but is slightly more complex than the quarter sine wave version. It adds all samples to a midway value of 125d. This represents the offset zero value of the sine wave. In the first quadrant it steps up through the table, in the second it steps backwards. In the third it steps forward again, but subtracts the samples from 125d. In the fourth it steps backwards and subtracts. This can be seen in the full program listing.
The output of the dbt_pwm_full_sinwave program can be seen in Figure 9.16 (a), with the output taken through the 100 nF/20 kΩ filter section (cut-off frequency of 80 Hz approximately). Notice the vertical and horizontal settings in each. Channel 2 displays the sine wave in both cases. Image (a) appears to show a very satisfactory sine wave. Image (b) shows a detail of the very same waveform, along with the PWM stream that creates it. The PWM period can be seen to be exactly 250 μs (i.e. a frequency of 4 kHz) in image (b). The characteristic (but small) sawtooth-like rise and fall of the analog waveform that accompanies it is very evident in the analog trace, with the overall rise in the signal voltage being just evident. With a PWM frequency of 4 kHz and the delay1 subroutine in use, there will be just four or five PWM cycles per sample. The overall sine wave period can be seen to be approximately 3.8 divisions, at 50 ms each, i.e. 190 ms. This is accounted for by 180 samples making up the sine wave, each with a 1 ms delay, plus further program execution time.
The use of PWM for digital-to-analog conversion, as just described, can be simple and effective. It does, however, come with some weaknesses, which need to be understood if the technique is to be used. In brief, these are:
• The output analog voltage is directly dependent on the logic levels of the PWM stream. These in turn are dependent on the accuracy of the power supply voltage, cleanness of the ground path and logic technology in use. Overall, accurate D-to-A conversion cannot normally be expected from this technique.
• The impact of the low-pass filter is such that the technique is of little use to generate fast-changing signals. The situation can be improved by use of a higher-order filter and/or running the PWM faster. This can be achieved by reducing the value stored in register PR2. By increasing the PWM speed in this way, however, it should be noted that the resolution is decreased. In general, we can see that any demand for high PWM frequency conflicts with a demand for high resolution.
• There will always be some residual ripple on the analog output.
9.8. Frequency measurement
9.8.1. The principle of frequency measurement
Frequency measurement is a very important application of both counting and timing. Fundamentally, frequency measurement is a measure of how many times something happens within a certain known period, as illustrated in Figure 9.17. The use can be as diverse as how many counts are received per minute in a Geiger counter, how many cycles per second (i.e. Hertz) there are in an electronic or acoustic measurement, or how many wheel revolutions there are per unit of time in a speed measurement. Both a counter and a timer are needed, the timer to measure the reference time and the counter to count the number of events within that time.
9.8.2. Frequency (speed) measurement in the Derbot
The Derbot AGV applies frequency measurement techniques to measure the speed of travel of the machine, later applying this to speed control. As Figure 9.17 indicates, what is needed first is an accurate timebase against which measurement can be made. Although any of the 16F873A timers could be used for this, Timers 0 and 1 are both used in counting mode for the wheel shaft encoders, so are not available. Timer 2 appears to be committed to the PWM function but, just as with the software-generated PWM in Section 9.6, further inspection shows that it can still be used. It was explained in that section how a 4 ms interrupt period could be achieved without impeding the PWM action. This is too short a period for most frequency measurements, but if we build a measurement period based on a certain number of iterations of this clock tick period, then we have the basis of a good period for frequency measurement.
Program Example 9.5 shows sections of the program Dbt_speed_meas, a simple speed measurement program, which can be found in full on the book's companion website. The program simply switches on the motors and runs them at fixed PWM rate. The program is structured according to the simplified diagram of Figure 9.18. The system is initialised, and motors and Timer 2 interrupt are enabled. The Timer 2 interrupt occurs every 4 ms, and every 250th occurrence of this (i.e. every second), the count accumulated in Timers 0 and 1 is measured.
|Program Example 9.5.|
|Frequency measurement applied to the Derbot|
The timer settings applied can be explored through the program listing. The settings of Timers 0 and 1 are the same as for Program Example 9.1 and the setting of Timer 2 the same as for Program Example 9.3. Following the initialisation, the enabling of interrupts and motors can be seen, as can the setting of the interrupt counter int_cntr. The motors are set running forward at a modest speed.
At the beginning of the ISR, the value of int_cntr is first of all decremented. If it is non-zero, then the ISR is terminated. However, if the counter has decremented to zero, then one second exactly has elapsed, and the values of Timer 0 and 1 are read and saved. A frequency measurement is thus made. In this simple demonstration program nothing further is done with that measurement. It is used, however, in the next section of this chapter to implement Derbot speed control.
9.9. Speed control applied to the Derbot
Embedded systems are about control, and now for the first time we will apply some closed-loop control!
The Dbt_speed_control program, shown in part in Program Example 9.6, uses the frequency measurement just discussed to implement closed-loop speed control on the AGV's motors. It is based on the principles of a simple closed-loop control system [Ref. 9.1], in that an output variable (motor speed, as represented by shaft encoder frequency) is compared with a demand value. The difference between the two is amplified and used to modify the drive to the motors. The control algorithm is identical for each motor and is embedded within the program ISR, following the comment line adjust left motor speed.
The program is effectively an extension of Program Example 9.5, except that the contents of PR2, governing the maximum PWM period, have been set to 255D. This just makes the data manipulation simpler and the program easier to follow. It does, however, mean that the Timer 2 interrupt period is now 4.096 ms, not 4.000 ms, so the frequency measurements made
are not exactly per half second or second. As data is not displayed in human-friendly form, this does not really matter.
|Program Example 9.6.|
|Derbot speed control program|
To comprehend the settings within this program, an understanding of how the motor speed relates to the shaft encoder frequency is needed. A shaft encoder of 16 cycles per wheel revolution was used. With a supply of 9 V applied to the L293D drive IC, the free-running gearbox output speed was measured to be approximately 154 r.p.m. This is in reasonable agreement with Table A3.1, bearing in mind the losses that occur in the drive electronics. This speed converts to a maximum shaft encoder frequency of (154 × 16)/60, or 41 Hz. To test this program a speed of approximately half this maximum was chosen, implying that over a period of 0.512 s a count of 10 cycles (nearest integer) is expected. This value is embedded within the program.
The control algorithm itself follows the flow diagram of Figure 9.19. It should be possible to follow the program listing through, by cross-reference to the flow diagram. The motors’ PWM rates are initially set to mid-range (i.e. zero speed) at the start of the program and the ISR adjusts them thereafter. The program listing shows the left motor only being controlled in this way. The setting for the right motor can be found in the complete listing on the book's companion website.
This program was found to run well, with the controlled speed being measured first ‘on the bench’ by testing the frequency of the output waveform of the reflective opto-sensors. With the Derbot running on the floor, for the first time it was seen to run in a reasonably true straight line, rather than the gradual curve that occurs when the two motors just run freely.
It is worth reminding ourselves that all features of this program, from setting the motor speed to measurement and control of the same, have been achieved using counting and timing techniques.
9.10. When there is no timer
While we have seen the power of the hardware timer, situations will continue to arise in which they are not available. Maybe there are no timers on the microcontroller in use or maybe they have all been used up. This is the case with the Derbot AGV, where all timers are committed, yet if the ultrasound sensor is applied then a further timer is needed. The solution adopted here is to return to the software timing loop described in Chapter 5. The disadvantage of such a loop is that it wholly commits the CPU. It is justified in this case, as the ultrasound measurement is not made continuously and the measurement time is a comparatively small proportion of time overall.
Program Example 9.7 shows part of a program which measures the distance between the ultrasound sensor described in Section 8.6.5 of Chapter 8 and an object in its range. When we get to Chapter 11, the distance will be displayed in centimetres on the hand controller LCD and the circuit can be adapted as an ultrasonic tape measure. This second section of the program is not shown here, as it depends on data manipulation routines described in that chapter. The whole program is on the book's companion website. The ultrasound sensor shares pins with the diagnostic LEDs. Therefore, if the sensor is used, the LEDs are no longer available for independent use, although they still light in response to the ultrasound drive pulses.
|Program Example 9.7.|
|Ultrasound timing in software|
The main program applies the timing diagram of Figure 8.16 and is structured as a continuous loop, starting at the label us_loop. The ultrasound pulse is initiated by the pulse on Port C bit 5. The program then waits until the echo pulse rises. Once this happens, the program enters a timing loop, within which the counter echo_time is incremented on every cycle. The duration of this loop is designed to be exactly 30 μs. With sound travelling at 1 mm/3 μs, this implies that the sound will travel 10 mm for every iteration of the loop. As the sound must travel to the target and return, this implies in turn a measurement resolution of 5 mm. The state of the echo pulse is tested on every loop iteration, and if and when it is found to fall to zero, the loop is terminated. If the counter overflows, however, then no object has been detected. A short bleep on the AGV sounder is emitted if an object is detected and a long one if none is detected. The full program goes on to convert the reading in echo_time to a distance value expressed in centimetres.
9.11. Sleep mode
As with Chapter 6 we embed Sleep mode, when time appears to be suspended, in a chapter on timing. The Sleep mode of the 16F87XA follows exactly the principles of the Sleep mode of the 16F84A, described in Section 6.6 of Chapter 6. A possible limitation of the 16F84A Sleep mode was the limited range of wake-up opportunities. A significant example of this is the lack of a periodic timed wake-up. (Although the WDT seems to offer this, its frequency of operation is imprecise and the range of overflow periods not particularly wide.)
The 16F87XA in contrast offers a wide range of wake-up opportunities, including a number from peripherals. The interrupt structure diagram of Figure 7.10 suggests that all peripherals can cause a wake-up from Sleep. In practice, of course, some of these stop functioning as they depend on the clock oscillator, which is turned off during Sleep. An interesting case now is Timer 1, which can run with its own oscillator. This can be left running while in Sleep, with a periodic wake-up derived from its overflow interrupt. Peripheral wake-up opportunities are available from the following:
• Timer 1, when operating in asynchronous mode.
• The CCP Capture mode interrupt.
• The special event trigger, with Timer 1 operating in asynchronous mode with the external clock.
• The synchronous serial port.
• The ADC, when running with a RC clock oscillator.
• EEPROM write complete.
• The comparator output change.
• The parallel slave port read or write (for the 16F874A or ’877A).
9.12. Where do we go from here?
We have seen in the last few pages a wealth of tools and techniques that allow time-based activities to be developed. Life has been kept simple, however, as most examples have been introduced as if the activity in question will be the only one it will do. In practice this is not the case, of course – the Derbot AGV will need to run its motors while it measures the motor speed, while it controls the servo, and so on. The number of time-based tasks will become many, and possibly conflicting. We have already seen, for example, the case of one timer being used for two different and potentially conflicting tasks. This challenge of marshalling time-based activity in an embedded system is common in many systems and needs a systematic approach to resolve it. That systematic approach will be seen in the real-time operating system, a subject for Chapter 18.
9.13. Building the Derbot
To run most of the programs used as examples in this chapter, you will need to add the reflective opto-sensors to the Derbot and the shaft encoder patterns to the wheels. The circuit will then have reached the stage shown in Figure 9.20. To run Program Example 9.3, the servo will need to be added. This is not shown in Figure 9.20, but can be seen in Figure A3.1.
• Timing is an essential element of embedded system design – both in its own right and to enable other embedded activities, like serial communication and pulse width modulation.
• A range of timers is available, with clever add-on facilities which extend their capability to capture, compare, create repetitive interrupts or generate PWM pulse streams.
• In applications of any complexity, a microcontroller is likely to have several timers running simultaneously, for quite different and possibly conflicting applications. The question remains open at this stage: how can these different time-based activities be marshalled and harmonised?
9.1. Bolton, W., Control Engineering Pocket Book. (1998) Newnes, Oxford, UK. ; ISBN 0 75063928 8.
1. The Timer 0 module of a 16F873A is to be used to generate a regular interrupt. The interrupt must occur every 5 ms. Crystal oscillators are available at the following frequencies: 1.0 MHz, 1.8432 MHz, 2.0 MHz, 2.457 MHz, 3.276 MHz, 3.579 MHz and 4.0 MHz. Recommend one crystal, and indicate how the Option register should be set in order to achieve this objective.
2. The T1CON register of a 16F873A is loaded with 0011 0101. The microcontroller clock oscillator is running at 16 MHz and there is a 320 kHz logic compatible signal connected to pin 11. If the Timer is initially cleared, how long does it take before it overflows for the first time?
3. A 16F873A microcontroller is running from a clock oscillator frequency of 8 MHz. The T2CON register has been set to 0011 1101 and the PR2 loaded with 1111 1001. With what frequency (or period) is the TMR2IF interrupt flag set?
4. The Timer 1 of a 16F873A is connected to an external crystal of frequency 131.072 kHz, and T1CON loaded with 0010 1011. The register CCP1CON is loaded with 0000 0110. Timer 1 is cleared to zero and left to run. Ten ms after this, and then every 10 ms, a positive-going pulse is applied at pin 13. What values are held in CCPR1H and CCPR1L after 45 ms?
5. The Timer 2 and PWM module of a 16F873A are operating in an application with a clock oscillator frequency, FOSC, of 4 MHz. The Timer 2 prescaler is initially set to 1:4, the PR2 register is loaded with a value 240 (decimal), and CCPR1H with a value of 30 (decimal).
(a) Which register controls the period of the PWM waveform, and which register controls the ‘on' time?
(b) For the settings described, what is the resulting PWM period?
(c) For the settings described, what is the approximate resulting ‘on’ time?
6. Estimate the pulse width and period of the PWM signal generated by the program fragment of Program Example 9.8, assuming a 4 MHz oscillator frequency.
|Program Example 9.8.|
|Program Fragment for Question 6|