LED turn on after pressing switch on RB4

Test 7. LED turn on after pressing switch on RB4

Interfacing PIC Microcontrollers to Peripherial Devices-0271Interfacing PIC Microcontrollers to Peripherial Devices-0272

In the loop two routines are called: turning LED on and off. Both routines call also routine for delaying, generating delay of 48.6 ms:

Tcm x 3 cycles x op = 108 us x 3 x 150 = 48.6 ms

On the picture below on the evaluation board, at the right down side there are two 8 bit ports: port A and above port B. The pencil points to port B. All port B lines are on HIGH, except of line RB4. Diodes attached to port B are lighting, but LED attached to RB$ is off, because the switch connected to RB4 is pressed down. After pressing any of RB4 – RB7 switches the LED on RA1 get lighted.

If no switch is depressed (high on particular port B line) then, in the lin4 loop, af- ter the conditional instruction:

Interfacing PIC Microcontrollers to Peripherial Devices-0273

the next instruction (goto zapal) is omitted. Forcing low on RB4 causes executing next instruction and turning LED on RA1 on.

Interfacing PIC Microcontrollers to Peripherial Devices-0274

We see two LEDs lighting on PORT A: on RA5, which is input only port, always kept high. When this pin is configured as ~MCLR, is an active low Reset to the device. LED connected to RA1 lights when switch on RB4 is pressed.

 

Morse code: PIC generated with PWM

Test 6. Morse code: PIC generated with PWM

Generating the word PIC in Morse code using PWM module. Generating acoustic signal with PWM was described in previous test.

Interfacing PIC Microcontrollers to Peripherial Devices-0266Interfacing PIC Microcontrollers to Peripherial Devices-0267Interfacing PIC Microcontrollers to Peripherial Devices-0268Interfacing PIC Microcontrollers to Peripherial Devices-0269

Routine del contains nested loop. Two general purpose registers l2 and l3 are decremented. l2 is first cleared and then is decremented in the inner loop with instruction decfsz (decrement f, skip if zero). The loop is executed 256 times. It takes time of 1.024 ms (256 x 4 x 1us).

Interfacing PIC Microcontrollers to Peripherial Devices-0270

 

TIMERS AND COUNTERS:TIMERS

TIMERS

Timer0 will be covered first, and in more detail, as a prototypical timer, and discussion and examples for the use of Timer1 and Timer2 will be provided.

The use of timers internal to microprocessors is a bit more complicated than what we have been doing so far because there is a considerable amount of setup required before the timer can be used, and the options for setting the timers up are extensive. We will cover the timers one at a time in an introductory manner. However, you should be aware that there is an entire book available from Microchip Technologies that cov- ers nothing but timers, so the coverage here will be rudimentary.

Note The Microchip Technologies timer manual is called The PICmicro Mid- Range MCU Family Reference Book (DS33023), available from Microchip Technology Inc.

To understand timers, you must understand how to turn them on and off and how to read and set the various bits and bytes that relate to them. Essentially, in the typical timer application you turn on a timer by turning on its enable bit. The timer then counts a certain number of clock cycles, sets an interrupt bit that causes an interrupt, and continues running toward the next interrupt. Your program responds to the inter- rupt by executing a specific interrupt handling routine and then clearing the interrupt bit. The program then returns to wherever it was when the interrupt occurred. The pre-/post-scalers have to do with modifying the time it takes for an interrupt to take place. The hard part is getting familiar with which bit does what and where it is located, which is why reading and understanding the data sheet chapters (5, 6, or 7) depending on the timer you are using is imperative. There is no escaping this horror! However, this chapter will ease your pain.

Timers allow the microcontroller to create and react to chronological events. These include:

N Timing events for communications

N Creation of clocks for various purposes

N Generating timed interrupts

N Controlling PWM generation

N Waking the PIC up from the sleep mode at intervals to do work and go back to sleep

N Special use of the Watchdog Timer

There are three internal timers in the PIC 16F877A (there is also a Watchdog Timer, which is discussed after the timers in this chapter):

N Timer0 is an 8-bit free running timer/counter with an optional pre-scaler. It is the simplest of the timers to use.

N Timer1 is a 16-bit timer that can be used as a timer or as a counter. It is the only 16-bit timer and can also be used as a counter. It is the most complicated of the timers.

N Timer2 is an 8-bit timer with a pre-scaler and a post-scaler and cannot be used as a counter. (There is no way to input a signal to this timer.)

Each timer has a timer control register that sets the options and properties that the timer will exhibit. All the timers are similar, but each of them has special features that give it special properties. It is imperative that you refer to the data sheet for the PIC 16F877A (Chapters 5, 6, and 7) as you experiment with the timer functions. Once you start to understand what the PIC designers are up to with the timer functions, it will start to come together in your mind.

Timers can have pre-scalers and post-scalers associated with them that can be used to multiply the timer setting by a limited number of integer counts. The scaling abil- ity is not adequate to allow all exact time intervals to be created, but it is adequate for all practical purposes. To the inability to create perfectly timed interrupts we have to add the uncertainty in the frequency of the oscillator crystal, which is usually not exactly what it is stated to be (and which is affected by the ambient temperature as the circuitry warms up). Though fairly accurate timings can be achieved with the hard- ware as received, additional software adjustments may have to be added if extremely accurate results are desired. The software can be designed to make a correction to the timing every so often to make it more accurate. We will also need to have an external source that is at least as accurate as we want our timer to be so we can verify the accuracy of the device that we create.

First we’ll write a simple program to see how this timer works. We will use the LED bar graph to show what is going on inside the microcontroller.

As always, the bar graph is connected to the eight lines of PORTD of the LAB-X1. First, we will write a program that will light the two LEDs connected to D0 and D1 alternately. Having them light alternately lets you know that the program is running or, more accurately, the segment of the program that contains this part of the code is running. These two LEDs will be used to represent the foreground task in the program.

There is no timer process in use in Program 6.1 at this stage.

RUNNING SMALL MOTORS-0054RUNNING SMALL MOTORS-0055

The use of the PAUSEUS loop in Program 6.1 provides a latency of 100 Ms (worst case) in the response to an interrupt and eliminates most of the effect of changing the OSC frequency if that should become necessary. It is better than using an empty counter, which would be completely dependent of the frequency of the system oscil- lator. There is an assumption here that the 100 microsecond latency is completely tolerable to the task at hand and it is for this program. This may not be true for your real-world program and may have to be adjusted.

We are turning one LED off and another LED on to provide a more positive feed- back. As long as we are executing the main loop, the LCDs will light alternately and provide a dynamic feedback of the operation of the program in the foreground loop. It is important that you learn to develop failsafe techniques for your programs, and this is a rudimentary one for making sure that a program is running.

We have selected a relatively fast on/off cycle so that we will better be able to see minor delays and glitches that may appear in the operation of the program as we proceed.

Run this program to get familiar with the operation of the two LEDs. Adjust the counter (the 300 value) to suit your taste.

Next, in Program 6.2, we will add the code that will interrupt this program periodi- cally and make a third LED go on and then off on an approximately one-second cycle. This will serve as the interrupt driven task that we are interested in learning how to create. In most programs this would be the critical, time-dependent task.

Here is what you have to do to make the interrupt driven LED operational:

N Enable Timer0 and its interrupts with appropriate register/bit settings.

N Add the ON INTERRUPT command to tell the program where to go to handle the interrupt when an interrupt occurs.

N Set up the interrupt routine to do what needs to be done (the interrupt routine counts to 61 and turns the LED on if it is off and off if it is on).

N Clear the interrupt flag that was set by Timer0.

N Send the program back to where it was interrupted with the RESUME command.

WHY ARE WE USING 61?

N Set the pre-scaler to 64 (bits 0 to 2 are set at 101 in the OPTION_REG).

N Set the counter to interrupt every 256 counts (256 s 64 = 16,384).

N Set the clock to 4,000,000 Hz

N Set Fosc/4 to 1,000,000 (1,000,000 /16,384 = 61.0532—it’s not exact but close enough for our purposes for now).

The lines of code now look like Program 6.2.

RUNNING SMALL MOTORS-0056

RUNNING SMALL MOTORS-0057

Make your predictions and then try changing the three low bits in OPTION_REG to see how they affect the operation of the interrupt.

In Program 6.2, Timer0 is running free and providing an interrupt every time its 8 bit counter overflows from FF to 00. The pre-scaler is set to 64 so we get the interrupt

after 64 of these interrupt cycles. When this happens we jump to the “InterruptRoutine” routine, where we make sure that 61 interrupts have taken place. If they have, we change the state of an LED and return to the place where the interrupt took place. (It happens that it takes approximately 61 interrupts to equal one second in this routine with a processor running at 4 MHz. This could be refined by trial and error after initial calculation if necessary.)

Note that the interrupts are disabled while we are in the “InterruptRoutine” routine, but the free running counter is still running toward its next overflow, meaning that whatever we do has to get done in less than 1/61 seconds if we are not going to miss the next interrupt (unless we make some other arrangements to count all the interrupts with an internal subroutine or some other scheme). It can become quite complicated and we will not worry about it for now.

Before going any further, let’s take a closer look at the OPTION_REG and the INTCON (INTerrupt CONtrol) register. These registers were used in Program 6.1, but the details of their operations were not explained. These are 8-bit registers with the eight bits of each register assigned as follows:

OPTION_REG the option register

Bit 7 RBPU. Not of interest to us at this time. (This bit enables the port B weak pull-ups.)

Bit 6 INTEDG. Not of interest to us at this time. Interrupt edge select bit deter mines which edge the interrupt will be selected on, rising (1) or falling (0). Either one works for us.

Bit 5 T0CS, Timer0 Clock Select bit. Selects which clock will be used.

1 = Transition on TOCKI pin.

0 = Internal instruction cycle clock (CLKOUT). We will use this, the oscil- later. See bit 4 description.

Bit 4 T0SE, Source Edge Select Bit. Determines when the counter will increment.

1 = Increment on high to low transition of TOCKI pin. 0 = Increment on low to high transition of TOCKI pin.

Bit 3 PSA, Pre-scaler assignment pin. Decides what the pre-scaler applies to.

1= Select Watch Dog Timer (WDT).

0 = Select Timer0. We will be using this.

Bits 2, 1 and 0 define the pre-scaler value for the timer. As mentioned previously, the pre-scaler can be associated with Timer0 or with the Watchdog Timer (WDT) but not both. Note that the scaling for the WDT is half the value for Timer0 for the same three bits.

RUNNING SMALL MOTORS-0058

RUNNING SMALL MOTORS-0059

Caution There is a very specific sequence that must be followed (which does not apply here) when changing the pre-scaler assignment from Timer0 to the WDT (Watch Dog Timer) to make sure that an unintended reset does not take place. This is described in detail in The PICmicro Mid-Range MCU Family Reference Book (DS33023).

RUNNING SMALL MOTORS-0060

ote that Bit 2 is set clear when we start and will be set to 1 when the interrupt takes place. It has to be recleared within every interrupt service routine, usually at the end of the interrupt routine.

A Timer0 Clock

The following program (Program 6.3) written by microEngineering Labs and provided by them as a part of the information on their web site demonstrates the use of interrupts to create a reasonably accurate clock that uses the LCD display to show the time in hours, minutes, and seconds. (I did not modify this program in any way so it does not include the CLEAR or OSC statements and so on that we have been using in our programs.)

; LCD clock program using On Interrupt

; Uses TMR0 and pre-scaler. Watchdog Timer should be

; set to off at program time and Nap and Sleep should not be

; used.

; Buttons may be used to set hours and minutes.

RUNNING SMALL MOTORS-0061

RUNNING SMALL MOTORS-0062

RUNNING SMALL MOTORS-0063

In the clock implemented in Program 6.3, the keyboard buttons are used as follows:

N SW1 and SW5 increment the hours

N SW2 and SW6 decrement the hours

N SW3 and SW7 increment the minutes

N SW4 and SW8 decrement the minutes

The seconds cannot be affected other than with the reset switch.

TIMER1: THE SECOND TIMER

The second timer, Timer1, is the 16 bit-timer/counter. This is the most powerful timer in the MCU. As such it is the hardest of the three timers to understand and use, and it is also the most flexible. It consists of two 8-bit registers; each register can be read and be written to. The timer can be used either as a timer or as a counter depending on how the Timer1 Clock Select bit (TMR1CS) is set. This bit is Bit 1 in the Timer1 Control Register (T1CON).

In Timer1, we can set the value the timer starts its count with, and thus change the frequency of the interrupts. Here we are looking to see the effect of changing the value preloaded into Timer1 on the frequency of the interrupts as reflected in a very rudi- mentary pseudo stopwatch. The higher the value of the preload, the sooner the counter will get to $FFFF, and the faster the interrupts will come. We will display the value of the pre-scaler loaded into the timer on the LCD so that we can see the correlation between the values and the actual operation of the interrupts. As the interrupts get closer and closer together, the time left to do the main task gets shorter and shorter and you can see this on the speed at which the stopwatch runs.

In Program 6.4 the switches perform the following actions:

N SW1 turns the stopwatch on

N SW2 stops the stopwatch

N SW3 resets the stopwatch

POT1 is the first potentiometer. It is read and then written to TMR1H to change the interrupt rate. (We are ignoring the low byte because it does not affect the interrupt rate much in this experiment.)

The results of the experiment are displayed on the LCD display.

Let us creep up on the solution. We will develop the program segments and discuss them as we go along and then put the segments together for a program we can run.

RUNNING SMALL MOTORS-0064

RUNNING SMALL MOTORS-0065

RUNNING SMALL MOTORS-0066RUNNING SMALL MOTORS-0067RUNNING SMALL MOTORS-0068RUNNING SMALL MOTORS-0069

Run this program to see how the setting of the potentiometer affects the operation of the stopwatch. It becomes clear that choosing how the interrupt will serve our purposes is very important, and a bad choice can compromise the operation of the program.

We can read the timer and the interrupts at our discretion either before or after an interrupt has occurred, and the interrupt flag can be cleared whenever we want to, if it has been set. If it has not been set there is no need to clear it. A simplified flow diagram is provided in Figure 6.1 to help you to understand what is going on in an interrupt servicing routine.

Even the 16-bit Timer1 on the 16F877A cannot time a period of any length. Repeated intervals have to be put together to create long time periods. The longest possible time between interrupts for Timer1 (with a 4 MHz clock) is 0.524288 sec- onds. The maximum pre-scale value is 1:8. The post-scaler is only available on Timer2, which in any case is an 8-bit timer. This results in a maximum time that is determined by multiplying the instruction clock cycle (1 MS @ 4 MHz) by the pre- scale (8) by the number of counts from one overflow to the next (65536):

1 μS * 8 * 65536 = 0.524288 seconds

On a 20 MHz machine the time would be one-fifth of this.

RUNNING SMALL MOTORS-0070

` Timer1, the 16-bit timer/counter, uses two registers: TMR1H and TMR1L. The timer has the following general properties:

N It increments from $0000 to $FFFF in two registers.

N If the interrupt is enabled, an overflow will occur when the 2-byte counter over- flows from $FFFF to $0000.

N The device can be used as a timer.

N The device can be used as a counter.

N The timer registers can be read and written to.

N There is no post-scaler for this timer.

Simply stated again, this timer is used by setting its register to a selected value and using the interrupts this value creates for our purpose. A 16-bit timer will count up from where set to 65,535 and then flip to the selected value and start over again. An interrupt occurs and the interrupt flag is set every time the register overflows from 65,535 to 0. We do whatever needs to be done in response to the interrupt, resetting the interrupt flag and then going back to the main routine. On timers that permit the use of a pre-scaler and post-scaler, the pre-/post-scaler allows us to increase the time between interrupts by multiplying the time between interrupts with a definable value in a three to eight bit location. On writable timers we have the ability to start the tim- ers with values of our choice in the timer register(s). This gives us very usable but not absolute control over the interrupt intervals.

Consider the fact that a 0.01 second timer setting with a pre-scaler set to 16 would provide us with an interrupt every 0.16 seconds. We would have 0.16 seconds to do whatever we wanted to do between interrupts. There are limits to what can be put in the timer counter and what can be put in the pre-scaler, and the interrupt frequency is also affected by the accuracy of the processor clock oscillator.

The value of the scaling that will be applied to the timer is determined by the con- tents of two bits in the interrupt control register. These bits multiply the time between interrupts by powers of 2 as under:

RUNNING SMALL MOTORS-0071

Using Timer1 to Run a Critical Interrupt Driven Task While the Main Program Runs a Foreground Task

Let us use this timer in the same way we used Timer0 earlier and see what the differences between the two timers are. Since Timer1 is 16 bits wide, it can take much longer for it to set its interrupt flag. The interrupt flag was set approximately 61 times a second by Timer0. The Timer1 flag can take approximately 0.524 seconds, as calculated earlier. Let us write a short Timer1 program that is similar to the original Timer0 blinker program to see what the differences are.

Program 6.5 blinks the LEDs at D0 and D1 on and off alternately as the foreground part of the program. The interrupts generated by Timer1 are used to blink D3 on and off at half-second intervals. Since the control of D3 is driven by the interrupt, the tim- ing stays accurate. Any time used by the interrupt routine is lost by the foreground task and affects the overall frequency of D0/D1 blink rate.

RUNNING SMALL MOTORS-0072

RUNNING SMALL MOTORS-0073

Play with the value of the counter J to see how this affects the operation of the program. Study the differences between the two programs to set and clear the timer flags. Though Programs 6.4 and 6.5 do essentially the same thing, the setting of the potentiometer in the first program has to be modified to match the needs of the timer being used.

TIMER2: THE THIRD TIMER

Timer2 is an 8-bit timer only. It cannot be used as a counter. It has a pre-scaler and a post-scaler. The timer register for this counter is both writable and readable. If you can write to a counting register, you can set the value the count starts at and thus control the interval between interrupts (to some degree). That and the ability to set the pre- and post-scalers gives you the control you need for effective control of the interrupt interval, although you still cannot time all events exactly because of the coarseness of the settings available. Timer2 has a period register, PR2, which can be set by the user. The timer counts up from $00 to the value set in PR2, and when the two are the same it resets to $00. Small values in PR2 can be used to create very rapid interrupts—so much so that there may be no time to do anything else.

As always, the input clock for this timer is divided by 4 before it is fed to the timer. On a processor running at 4 MHz, the feed to the timer is at 1 MHz.

RUNNING SMALL MOTORS-0074

The timer is turned on by setting bit 2 in register T2CON (the Timer2 control register).

The interrupt for Timer2 is enabled by setting Bit 1 of PIE1, and the system lets the program know that an interrupt has occurred by setting Bit 1 in PIR1. (Bit 0 in both these registers is for Timer1.)

Bit 7 (the global interrupt enable bit) of INTCON (the interrupt control register) enables all interrupts, including those created by Timer2. Bit 6 of INTCON enables all unmasked peripheral interrupts and is one of the ways to awaken a sleeping MCU.

Timer2 can also control the operation of the two PWM signals that can be pro- grammed to appear on lines C1 and C2 with the HPWM command in PICBASIC PRO. Since one timer must control both lines, they both have to have the same PWM frequency. The relative width of the pulse within each of the PWM signals during each cycle does not have to be the same.

Timer2 is also used as a baud rate clock timer for communications. See Chapter 7 of the data sheet.

 

CONTROLLING THE OUTPUT AND READING THE INPUT:GENERATING OUTPUTS

GENERATING OUTPUTS

It will be easier if we learn to control the outputs first because we can do this from programs that we write without the need for any additional hardware or input signal. We will start with the simple control of LEDs and proceed to the control of the two- line LCD that is provided on the LAB-X1, and then move on to using the speaker and an R/C hobby servo.

Let us start with the standard turning an LED on and off program. We will use one of the LEDs in the ten-LED bar graph that is provided on the LAB-X1. On the LAB-X1 we have control of only the rightmost eight LEDs on the bar graph. The leftmost LED is the power-on indicator and the one next to it comes on if we were using a common cathode arrangement (as opposed to the common anode arrangement as it is currently configured).

The circuitry we are interested in is shown in Figure 5.1. All other circuitry of the LAB-X1 is still in place, but we have suppressed it, as shown in the figure, so we won’t be distracted by it and can concentrate on the one LED that is of interest, PORTD.0. (PORTD.0 refers to bit 0 of PORTD.)

This is how we turn something on with a microprocessor. We will use this technique whenever we need to turn something on in our experiments. If the signal needs to be

RUNNING SMALL MOTORS-0018

amplified to do useful work, we will do that. Transistors, conventional relays, and solid state relays can all be controlled by TTL level signals to give us the control voltages and amperages we need.

The following paragraphs and Program 5.1 guide through your first interaction with the microcontroller. We will take all the steps necessary to write an operational program and run it on the LAB-X1. Though this is a very simple program the steps taken here will be repeated for all the programs that we will ever write. It is important that you understand each and every step undertaken here before we proceed any further.

In this first experiment, we want to control the rightmost LED of the LED array. This is connected to bit 0 of PORTD in the circuitry shown in Figure 5.1. Our program needs to turn this LED on and off to demonstrate that we have control of these two functions.

In general, the ports on the microcontrollers (MCUs) are designed so that they can be used as inputs or outputs. In fact, the ports can be programmed so that certain pins on a port are inputs and others are outputs. All we have to do is tell the program what we want done and the compiler will handle the details. The compiler not only allows you to define how you will use the pins of each port, it can also set them up as inputs or as outputs automatically, depending on the instructions that we use in our programs. You have a choice of setting PORTD to an output port and then setting pin 1 on this port high, or you can simply tell the compiler to make pin 1 of PORTD high and it will take care of the details.

The ports can be treated just like any other memory location in the microcontroller. By name, you can read them, set them, and use them in calculations and manipulations just like you can with any other named or unnamed memory location. If things are connected to the ports and pins, the program will interact with and respond to what- ever is connected to them. (Any named port, register, or pin can be addressed directly by name for all purposes when using the PBP Compiler. They are called out as they are named in the data sheet.)

BLINK ONE LED

Type Program 5.1 as follows into your PC and save it. It does not need to be saved in the same directory as the PBP.exe program. To keep the conventions being used in the compiler manual, call this program myBLINKL so that it does not overwrite the BLINK.BAS program provided on the disk that came with the LAB-X1. Program 5.1 here demonstrates the on-off control pin 0 of PORT D.

RUNNING SMALL MOTORS-0019

The program demonstrates the most elementary control we have over an output. In this program we did not have to set the port directions (with the TRIS command) because the HIGH and LOW commands take care of that automatically. (If we used PORTD.0=1 instead of HIGH PORTD.0 we would have to set TRISD to %11111110 first to set all lines to inputs except D0, which is here shown set as an output.)

We will use binary notation (%11110000) for setting all ports and port directions throughout this book, though you can use hexadecimal ($F0) and decimal (DEC 240) notation interchangeably. Using binary notation lets you see what each pin is doing without having to make any mental conversions.

RUNNING SMALL MOTORS-0020

BLINK EIGHT LEDS IN SEQUENCE

In the next experiment (Program 5.2), the circuitry for which is shown in Figure 5.2, we will blink the eight rightmost LEDs on the bar graph one LED at a time. We do this by setting PORTD to 1 and then multiplying it by two eight times to move the lighted LED left in each iteration. Note that the last multiplication overflows the 8-bit counter and turns all the LEDs off.

RUNNING SMALL MOTORS-0021

RUNNING SMALL MOTORS-0022

With the preceding programs we learned that we can control the on-off state and the brightness on an LED. Controlling the brightness becomes relevant when we are con- trolling seven segment displays because the LEDs in them are turned on one at a time and the duty cycle has to be managed properly to get an acceptable display within an acceptable time frame.

 

CONTROLLING THE OUTPUT AND READING THE INPUT:GENERATING OUTPUTS

GENERATING OUTPUTS

It will be easier if we learn to control the outputs first because we can do this from programs that we write without the need for any additional hardware or input signal. We will start with the simple control of LEDs and proceed to the control of the two- line LCD that is provided on the LAB-X1, and then move on to using the speaker and an R/C hobby servo.

Let us start with the standard turning an LED on and off program. We will use one of the LEDs in the ten-LED bar graph that is provided on the LAB-X1. On the LAB-X1 we have control of only the rightmost eight LEDs on the bar graph. The leftmost LED is the power-on indicator and the one next to it comes on if we were using a common cathode arrangement (as opposed to the common anode arrangement as it is currently configured).

The circuitry we are interested in is shown in Figure 5.1. All other circuitry of the LAB-X1 is still in place, but we have suppressed it, as shown in the figure, so we won’t be distracted by it and can concentrate on the one LED that is of interest, PORTD.0. (PORTD.0 refers to bit 0 of PORTD.)

This is how we turn something on with a microprocessor. We will use this technique whenever we need to turn something on in our experiments. If the signal needs to be

RUNNING SMALL MOTORS-0018

amplified to do useful work, we will do that. Transistors, conventional relays, and solid state relays can all be controlled by TTL level signals to give us the control voltages and amperages we need.

The following paragraphs and Program 5.1 guide through your first interaction with the microcontroller. We will take all the steps necessary to write an operational program and run it on the LAB-X1. Though this is a very simple program the steps taken here will be repeated for all the programs that we will ever write. It is important that you understand each and every step undertaken here before we proceed any further.

In this first experiment, we want to control the rightmost LED of the LED array. This is connected to bit 0 of PORTD in the circuitry shown in Figure 5.1. Our program needs to turn this LED on and off to demonstrate that we have control of these two functions.

In general, the ports on the microcontrollers (MCUs) are designed so that they can be used as inputs or outputs. In fact, the ports can be programmed so that certain pins on a port are inputs and others are outputs. All we have to do is tell the program what we want done and the compiler will handle the details. The compiler not only allows you to define how you will use the pins of each port, it can also set them up as inputs or as outputs automatically, depending on the instructions that we use in our programs. You have a choice of setting PORTD to an output port and then setting pin 1 on this port high, or you can simply tell the compiler to make pin 1 of PORTD high and it will take care of the details.

The ports can be treated just like any other memory location in the microcontroller. By name, you can read them, set them, and use them in calculations and manipulations just like you can with any other named or unnamed memory location. If things are connected to the ports and pins, the program will interact with and respond to what- ever is connected to them. (Any named port, register, or pin can be addressed directly by name for all purposes when using the PBP Compiler. They are called out as they are named in the data sheet.)

BLINK ONE LED

Type Program 5.1 as follows into your PC and save it. It does not need to be saved in the same directory as the PBP.exe program. To keep the conventions being used in the compiler manual, call this program myBLINKL so that it does not overwrite the BLINK.BAS program provided on the disk that came with the LAB-X1. Program 5.1 here demonstrates the on-off control pin 0 of PORT D.

RUNNING SMALL MOTORS-0019

The program demonstrates the most elementary control we have over an output. In this program we did not have to set the port directions (with the TRIS command) because the HIGH and LOW commands take care of that automatically. (If we used PORTD.0=1 instead of HIGH PORTD.0 we would have to set TRISD to %11111110 first to set all lines to inputs except D0, which is here shown set as an output.)

We will use binary notation (%11110000) for setting all ports and port directions throughout this book, though you can use hexadecimal ($F0) and decimal (DEC 240) notation interchangeably. Using binary notation lets you see what each pin is doing without having to make any mental conversions.

RUNNING SMALL MOTORS-0020

BLINK EIGHT LEDS IN SEQUENCE

In the next experiment (Program 5.2), the circuitry for which is shown in Figure 5.2, we will blink the eight rightmost LEDs on the bar graph one LED at a time. We do this by setting PORTD to 1 and then multiplying it by two eight times to move the lighted LED left in each iteration. Note that the last multiplication overflows the 8-bit counter and turns all the LEDs off.

RUNNING SMALL MOTORS-0021

RUNNING SMALL MOTORS-0022

With the preceding programs we learned that we can control the on-off state and the brightness on an LED. Controlling the brightness becomes relevant when we are con- trolling seven segment displays because the LEDs in them are turned on one at a time and the duty cycle has to be managed properly to get an acceptable display within an acceptable time frame.