Microcontroller Code Example Explanation and Words of Wisdom For Senior Design For use with the following equipment: • PIC16F877 • QikStart Development Board • ICD2 Debugger • MPLAB Environment • exampleMain.c and exampleLCD.c Project Build Instructions: To get this example program working with MPLAB take the following steps: 1. Create a new folder in your Z: drive titled Example Code. 2. Copy the exampleMain.c and exampleLCD.c files into the folder. 3. Open MPLAB and select Project -> Project Wizard. 4. Follow the wizard selecting the PIC16F877. 5. Select the HI-TECH Universal ToolSuite and click NEXT. 6. Browse to select your Example Code folder and name your project. 7. Click NEXT and add the two .c files to the list. 8. Click the A next to each of the added files and make sure they change to a U. 9. Finish the wizard. 10. If nothing appears automatically select View-> Project and double-click the .c files in the window that appears. Project Run Instructions: 1. Make sure your board is powered and connected to the computer through the ICD2 debugger. 2. Select Debugger-> Select Tool-> MPLAB ICD 2. 3. Click the black Build icon on the toolbar to build the code. 4. Once the build is finished click the Program Target Device icon on the toolbar. 5. Wait for the device to be programmed (this takes some time) and then click the Run button on the toolbar. 6. The program should be running on the QikStart board now. Using the Program: This program does a number of things that can be seen and interacted with on the QikStart board. Upon running the program you should notice the array of LEDs on the right blinking on and off every 0.5 seconds. The LCD screen should also read “BLINK” on the first line and “PRESS ENTER” on the second line. Follow the directions on the LCD screen by pressing and holding the ENTER button on the board. Notice that the program does not change until you release the button. Once the button is release the lights will stop blinking and the LCD will display “A/D CONVERT” on the first line and “TURN RP1” on the second line. Again, follow the directions and turn the RP1 potentiometer back and forth. Notice that now, instead of blinking, the LEDs turn on or off in sequence with the turning of the potentiometer. Pressing the ENTER button again brings the program back to the original LCD message and the blinking LEDs. The program that runs the board this way is relatively simple, but demonstrates a number of useful embedded programming techniques and tools. Look at the code in the exampleMain.c file in MPLAB. You will notice that it is broken down into functions. Each function serves a specific purpose and fulfills a need of the overall program. The functions will all be broken down to their components by this paper, but it is important to note that understanding them will require considerable cross-reference to both the PIC16F877 datasheet and the QikStart board schematic. A serviceable amount of C programming language competency is required to follow what is going on and it is strongly recommended that you read up on C code if you are unfamiliar with the language. Top of the Code: Look at the exampleMain.c from the top. The first part is commented instructions and should be read, but have no effect on the program. Next comes the #include statements. These are standard and should be in every program you right for PICs. They specify the library of terms the microcontroller will recognize. The __CONFIG() function serves to setup some of the basic components of the PIC. The only one that might be changed by programs you write is the XT. This refers to the type of oscillator input and should be changed to RC if a 555 timer circuit is used instead of a crystal oscillator. The #define that comes next demonstrates how this functionality of the C language can be used to assign useful names to heavily used registers. This can make it easier to remember what your program is doing during debugging. The top of the code is rounded out by function and global variable declarations, which should be familiar to you. Initialization Code: Skip down to where the comments say Initial Subroutine. This is the initialization function. This is run once after the microcontroller is reset. The initialization routine defines starting parameters for the A/D converter, the input/output state of almost every pin on the PIC, the on-board timers, interrupts, and initial values of variables. The initialization routine is extremely important to the program. When writing code make sure all of your important registers are initialized correctly. Many problems can be solved by taking care that your registers are setup correctly! The following registers are very important to get right in the initialization: • • • • • ADCON1 – This register is responsible for setting up which pins can do A/D conversion. Use the information about this register in the datasheet to set the appropriate binary number for the number of analog signals. ADCS0 – This bit finishes the initialization of the oscillator for A/D conversion. TRISA-E – These registers define whether a pin is an input or an output. Use the pinout diagram in the datasheet to determine which pins need to be inputs/outputs. Set an 8 digit binary number for each of these, where the each bit of the number correspond to their respective pin in of the port. Set a 1 for an input and a 0 for an output. PR2/T2CON – This sets up TIMER2 and the TIMER2 interrupt, which is beyond the scope of these instructions (read the datasheet). INTCON – This sets up interrupts on the PIC. The default for this program is to have them enabled, but only timing interrupts are used. The Main Program Loop: Skip down to the bottom of the program and find the main function. This function is where everything starts and eventually returns to. It calls the Initial function the first time it runs, and then enters a continuous FOR loop. This FOR loop runs through its function calls until the PIC is reset. Using this technique the PIC is able to continuously monitor the various inputs and output of the peripheral functions and service events as they occur. The Button Push Function: This is the first function called in the FOR loop of the main function. It serves to monitor the state of the ENTER button. The first IF statement is satisfied when the button is pressed. ENTER_BUTTON becomes equal to 0 and the code sets the ChangState flag to remember the event. The function then returns to main. The function will continue to do this every time it is called, until the button is released. Once the button is released the first IF statement is no longer satisfied, so it moves onto the next one. This IF statement is satisfied when it sees that the ChangeState flag is set. The body of this IF statement resets the ChangeState flag and increments the mode counter. It also resets the mode counter if the final mode is active at the time. Try to figure out which parts of the IF statement are accomplishing this. The Blink Function: This is a simple function designed to turn the array of LEDs on/off on a specific time interval. When it is called it uses the bit toggle assignment operator (^=) to change all of the bits of PORTD to the opposite of whatever their current state is. The function then waits for 0.5 seconds by calling the 10 ms LoopTime routine 50 times. This makes the LEDs blink just about every 0.5 seconds. This is not exact, because the program actually runs through another cycle, but this takes very little time compared to the 0.5 second wait. The LCD Function: This function uses the DisplayC function from the exampleLCD.c file to write strings to the LCD screen. The first IF statement determines whether there needs to be a change in the LCD display, based on what the program wants displayed. If no change is needed the function returns to main to save time. If a change is needed it first clears the resetLCD flag that signals that need for change. It then calls the clear_display function from the exampleLCD.c file, which makes the LCD blank to avoid residual characters. The function then checks the DispMode variable to decide what to display. The DisplayC function is used to write to the LCD. It takes a position parameter and a string parameter. The position parameter to start writing at the top left is 0x80 and the bottom left is 0xC0. The ADConvert Function: This function takes an analog voltage level coming in from one of the pins and converts it to a digital level in A/D counts. This description assumes the reader has previous experience with A/D conversion and only explains the microcontroller implementation. The converter on the PIC16F877 is a 10-bit on board converter. More information is available in the datasheet. The assignments to CHS0-2 at the beginning of the function sets the analog input that will be converted. The ADON bit is part of the ADCON0 register and setting it to 1 turns the A/D converter on for conversion. The FOR loop is required to allow time for the converter to settle after being turned on. It takes roughly 30 us. Setting ADGO to 1 begins the A/D conversions and while(ADGO) waits until the conversion is finished before moving on. The assignment following takes the two A/D conversion results registers and combines them into one 10-bit value. Read the datasheet regarding how the results of the A/D converter are stored for more information. The final assignment of the ADON bit is to turn off the A/D converter, which saves power. The ShowAD Function: This function is intended to display the level of the analog signal acquired by the A/D converter. The structure of this function is a long IF statement with a number of possible cases. The statement runs through and checks whether the adValue is less than a particular threshold. If the adValue is below the threshold it sets the appropriate number of LEDs to on. If the adValue is above the threshold it moves on to check the next threshold. Wrap Up: This document describes the basic function of this relatively simple program. The techniques covered are important to know for programming microcontrollers. Now that you know basically what is going on take time to go through and thoroughly find the connections between what is happening in the code, and how it uses the circuit shown in the schematic. Use this code as a jumping off point for developing your own programs. Some of the routines can be cut and pasted and expanded into much more complex functions. This microcontroller can be programmed to do much more than has been shown and the datasheet has information for all of it. Combine knowledge of the circuit you are using with knowledge about how the microcontroller works and your programs will work. Use your imagination and do not feel constrained to using only what has been demonstrated. Note: This document did not cover specifics of the exampleLCD program, but you are definitely encouraged to take a look and try to figure out what is happening.